{
    "componentChunkName": "component---src-templates-post-page-js",
    "path": "/2018/cryptomate/exploring-patterns",
    "result": {"data":{"site":{"siteMetadata":{"title":"Solid Abstractions","siteUrl":"https://solidabstractions.com","twitterId":291334023,"author":{"fullName":"Julien Hartmann","profileHtml":"I am an open-source de­vel­op­er, for­mer IT con­sul­tant with a pas­sion for new tech­nol­o­gies. I be­lieve the role of an en­gi­neer is to em­pow­er peo­ple, by as­sem­bling sim­ple, re­fined de­signs.\n","links":[{"url":"https://github.com/spectras/","name":"github","title":"GitHub"},{"url":"https://stackoverflow.com/users/3212865/spectras","name":"stackoverflow","title":"StackOverflow"},{"url":"https://www.linkedin.com/in/julienhartmann/","name":"linkedin","title":"LinkedIn"}],"profilePicNode":{"original":{"src":"/static/profile-pic-301a9cbe7b572c3e7910c9717d2b3bcd.jpg"}},"url":"https://etherdream.org/about"}}},"markdownRemark":{"id":"06288b6b-d3cb-54b6-8cd1-7e1d9c48be0a","excerpt":"Event-driven, hexagonal, micro-services… we can quickly trim down the options to a few\ncandidates. We will then explore, evaluate and select one of them.","html":"<p>Event-driven, hexagonal, micro-services… we can quickly trim down the options to a few\ncandidates. We will then explore, evaluate and select one of them.</p>\n<p>--- excerpt ---</p>\n<p>This post is part of a 3-subseries in which we design the high-level architecture for Cryptomate.</p>\n<blockquote>\n<ol>\n<li><a href=\"modules\" class=\"internal\">Modules and components</a>.</li>\n<li>Exploring patterns <em>(this post)</em>.</li>\n<li><a href=\"critical-points\" class=\"internal\">Critical points</a>.</li>\n</ol>\n</blockquote>\n<h2 id=\"evaluating-architecture-patterns\">Evaluating architecture patterns</h2>\n<p>Given the task at hand, we can quickly trim down the options to a few candidates:</p>\n<ul>\n<li><strong>Event-driven</strong> architecture.</li>\n<li><strong>Hexagonal</strong> architecture.</li>\n<li><strong>Micro-services</strong> architecture.</li>\n<li><strong>Micro-kernel</strong> architecture.</li>\n</ul>\n<p>We will explore, evaluate and eventually select one of them.</p>\n<h3 id=\"event-driven-architecture\">Event-driven architecture</h3>\n<p>This architecture pattern revolves around reacting to events by orchestrating the workflow\nas a chain of events flowing through event processors, under possible supervision by a\nmediator.</p>\n<p>It enables asynchronous, distributed workflows, which could power Cryptomate:</p>\n<ul>\n<li>Initial events would come from market data providers.</li>\n<li>Components would forward messages using event channels as it goes through logic layers.</li>\n<li>Outgoing notifications and orders would be events down the line.</li>\n</ul>\n<div class=\"figure-wrapper\"><figure id=\"fig-1\"><img src=\"/files/eventdriven-6afb461fefb45c1cfd4b5b3a6878dfe6.png\" alt=\"Event-driven architecture diagram\" srcset=\"/files/eventdriven-1.5x-7721f7081152ef228802ba1f155e8d58.png 1.5x, /files/eventdriven-2x-0deb0b5b44a14316d72273b0a89d7e0d.png 2x\"><figcaption><div class=\"figcaption-wrapper\">Event-driven architecture example. This is a simple variant with no mediator. Each components listens for messages it knows how to process and publishes its result back. The event channel may be common or split into multiple local event channels. The audit component monitors the channels for relevant data.</div></figcaption></figure></div>\n<p>The main selling points of this architecture pattern are excellent agility and deployment,\nas event processors are standalone and self-contained, and good performance through scalability\nas processors can be instantiated several times over new resources to accommodate demand.</p>\n<p>This comes at the cost of difficult development and testing. Failures in event processors\nare tricky to diagnose and the fully asynchronous nature of the workflow is hard to reason\nabout. As for testing, testing single event processors is easy, but end to end testing is hard.</p>\n<h3 id=\"hexagonal-architecture\">Hexagonal architecture</h3>\n<p>This architecture pattern, also called the <em>ports &#x26; adapters</em> pattern, designs the system by\ndefining a bound between the inside and the outside of the application. Inside is the business\nlogic, working in an abstract environment. Every domain-level feature or functionality it\nrequires is defined by a <em>port</em>, that is, an abstract slot in the application.\nOn the outside, adapters support specific ports, allowing one to “plug” an external\nservice onto the port, providing the feature.</p>\n<div class=\"figure-wrapper\"><figure id=\"fig-2\"><img src=\"/files/hexagonal-34596ae6cc8251aa4357500a509f8195.png\" alt=\"Hexagonal architecture diagram\" srcset=\"/files/hexagonal-1.5x-a9c17235db4aae2f7ad673c5be50ba10.png 1.5x, /files/hexagonal-2x-eb50881fa11178eaa804fae8efc5c244.png 2x\"><figcaption><div class=\"figcaption-wrapper\">Hexagonal architecture example.</div></figcaption></figure></div>\n<p>By encapsulating all communications, this pattern facilitates interchangeability of both\ninput and output channels. This could power Cryptomate like this:</p>\n<ul>\n<li>Strategy engine would be business logic, sitting at the heart of the system.</li>\n<li>Interactions with data sources and event sinks could be modelized as ports and adapters.</li>\n<li>Interactions with trading platforms could be modelized as ports and adapters as well.</li>\n</ul>\n<p>The main selling points of this pattern are maintainability and testability. By enforcing\nthat all communications go through ports and adapters, this pattern makes it easy to adapt\nthe system to changing third parties. Say, supporting new brokers. This can be leveraged to\ntest components by providing them adapters that feed them test data and trace their reaction.</p>\n<h3 id=\"micro-services-architecture\">Micro-services architecture</h3>\n<p>This architecture pattern comes as a simplification of the famous Service-Oriented\nArchitecture or <a href=\"https://en.wikipedia.org/wiki/Service-oriented_architecture\" class=\"external\" rel=\"external noopener noreferrer\">SOA</a>,\ndropping orchestration and complex routing in favor of a lightweight message broker,\nor no broker at all.</p>\n<p>Micro-services revolve around organizing the application as a set of small, standalone,\nindependently-deployed service components. Each component performs a self-contained business\nfunction, which it exposes using a standard interface.</p>\n<div class=\"figure-wrapper\"><figure id=\"fig-3\"><img src=\"/files/microservices-0e67bd2c8ec432996b9d3ffc48b6766b.png\" alt=\"Micro-services architecture diagram\" srcset=\"/files/microservices-1.5x-6c00550c1385249e0ab8bd3a6c80f4cf.png 1.5x, /files/microservices-2x-0ec30b37b1fed3016197c7202f282aaa.png 2x\"><figcaption><div class=\"figcaption-wrapper\">Micro-services architecture example.</div></figcaption></figure></div>\n<p>Cryptomate could be designed as a set of micro-services like this:</p>\n<ul>\n<li>Market data collection would be a set of third-party-specific service components.</li>\n<li>Trading platform communications would be handled by a service component.</li>\n<li>Strategy engine would be a service component as well, and would benefit from the\narchitecture in that it would naturally scale, new strategy instances requiring no more than\nstarting additional engine instances.</li>\n</ul>\n<p>The main selling points of this pattern are scalability and continuous delivery, as\nservice components can be easily multiplied to handle increasing load, and their\nindependently-deployed, self-contained nature allows incremental deployment. Testability is\nexcellent too, as each service component can be tested in isolation.</p>\n<p>On the other hand, being a distributed architecture, it shares the caveats of complexity\nof event-driven architectures. Performance also tends to be poor, due to tasks requiring\na lot of communications to distributed nodes. This <em>can</em> be counter-balanced by careful\nimplementation, but does not come naturally with the pattern.</p>\n<h3 id=\"micro-kernel-architecture\">Micro-kernel architecture</h3>\n<p>This architecture pattern revolves around creating a basic core system, which is then\naugmented with plugin modules to create a fully functional system. The core system acts\nas a simple framework, capable of locating plugins and managing them. It typically has but\na very simple knowledge of business logic, delegating all details to the plugins.</p>\n<div class=\"figure-wrapper\"><figure id=\"fig-4\"><img src=\"/files/microkernel-6370062dbf51f6bc5936e2b78bdf4fd5.png\" alt=\"Micro-kernel architecture diagram\" srcset=\"/files/microkernel-1.5x-ff6dae289e962cebbbe457f4204bd2f0.png 1.5x, /files/microkernel-2x-24d7ef11a6ab161f627aeff11a943b0f.png 2x\"><figcaption><div class=\"figcaption-wrapper\">Micro-kernel architecture example.</div></figcaption></figure></div>\n<p>Cryptomate could be designed as a micro-kernel like this:</p>\n<ul>\n<li>The core would only know about finding market plugins, strategy plugins, notification\nplugins and trading plugins, and the basic outline of the workflow: markets produce events\nthat go to strategies, which may take actions.</li>\n<li>Market plugins know how to receive data events.</li>\n<li>Strategy plugins fill in the actual trading logic.</li>\n<li>Action plugins include both trading orders and notifications.</li>\n</ul>\n<p>The main selling points of this pattern are excellent agility and testability. By adding\nand removing plugins, the system can easily adapt, and plugins can be tested in isolation.</p>\n<p>On the other hand, this pattern does not address scalability at all, as the run-time is\nmonolithic even though its design is not. Also, designing a solid plugin system, capable\nof handling the diverse contracts that may apply to all the facets of the business logic,\nis difficult.</p>\n<h2 id=\"picking-and-compositing\">Picking and compositing</h2>\n<h3 id=\"summary\">Summary</h3>\n<p>Here is what we have so far:</p>\n<div class=\"figure-wrapper\"><figure id=\"fig-5\"><table>\n<thead>\n<tr>\n<th>Attribute</th>\n<th align=\"center\">Event-driven</th>\n<th align=\"center\">Hexagonal</th>\n<th align=\"center\">Micro-services</th>\n<th align=\"center\">Micro-kernel</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Testability</td>\n<td align=\"center\"><svg viewBox=\"0 0 1000 1000\" class=\"symbol\"><path d=\"M500,990L71.2,561.3H255V10h490v551.3h183.8L500,990z\" fill=\"url(#down-symbol-gradient)\"/></svg></td>\n<td align=\"center\"><svg viewBox=\"0 0 1000 1000\" class=\"symbol\"><path d=\"M500,10L71.2,438.7H255V990H745V438.7h183.8z\" fill=\"url(#up-symbol-gradient)\"/></svg><svg viewBox=\"0 0 1000 1000\" class=\"symbol\"><path d=\"M500,10L71.2,438.7H255V990H745V438.7h183.8z\" fill=\"url(#up-symbol-gradient)\"/></svg></td>\n<td align=\"center\"><svg viewBox=\"0 0 1000 1000\" class=\"symbol\"><path d=\"M500,10L71.2,438.7H255V990H745V438.7h183.8z\" fill=\"url(#up-symbol-gradient)\"/></svg></td>\n<td align=\"center\"><svg viewBox=\"0 0 1000 1000\" class=\"symbol\"><path d=\"M500,10L71.2,438.7H255V990H745V438.7h183.8z\" fill=\"url(#up-symbol-gradient)\"/></svg></td>\n</tr>\n<tr>\n<td>Maintainability</td>\n<td align=\"center\"><svg viewBox=\"0 0 1000 1000\" class=\"symbol\"><path d=\"M500,10L71.2,438.7H255V990H745V438.7h183.8z\" fill=\"url(#up-symbol-gradient)\"/></svg></td>\n<td align=\"center\"><svg viewBox=\"0 0 1000 1000\" class=\"symbol\"><path d=\"M500,10L71.2,438.7H255V990H745V438.7h183.8z\" fill=\"url(#up-symbol-gradient)\"/></svg><svg viewBox=\"0 0 1000 1000\" class=\"symbol\"><path d=\"M500,10L71.2,438.7H255V990H745V438.7h183.8z\" fill=\"url(#up-symbol-gradient)\"/></svg></td>\n<td align=\"center\"><svg viewBox=\"0 0 1000 1000\" class=\"symbol\"><path d=\"M500,10L71.2,438.7H255V990H745V438.7h183.8z\" fill=\"url(#up-symbol-gradient)\"/></svg><svg viewBox=\"0 0 1000 1000\" class=\"symbol\"><path d=\"M500,10L71.2,438.7H255V990H745V438.7h183.8z\" fill=\"url(#up-symbol-gradient)\"/></svg></td>\n<td align=\"center\"><svg viewBox=\"0 0 1000 1000\" class=\"symbol\"><path d=\"M500,10L71.2,438.7H255V990H745V438.7h183.8z\" fill=\"url(#up-symbol-gradient)\"/></svg></td>\n</tr>\n<tr>\n<td>Ease of development</td>\n<td align=\"center\"><svg viewBox=\"0 0 1000 1000\" class=\"symbol\"><path d=\"M500,990L71.2,561.3H255V10h490v551.3h183.8L500,990z\" fill=\"url(#down-symbol-gradient)\"/></svg></td>\n<td align=\"center\"><svg viewBox=\"0 0 1000 1000\" class=\"symbol\"><path d=\"M500,10L71.2,438.7H255V990H745V438.7h183.8z\" fill=\"url(#up-symbol-gradient)\"/></svg></td>\n<td align=\"center\"><svg viewBox=\"0 0 1000 1000\" class=\"symbol\"><path d=\"M500,10L71.2,438.7H255V990H745V438.7h183.8z\" fill=\"url(#up-symbol-gradient)\"/></svg></td>\n<td align=\"center\"><svg viewBox=\"0 0 1000 1000\" class=\"symbol\"><path d=\"M500,990L71.2,561.3H255V10h490v551.3h183.8L500,990z\" fill=\"url(#down-symbol-gradient)\"/></svg></td>\n</tr>\n<tr>\n<td>Performance</td>\n<td align=\"center\"><svg viewBox=\"0 0 1000 1000\" class=\"symbol\"><path d=\"M500,10L71.2,438.7H255V990H745V438.7h183.8z\" fill=\"url(#up-symbol-gradient)\"/></svg><svg viewBox=\"0 0 1000 1000\" class=\"symbol\"><path d=\"M500,10L71.2,438.7H255V990H745V438.7h183.8z\" fill=\"url(#up-symbol-gradient)\"/></svg></td>\n<td align=\"center\"><svg viewBox=\"0 0 1000 1000\" class=\"symbol\"><path d=\"M500,10L71.2,438.7H255V990H745V438.7h183.8z\" fill=\"url(#up-symbol-gradient)\"/></svg></td>\n<td align=\"center\"><svg viewBox=\"0 0 1000 1000\" class=\"symbol\"><path d=\"M500,990L71.2,561.3H255V10h490v551.3h183.8L500,990z\" fill=\"url(#down-symbol-gradient)\"/></svg></td>\n<td align=\"center\"><svg viewBox=\"0 0 1000 1000\" class=\"symbol\"><path d=\"M500,10L71.2,438.7H255V990H745V438.7h183.8z\" fill=\"url(#up-symbol-gradient)\"/></svg></td>\n</tr>\n<tr>\n<td>Availability</td>\n<td align=\"center\"><svg viewBox=\"0 0 1000 1000\" class=\"symbol\"><path d=\"M500,10L71.2,438.7H255V990H745V438.7h183.8z\" fill=\"url(#up-symbol-gradient)\"/></svg></td>\n<td align=\"center\"><svg viewBox=\"0 0 1000 1000\" class=\"symbol\"><path d=\"M500,990L71.2,561.3H255V10h490v551.3h183.8L500,990z\" fill=\"url(#down-symbol-gradient)\"/></svg></td>\n<td align=\"center\"><svg viewBox=\"0 0 1000 1000\" class=\"symbol\"><path d=\"M500,10L71.2,438.7H255V990H745V438.7h183.8z\" fill=\"url(#up-symbol-gradient)\"/></svg></td>\n<td align=\"center\"><svg viewBox=\"0 0 1000 1000\" class=\"symbol\"><path d=\"M500,990L71.2,561.3H255V10h490v551.3h183.8L500,990z\" fill=\"url(#down-symbol-gradient)\"/></svg></td>\n</tr>\n<tr>\n<td>Scalability</td>\n<td align=\"center\"><svg viewBox=\"0 0 1000 1000\" class=\"symbol\"><path d=\"M500,10L71.2,438.7H255V990H745V438.7h183.8z\" fill=\"url(#up-symbol-gradient)\"/></svg></td>\n<td align=\"center\"><svg viewBox=\"0 0 1000 1000\" class=\"symbol\"><path d=\"M500,990L71.2,561.3H255V10h490v551.3h183.8L500,990z\" fill=\"url(#down-symbol-gradient)\"/></svg></td>\n<td align=\"center\"><svg viewBox=\"0 0 1000 1000\" class=\"symbol\"><path d=\"M500,10L71.2,438.7H255V990H745V438.7h183.8z\" fill=\"url(#up-symbol-gradient)\"/></svg></td>\n<td align=\"center\"><svg viewBox=\"0 0 1000 1000\" class=\"symbol\"><path d=\"M500,990L71.2,561.3H255V10h490v551.3h183.8L500,990z\" fill=\"url(#down-symbol-gradient)\"/></svg></td>\n</tr>\n</tbody>\n</table><figcaption><div class=\"figcaption-wrapper\">Pattern quality attributes evaluation</div></figcaption></figure></div>\n<p>Quality Attributes are ordered from the most valued by our requirements to the least valued.\nI intentionally left out quality attributes that are mostly unaffected by this choice.</p>\n<p>We can clearly eliminate the event-driven architecture immediately.<sup id=\"fnref-1\"><a href=\"#fn-1\" class=\"footnote-ref\">1</a></sup>\nNow, the hexagonal model seems like a good fit, but is lacking on the availability and\nscalability side. Also, it does not provide a model for abstracting out business logic,\nwhich we need to build a versatile strategy engine.</p>\n<h3 id=\"compositing\">Compositing</h3>\n<p>We could alleviate those weaknesses though, by:</p>\n<ol>\n<li>Applying some micro-service concepts to specific areas. In fact the very nature of the\nhexagonal pattern makes it easy to detach a single module as a micro-service, without\ntouching anything but the matching port and adapter parts.<br>\nThis will allow us to increase scalability and availability of specific modules, with\ncontrolled performance impacts (we know the impact is limited to flows going through\nthis specific adapter).</li>\n<li>Using micro-kernel principles on the strategy evaluator module, turning it into an empty\nworkflow that delegates to strategy plugins.</li>\n</ol>\n<p>Here is a tentative high-level design leveraging this combination:</p>\n<div class=\"figure-wrapper\"><figure id=\"fig-6\"><img src=\"/files/composed-4f1a85618d2bd380a1427d99cf4bf0aa.png\" alt=\"Cryptomate architecture diagram\" srcset=\"/files/composed-1.5x-7e08595e66a8c42cf8d10c162283adc6.png 1.5x, /files/composed-2x-0f45fae9e0959dbdd22db13a96976b3a.png 2x\"><figcaption><div class=\"figcaption-wrapper\">Cryptomate architecture diagram. Unlabelled arrows are “sends to” relationships.</div></figcaption></figure></div>\n<p>This gives us a hybrid architecture: an hexagonal architecture where some adapters use\nmicro-services. Thus, the performance/scalability trade-off can be postponed\nto integration-time, making our system equally potent at servicing large-scale farm of\nstrategies and performance-critical, tailored, single-user setups.</p>\n<h2 id=\"conclusion\">Conclusion</h2>\n<p>As a last step, we should double-check with our <a href=\"requirements\" class=\"internal\">requirements</a> that this\ntentative architecture has a straightforward path for all of them. For instance, adding\nsupport for a new market data provider can be done by creating a new adapter, which, in a\nproperly structured hexagonal pattern, will not change existing code.</p>\n<div class=\"note\"><p>I did check all of them, feel free to do it on your side as an exercise, and send me\n<a href=\"/about\" class=\"internal\">feedback</a> if you find I missed something.</p></div>\n<p>We created our initial idea of the system's architecture. We validated all known scenarios\nfit into our idea. There are still a few <a href=\"critical-points\" class=\"internal\">critical areas</a> that need to\nbe refined.</p>\n<svg style=\"width: 0; height: 0; visibility: hidden;\"><defs><linearGradient id=\"down-symbol-gradient\" x1=\"0\" x2=\"0\" y1=\"0\" y2=\"1\"><stop offset=\"0%\" stop-opacity=\".5\" stop-color=\"red\"/><stop offset=\"100%\" stop-opacity=\"1\" stop-color=\"red\"/></linearGradient></defs><defs><linearGradient id=\"up-symbol-gradient\" x1=\"0\" x2=\"0\" y1=\"1\" y2=\"0\"><stop offset=\"0%\" stop-opacity=\".5\" stop-color=\"green\"/><stop offset=\"100%\" stop-opacity=\"1\" stop-color=\"green\"/></linearGradient></defs></svg>\n<div class=\"footnotes\">\n<hr>\n<ol>\n<li id=\"fn-1\">\n<p>Note the event-driven model is a bad fit mostly because I am doing this project alone, which pushes ease of development and testability high up the list; a larger team would probably overcome those difficulties and pick an event-driven model for its performance.</p>\n<a href=\"#fnref-1\" class=\"footnote-backref\">↩</a>\n</li>\n</ol>\n</div>","fields":{"isPage":false,"slug":"/2018/cryptomate/exploring-patterns"},"frontmatter":{"title":"Exploring Patterns","classname":null,"date":"2018-08-20T00:00:00.000Z","formattedDate":"August 20, 2018","isoDate":"2018-08-20T00:00:00+00:00"},"headings":[{"value":"Evaluating architecture patterns","depth":1},{"value":"Event-driven architecture","depth":2},{"value":"Hexagonal architecture","depth":2},{"value":"Micro-services architecture","depth":2},{"value":"Micro-kernel architecture","depth":2},{"value":"Picking and compositing","depth":1},{"value":"Summary","depth":2},{"value":"Compositing","depth":2},{"value":"Conclusion","depth":1}],"image":null,"series":{"name":"cryptomate","fullName":null,"fields":{"slug":"/cryptomate"}},"tags":[{"name":"architecture","slug":"/tag/architecture"},{"name":"pattern","slug":"/tag/pattern"}]}},"pageContext":{"series":"cryptomate","slug":"/2018/cryptomate/exploring-patterns","previous":{"fields":{"slug":"/2018/cryptomate/modules"},"frontmatter":{"title":"Modules and Components","series":"cryptomate"},"tags":[{"name":"architecture","slug":"/tag/architecture"}]},"next":{"fields":{"slug":"/2018/cryptomate/critical-points"},"frontmatter":{"title":"Critical Points","series":"cryptomate"},"tags":[{"name":"architecture","slug":"/tag/architecture"}]},"seriesPrevious":{"fields":{"slug":"/2018/cryptomate/modules"},"frontmatter":{"title":"Modules and Components","series":"cryptomate"},"tags":[{"name":"architecture","slug":"/tag/architecture"}]},"seriesNext":{"fields":{"slug":"/2018/cryptomate/critical-points"},"frontmatter":{"title":"Critical Points","series":"cryptomate"},"tags":[{"name":"architecture","slug":"/tag/architecture"}]}}},
    "staticQueryHashes": ["1733002695","4006707078"]}