Modules and Components
Our architecturally significant requirements workbook in hand, we are confident we have clear enough understanding of the problem to start building our high-level architecture.
Our goal now will be to map requirements to modules and components, explore possible architecture patterns and descend into details on critical points.
This is a long step, as we will build the bulk of the design, so I decided to split this step into multiple posts:
Modularizing the requirements
We will start with arranging our requirements as a set of modules. Each modules shall be responsible for one requirement, or one group of requirements. For instance, Cryptomate shall be able to open, cancel and monitor orders on trading platforms: a trading element would be in order.
Here are the modules I have identified:
|Auditing||Writes down auditing trails.|
|Control endpoint||Authenticates and authorizes user requests. Manages strategies according to user directives.|
|Market history||Provides random-access to past market events.|
|Notification||Sends notifications based on user-defined rules.|
|Real-time market||Provides access to real-time market events.|
|Strategy evaluator||Runs user-defined business logic.|
|Strategy persistence||Persists strategy state so it can be recovered.|
|Trading||Controls orders placed by the system. Provides events related to orders.|
As usual, if you found I missed one, please tell me.
The way these modules get instantiated at run-time is interesting, to better understand the allocation mechanisms that will be needed:
|Control endpoint||static, single||configuration|
|Market history||static, single||configuration|
|Real-time market||dynamic, multiple||strategy|
|Strategy evaluator||dynamic, multiple||strategy|
|Strategy persistence||static, single||configuration|
Where static means the component is allocated on startup and destroyed at shutdown, while dynamic means allocations and de-allocations can happen during normal life of the system. Multiple allocations are the components that will have several instances coexisting during the life of the system. For instance, the system might connect to several markets at once.
Lastly, the third column details where the knowledge of what and how to instantiate components lives. In Cryptomate, it may either be statically configured within the configuration file, or dynamically decided by currently running strategies. This means both process will probably be complex enough to mandate a specific builder module.
We will therefore add the following modules to the list:
|Configuration builder||Instantiates and initializes statically-allocated components from a configuration description (either a file or a data-structure).|
|Strategy builder||Instantiates or trigger the instantiation of components required to start a strategy. This includes the required bookkeeping to shut them down upon stopping the strategy.|
Event flow overview
Since market events will drive most of our logic, and trading is inherently very time-sensitive, now is a good time to picture how incoming market events will flow through our system, from market data providers all the way to outgoing trading orders:
We will be mindful of both ensuring the critical path has reasonable latency, and side processing do not introduce spurious delays.
This concludes our initial pass of identifying key Cryptomate modules. This is not set in stone yet, but this should be enough for us to design our high-level architecture.
So let's now explore architecture patterns we could use to structure those modules into an actual design.