If you’ve read other Wealthfront engineering blog posts (Continuous Deployment: API Compatibility Verification, Move cash faster, Pushing a Feature On My First Day), you’re aware that continous integration and deployment forms the core of our development process. Many consequences of a continuous integration and deployment process such as ours are obvious – high confidence test suites, robust build/test/deploy automation, etc. A less obvious consequence is that the streamlined development process impacts how we code. Consider software configuration.
- Environment Config – configuration that enables software to run properly within a specific environment. Examples include host configuration, database connection information, and external service endpoints information. Various tools exist to help manage environment configuration. Chef and ZooKeeper are a couple that we use at Wealthfront.
- Behavior Config – configuration that defines how software functions, and in some cases what data elements are available to the system. Examples include formula constants, logic thresholds, and the definition of constant data such as Wealthfront investment options.
etf_models table, and represented in code by the corresponding
EtfModel entity class.
etf_models table. However, investment configuration was not fully represented within the database, so code changes were still required for the system to utilize new investment options. In this case, the in-database / in-code configuration hybrid made it really easy to consider moving all of the investment configuration into code. I did, and realized that the resulting code was far simpler. In the end, I removed multiple files related to database persistence, and simplified the code which configures which
EtfModel’s to invest in, in what ratios, and under which scenarios.
Most important in this case, in code without concern for external persistence, it became easy to evolve
EtfModel into a more flexible data model representation which lays the groundwork for some exciting investment features coming in the future.
EtfVehicle, an enum-like class within a small class hierarchy which makes way for new types of investment vehicles. A representation as rich and flexible as this would be complicated if expressed within database tables or config files. However, in code it is easy to implement and easy to test. And, with continuous integration and deployment, the data it configures is trivial to maintain.
AllocatedAssetType base class provides an abstraction for all types of assets, including cash, across which funds are allocated.
InvestmentVehicle base class extends
AllocatedAssetType and provides a unified representation for all future types of investments.
InvestmentVehicle and contains the data previously configured within the
etf_models table, using the type-safe enumeration pattern prevalent in java before java 5.0.
etf_models table was dropped from the database, and even though
EtfModel.id numeric values were retained (within
InvestmentVehicle) for backward compatibility, table columns referencing
etf_models.id now instead reference
EtfVehicle by name as you might do when persisting an enum value. This makes database data easier to inspect, now that there is no
etf_models table to join with.
EtfModel refactor worked out so nicely that it got me thinking about how much simpler an implementation is when constant data is defined in code vs. in config files and/or database tables. I am now on the lookout for other constant data currently stored in the database or config files, and my habit of blindly keeping behavior config out of code has been broken!