I recently pulled out an old coding project I had started almost 10 years ago involving OFX files. OFX files are used by Money and Quicken to import transactions from banking and investment websites. The plan now is as it was then, to create a utility to convert CSV files to OFX files for websites that have given up on OFX support.
Back then, I was at a serious disadvantage because I was reverse-engineering the files. Despite the name, the Open Finance eXchange organization was not very open about sharing the specifications for the OFX file format. This time around, I was able to find and download the specification files and have been building my object model in accordance with them.
It’s not an easy spec to digest, for sure. But, it’s more than what I had and I’m able to make some significant progress. After a few focused days of coding, I am able to create OFX files for Banking and Credit Card transaction downloads. Currently, I am building out the Investment download, which is as big as everything I’ve done so far.
So, I wanted to pause for a moment and write out what I want to accomplish in the near and distant future. Here’s a short list of goals:
- Create banking transaction download (X)
- Create credit card transaction download (X)
- Create investment transaction download
- Create validation functions
- Create import functions
- Support v2.0+ format
- Support direct serialization/deserialization
So as you see, it’s not a short path and there’s still plenty to do. So, with that, back to coding.
Results from Phase 1
After completing the goals of downloading the three major transaction lists, I grabbed the broom and cleaned up the mess I had made. A clean shop will make going forward easier. So, upon reflection, what’s good and bad?
I started the code with little to no understanding of the model I was coding. Because of that, I was not able to preemptively design namespaces and so my class names were long and redundant, like InvestmentPositionBuyMutualFund. This specific case was refactored to OFX.Investment.Position.BuyMutualFund. Creating namespaces simplified my naming structure greatly. I was not able to really think big-picture until I had all the classes coded. Even before creating the namespaces, I had to physically organize the classes into folders.
I started out aggressively trying to reuse classes as much as possible, which led to some class hierarchies that led to poor developer experience. The biggest example was when I had a property of a base class type. Yeah, it was sort of good that it was limited to only the classes that inherited from it, so it was sort of discoverable, but it meant casting it to the specific type every time you wanted to work with it, which really sucked. I was trying to be clever with automatic instantiation with a factory, but in the end, it was better to drop that property from the base class and move an instance of it to each specific class.
As I refined the code I was pleased that I took the time to automatically instantiate any objects that were needed through properties. It’s one less thing you have to worry about is setting an instance to a property. And as I write more detailed unit tests, I should be able to find any cases where I forgot to do this.
The unit tests have been very helpful for me to test out my changes and my refactorings as I go. In actuality, the unit test code is pretty much what a developer is going to be doing with the library anyway, so it’s also documentation.
So what’s bad? The OFX schema is pretty ridiculous. Even in my unit test coding, I was using an existing OFX file to determine what properties I need to set. There’s going to need to be a lot of documentation. I think I can assist by making constructors from classes that include all the required fields for the node. I know the validate methods will help when I get to them. So that’s the big bad, is that there’s no real way to simplify this library.
The only other thing I’m not happy about is how much more there is to do. I have a lot more classes to write and I have a lot of classes written that aren’t being used (yet). I don’t have any practical way of testing these. Well, I do, but it’s not practical. The way I have to test them is to create new file in Money, and create OFX files that simulate transactions that I can verify got imported correctly. Unit tests, you are going to get a WORKOUT.