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. EtfModel
became 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.
The AllocatedAssetType
base class provides an abstraction for all types of assets, including cash, across which funds are allocated.
The InvestmentVehicle
base class extends AllocatedAssetType
and provides a unified representation for all future types of investments.
EtfVehicle
extends 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!