<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Denys Poltorak on Medium]]></title>
        <description><![CDATA[Stories by Denys Poltorak on Medium]]></description>
        <link>https://medium.com/@denyspoltorak?source=rss-7d4e79c3c009------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*h7aQtRSEV2EBK5hMwsvVXA.png</url>
            <title>Stories by Denys Poltorak on Medium</title>
            <link>https://medium.com/@denyspoltorak?source=rss-7d4e79c3c009------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 17 May 2026 10:12:38 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@denyspoltorak/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[The Map of System Topologies]]></title>
            <link>https://itnext.io/the-map-of-system-topologies-e2d3d0b89618?source=rss-7d4e79c3c009------2</link>
            <guid isPermaLink="false">https://medium.com/p/e2d3d0b89618</guid>
            <category><![CDATA[software-design]]></category>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[design-patterns]]></category>
            <category><![CDATA[system-architecture]]></category>
            <category><![CDATA[metapatterns]]></category>
            <dc:creator><![CDATA[Denys Poltorak]]></dc:creator>
            <pubDate>Tue, 05 May 2026 07:30:58 GMT</pubDate>
            <atom:updated>2026-05-05T07:30:58.381Z</atom:updated>
            <cc:license>http://creativecommons.org/licenses/by/4.0/</cc:license>
            <content:encoded><![CDATA[<blockquote>This is a new chapter for my book <a href="https://leanpub.com/metapatterns">Architectural Metapatterns: the Pattern Language of Software Architecture</a>. It should appear in release 1.2 scheduled in a couple of weeks.</blockquote><p>In the <a href="https://metapatterns.io/introduction/metapatterns/">previous chapter</a> we started with architectural patterns and grouped them in accordance with their structure and function into <a href="https://metapatterns.io/introduction/metapatterns/#structure-determines-architecture"><em>metapatterns</em></a>. Now let’s traverse in the opposite direction: from <em>topology</em> (the structure of a system) to the patterns which describe it. We will draw and analyze a map of common system topologies and along the way outline the scope of <a href="https://leanpub.com/metapatterns">this book</a>.</p><h3>Methodology</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*X0cT4hrIGo7pdk6HwNGnXg.png" /></figure><p>We will rely on our finding that any system has a characteristic representation in the <a href="https://metapatterns.io/introduction/metapatterns/#the-system-of-coordinates">abstractness-subdomain-sharding space</a>. The amounts of a system’s partitioning along each of the three dimensions can be used as its coordinates on a map of system topologies:</p><p><em>Abstractness</em> corresponds to the <em>technical partitioning</em> [<a href="https://metapatterns.io/appendices/books-referenced/#fsa">FSA</a>] — subdivision of a system into <a href="https://metapatterns.io/basic-metapatterns/layers/"><em>layers</em></a> with different roles and technologies. Any use case will likely involve all the layers.</p><p><em>Subdomain</em> represents the <em>domain partitioning</em> [<a href="https://metapatterns.io/appendices/books-referenced/#fsa">FSA</a>] — segregation of a system into <a href="https://metapatterns.io/basic-metapatterns/services/"><em>modules</em> or <em>services</em></a> that encapsulate distinct parts of the business knowledge. A use case is often localized in one or two subdomains.</p><p><em>Sharding</em> is about running <a href="https://metapatterns.io/basic-metapatterns/shards/">multiple instances</a> (<a href="https://metapatterns.io/basic-metapatterns/shards/#persistent-slice-sharding-shards-partitions-multitenancy-cells-amazon-definition"><em>shards</em></a> or <a href="https://metapatterns.io/basic-metapatterns/shards/#persistent-copy-replica"><em>replicas</em></a>) of a component.</p><h4>From theory to practice</h4><p>Having a distribution of architectures in a 3D space sounds great, but how do we represent it as human-readable media?</p><p>There are at least the following issues:</p><ul><li>Many system topologies feature similar levels of segregation into layers and services, meaning that they belong to the same neighborhood on the map.</li><li>It makes a difference if a system’s business logic or its infrastructure is subdivided because business logic comprises the bulk of the code. Therefore we cannot estimate a system’s coordinates only from the number of layers or services it contains, which means that we are limited to something like “major layering” and “minor layering” instead of numeric values.</li><li>Sharding of many architectures varies widely and is hard to represent on a flat drawing.</li></ul><p>As a result, the following adjustments were necessary to make the map of system topologies comprehendable:</p><ul><li>Sharding is omitted, transforming 3D coordinates into a flat map. Yes, much information is lost, but <em>too much information is no information</em>. Now the map is easier to read.</li><li>I took the liberty of shifting topologies from their real positions to resolve overlaps.</li><li>Even worse, I moved some of the topologies around to group similar architectures.</li><li>Exotic (e.g. <a href="https://metapatterns.io/implementation-metapatterns/mesh/#leaf-spine-architecture-spine-leaf-architecture"><em>Leaf-Spine Architecture</em></a>) and duplicate (e.g. <a href="https://metapatterns.io/basic-metapatterns/services/#microservices"><em>Microservices</em></a>) topologies are omitted.</li></ul><h3>The map of system topologies</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mA1O8yAXt4pBuapfWWRLZQ.png" /></figure><p>The map contains only basic architectures which are easy to apprehend and name. Any complex system is very likely to be a combination of these simple topologies.</p><p>I somewhat arbitrarily divided the map of system topologies into five partially overlapping regions:</p><ul><li><em>Monolithic</em>, where the bulk of the system is kept in a single component.</li><li><em>Layered</em>, with mostly technical partitioning, where architectural components are specialized (drawn in few colors which correspond to different kinds of code).</li><li><em>Services</em> with domain partitioning, meaning that each of the main components includes several kinds of code.</li><li><em>Fragmented systems</em> built of many smaller parts.</li><li><em>Plugins</em> that usually have a cohesive core and external modular layers.</li></ul><p>This grouping allows us to study the topologies piecemeal without getting lost in their numbers and features.</p><h3>Monolithic systems</h3><p>In the simplest cases a project is too small for any internal structure to be justified — you can code it in a couple of hours without any preliminary design. In other cases the domain is known to be so cohesive that you cannot find good module boundaries — any internal interfaces result in much boilerplate code or degrade performance. Or there is no time left for a thoughtful design!</p><h4>True Monoliths</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hoLV9AAExTHMJj62G6B6dg.png" /></figure><p>Few system topologies are truly monolithic with one kind of system components:</p><ul><li><a href="https://metapatterns.io/basic-metapatterns/monolith/"><em>Monolith</em></a> keeps everything together in a single cohesive application which makes sense for small, one-off projects. A long-running <em>Monolith</em> may need to handle inputs and events, for which there are several options:<br>- <a href="https://metapatterns.io/basic-metapatterns/monolith/#single-threaded-reactor-one-thread-one-task"><em>Reactor</em></a> uses a thread for each request and blocks on calls to the OS or other components. This is the <a href="https://metapatterns.io/basic-metapatterns/monolith/#multi-threaded-reactor-a-thread-per-task">simplest server-side implementation</a>.<br>- <a href="https://metapatterns.io/basic-metapatterns/monolith/#proactor-one-thread-many-tasks"><em>Proactor</em></a> relies on callbacks that run in a single thread to achieve real-time latency and avoid locks. It is widely used in embedded programming.<br>- <a href="https://metapatterns.io/basic-metapatterns/monolith/#inexact-half-synchalf-async-coroutines-or-fibers"><em>Half-Sync/Half-Async</em></a> is an internally layered approach that allocates a coroutine or fiber to each task. It is more resource-efficient than <a href="https://metapatterns.io/basic-metapatterns/monolith/#single-threaded-reactor-one-thread-one-task"><em>Reactor</em></a> but lacks the real-time responsiveness of <a href="https://metapatterns.io/basic-metapatterns/monolith/#proactor-one-thread-many-tasks"><em>Proactor</em></a>.</li><li><a href="https://metapatterns.io/basic-metapatterns/shards/#persistent-slice-sharding-shards-partitions-multitenancy-cells-amazon-definition"><em>Shards</em></a> are multiple instances of a <a href="https://metapatterns.io/basic-metapatterns/monolith/"><em>Monolith</em></a>, each owning a slice of the system’s data. A client must know which shard to access either through storing its address or by querying an <a href="https://metapatterns.io/extension-metapatterns/proxy/#on-the-client-side-ambassador"><em>Ambassador</em> <em>Proxy</em></a> library written by the team that deploys the shards. This is the architecture of choice when clients are independent from each other but the entire dataset is too large to fit in a single server.</li><li><a href="https://metapatterns.io/basic-metapatterns/shards/#persistent-copy-replica"><em>Replicas</em></a> are instances of a <a href="https://metapatterns.io/basic-metapatterns/monolith/"><em>Monolith</em></a> with identical data used to achieve fault tolerance and high throughput. Any writes to one replica must be propagated to the other replicas:<br>- With <a href="https://metapatterns.io/fragmented-metapatterns/polyglot-persistence/#read-only-replicas">semi-specialized replicas</a> all write requests go to a single <em>leader</em> instance which publishes the changes for the other replicas, called <em>followers</em>, to apply to their datasets. Read requests usually go to the followers, and the more read traffic there is, the more followers are deployed.<br>- If all the replicas are identical, any of them can handle a write request and publish the update for the other replicas to apply. This scales write throughput but involves the chance of data conflicts when the same data record is simultaneously changed on multiple replicas. See <a href="https://metapatterns.io/extension-metapatterns/shared-repository/#data-grid-of-space-based-architecture-sba-replicated-cache-distributed-cache"><em>Data Grid</em></a><em> </em>of <a href="https://metapatterns.io/extension-metapatterns/sandwich/#space-based-architecture"><em>Space-Based Architecture</em></a>.</li></ul><h4>Monoliths with auxiliary layers</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*yBXdxSqYIFtSGSaQ3keyJg.png" /></figure><p>In other kinds of systems, common in server-side programming, some functionality moves to a dedicated layer while the business logic remains monolithic:</p><ul><li><a href="https://metapatterns.io/basic-metapatterns/monolith/"><em>Monolith</em></a><em> with a </em><a href="https://metapatterns.io/basic-metapatterns/layers/#data-persistence"><em>database</em></a> relies on an external data storage component for persistence.</li><li><a href="https://metapatterns.io/basic-metapatterns/monolith/"><em>Monolith</em></a><em> with </em><a href="https://metapatterns.io/fragmented-metapatterns/polyglot-persistence/"><em>Polyglot Persistence</em></a> uses specialized databases to improve performance.</li><li><a href="https://metapatterns.io/basic-metapatterns/monolith/"><em>Monolith</em></a><em> with </em><a href="https://metapatterns.io/fragmented-metapatterns/backends-for-frontends--bff-/"><em>Backends for Frontends</em></a> employs a <a href="https://metapatterns.io/extension-metapatterns/proxy/"><em>Proxy</em></a> for each kind of client to address variations in the clients’ protocols and security.</li><li><em>Managed </em><a href="https://metapatterns.io/basic-metapatterns/shards/#persistent-slice-sharding-shards-partitions-multitenancy-cells-amazon-definition"><em>Shards</em></a> run behind a single <a href="https://metapatterns.io/extension-metapatterns/proxy/#load-balancer-sharding-proxy-cell-router-messaging-grid-scheduler"><em>Sharding Proxy</em></a> which connects each system’s client to the shard that has that client’s data thus isolating the clients from the knowledge of the system’s internal composition.</li><li><a href="https://metapatterns.io/implementation-metapatterns/mesh/#peer-to-peer-networks"><em>Peer-to-Peer Mesh</em></a> interconnects multiple instances of an application, acting as a distributed <a href="https://metapatterns.io/extension-metapatterns/middleware/"><em>Middleware</em></a>.</li></ul><h4>Monoliths with Plugins</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9xBiqwd1au12bmS6t3QhVg.png" /></figure><p>A monolithic core can be extended with disposable additions:</p><ul><li><a href="https://metapatterns.io/implementation-metapatterns/plugins/"><em>Plugins</em></a> allow for parts of the core’s workflow to be supplied by internal or external teams, customizing the experience of the system’s users without modifications to its main code.</li><li><a href="https://metapatterns.io/implementation-metapatterns/hexagonal-architecture/#model-view-controller-mvc-action-domain-responder-adr-resource-method-representation-rmr-model-2-mvc2-game-development-engine"><em>Model-View-Controller</em> and related patterns</a> provide a <a href="https://metapatterns.io/extension-metapatterns/proxy/#user-interface-presentation-layer-separated-presentation-command-line-interface-cli-graphical-user-interface-gui-frontend-human-machine-interface-hmi-man-machine-interface-mmi-operator-interface"><em>presentation layer</em></a> that isolates the main code from dependencies on the UI framework or network protocol, thus minimizing the effort of porting the software to another platform.</li><li><a href="https://metapatterns.io/implementation-metapatterns/hexagonal-architecture/"><em>Hexagonal Architecture</em></a> keeps the entire business logic self-sufficient by wrapping every dependency with a dedicated <a href="https://metapatterns.io/extension-metapatterns/proxy/#adapter-anticorruption-layer-abstraction-layer-open-host-service-gateway-message-translator-api-service-cell-gateway-inexact-backend-for-frontend-database-access-layer-data-mapper-repository-driver"><em>Adapter</em></a>, which not only improves portability but also helps with testing and allows for changing vendors late in the development cycle.</li></ul><h4>Underdeveloped Moduliths</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*a3qtfeiqccFiZrQaDX6GRA.png" /></figure><p>If a <a href="https://metapatterns.io/basic-metapatterns/monolith/"><em>Monolith</em></a> evolves for a long time, it will likely become segmented into subdomain components, yielding a <a href="https://metapatterns.io/basic-metapatterns/services/#synchronous-modules-modular-monolith-modulith"><em>Modulith</em></a>. As that process is not instantaneous, there are a couple of transitional architectures:</p><ul><li><a href="https://metapatterns.io/basic-metapatterns/monolith/"><em>Monolith</em></a><em> with </em><a href="https://metapatterns.io/basic-metapatterns/layers/#generic-code-libraries-and-utilities"><em>libraries</em></a> involves subdomain-specific third-party components which are called by its cohesive business logic.</li><li><a href="https://metapatterns.io/basic-metapatterns/services/#synchronous-modules-modular-monolith-modulith"><em>Modulith</em></a><em> with shared code</em> has the business logic largely separated into subdomain modules which still rely on a common codebase for shared functionality.</li></ul><h3>Layered architectures</h3><p>Layering enables the use of specialized technologies and third-party components while avoiding the <a href="https://martinfowler.com/bliki/MonolithFirst.html">risky</a> subdivision of business logic. It also allows for parts of the system to <a href="https://metapatterns.io/foundations-of-software-architecture/forces--asynchronicity--and-distribution/#conflicting-forces">differ in their qualities, placement, and scalability</a>. All of that makes layered architectures suitable for full-featured, medium-sized projects run by one or two teams where both the speed of development and supportability matter.</p><h4>Ordinary Layers</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*funmmvFxnlFmLBf1j1AKKg.png" /></figure><p>Typical layered architectures include:</p><ul><li><a href="https://metapatterns.io/basic-metapatterns/layers/"><em>Layers</em></a> of various composition, for example:<br>- <a href="https://metapatterns.io/basic-metapatterns/layers/#entity-control-boundary-ecb-entity-boundary-control-ebc-boundary-control-entity-bce"><em>Entity-Control-Boundary</em></a> which represent the <a href="https://metapatterns.io/basic-metapatterns/layers/#domain-business-rules-or-model"><em>domain model</em></a>, <a href="https://metapatterns.io/basic-metapatterns/layers/#application-use-cases-or-integration"><em>use cases</em></a>, and <a href="https://metapatterns.io/basic-metapatterns/layers/#interface-api-or-ui"><em>interface</em></a>, respectively. This pattern originated in the age of complex desktop applications.<br>- <a href="https://metapatterns.io/basic-metapatterns/layers/#domain-driven-design-ddd-layers"><em>Domain-Driven Design</em> decomposition</a> into <em>presentation</em> (interface), <em>application</em> (use cases), <em>domain</em> (business rules), and <em>infrastructure</em> (communication and persistence). It targets enterprise systems.<br>- <a href="https://metapatterns.io/basic-metapatterns/layers/#embedded-systems"><em>Embedded systems</em></a> with pairs of UI + HMI, SDK + HAL, and FW + HW implemented by distinct parties in the supply chain.</li><li><a href="https://metapatterns.io/basic-metapatterns/layers/"><em>Layers</em></a><em> with </em><a href="https://metapatterns.io/fragmented-metapatterns/polyglot-persistence/"><em>Polyglot Persistence</em></a> where the <a href="https://metapatterns.io/basic-metapatterns/layers/#data-persistence"><em>persistence</em></a> layer involves multiple databases, usually chosen for their performance with specialized payloads.</li><li><a href="https://metapatterns.io/basic-metapatterns/layers/"><em>Layers</em></a><em> with </em><a href="https://metapatterns.io/fragmented-metapatterns/backends-for-frontends--bff-/"><em>Backends for Frontends</em></a> with a dedicated <a href="https://metapatterns.io/basic-metapatterns/layers/#interface-api-or-ui"><em>interface</em></a> and/or <a href="https://metapatterns.io/basic-metapatterns/layers/#application-use-cases-or-integration"><em>application</em></a> component for each kind of client when the clients differ in their protocols and/or workflows.</li><li><a href="https://metapatterns.io/basic-metapatterns/monolith/"><em>Monolith</em></a><em> with a </em><a href="https://metapatterns.io/basic-metapatterns/layers/#data-persistence"><em>database</em></a> as a case of rudimentary layering of server-side systems.</li></ul><h4>Scaled Layers</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LK6TjKO6_oquNQBobDHvVQ.png" /></figure><p>Several layered architectures build around scalability:</p><ul><li><a href="https://metapatterns.io/basic-metapatterns/layers/#three-tier-architecture"><em>Three-Tier Architecture</em></a> contains a frontend layer with an instance per system’s user, scaled backend, and non-scaled database. It exploits the physical distribution of the system to <a href="https://metapatterns.io/foundations-of-software-architecture/forces--asynchronicity--and-distribution/#distribution">reap cost, performance, and security benefits</a>.</li><li><a href="https://metapatterns.io/basic-metapatterns/services/#scaled-service"><em>Scaled service</em></a> runs multiple instances of a stateless application between a <a href="https://metapatterns.io/extension-metapatterns/proxy/#load-balancer-sharding-proxy-cell-router-messaging-grid-scheduler"><em>Load Balancer</em></a>, which evenly distributes user requests among the instances, and a <a href="https://metapatterns.io/extension-metapatterns/shared-repository/#shared-database-integration-database-data-domain-database-of-service-based-architecture"><em>Shared Database</em></a>. It is the default approach for scaling a server-side service.</li><li><a href="https://metapatterns.io/extension-metapatterns/orchestrator/#api-composer-remote-facade-gateway-aggregation-composed-message-processor-scatter-gather-mapreduce"><em>MapReduce</em> or <em>Scatter-Gather</em></a> runs a coupled part of a calculation in a non-scaled layer while mutually independent parts are delegated to multiple worker shards.</li><li><em>Managed </em><a href="https://metapatterns.io/basic-metapatterns/shards/#persistent-slice-sharding-shards-partitions-multitenancy-cells-amazon-definition"><em>Shards</em></a> rely on a <a href="https://metapatterns.io/extension-metapatterns/proxy/#load-balancer-sharding-proxy-cell-router-messaging-grid-scheduler"><em>Sharding Proxy</em></a> layer to connect a client to the appropriate shard. This removes the need for the client to know which shard contains its data.</li><li><a href="https://metapatterns.io/implementation-metapatterns/mesh/#peer-to-peer-networks"><em>Peer-to-Peer Mesh</em></a> builds a distributed <a href="https://metapatterns.io/extension-metapatterns/middleware/"><em>Middleware</em></a> layer that interconnects instances of a client application.</li></ul><h4>Other layered systems</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*V8TVSSdPTypxvVB4M6RV7g.png" /></figure><p>Besides that, there are a few peculiar layered systems:</p><ul><li><a href="https://metapatterns.io/implementation-metapatterns/hexagonal-architecture/#model-view-presenter-mvp-model-view-adapter-mva-model-view-viewmodel-mvvm-model-1-mvc1-document-view"><em>Model-View-Presenter</em> family of patterns</a> features layered user interfaces which decouple the main system from a GUI or web framework with the goal of being able to easily switch to another framework version or vendor.</li><li><a href="https://metapatterns.io/implementation-metapatterns/hexagonal-architecture/#ddd-style-hexagonal-architecture-onion-architecture-clean-architecture"><em>Onion Architecture</em> or <em>Clean Architecture</em></a> is a <a href="https://metapatterns.io/implementation-metapatterns/hexagonal-architecture/"><em>Hexagonal Architecture</em></a> (see below) with a layered core structured along the <a href="https://metapatterns.io/basic-metapatterns/layers/#domain-driven-design-ddd-layers">ideas of <em>Domain-Driven Design</em></a>.</li><li><a href="https://metapatterns.io/extension-metapatterns/sandwich/"><em>Sandwich</em> architectures</a> are <a href="https://metapatterns.io/basic-metapatterns/layers/"><em>Layers</em></a> with the <a href="https://metapatterns.io/basic-metapatterns/layers/#domain-business-rules-or-model"><em>domain logic</em> layer</a> split into subdomains. It is a pragmatic low effort approach to tackle complexity in quickly evolving projects that can afford several development teams. It also addresses <a href="https://metapatterns.io/foundations-of-software-architecture/arranging-communication/programming-and-architectural-paradigms/#procedural-data-centric-paradigm--shared-data">data-centric domains</a>.</li></ul><h3>Plugins family</h3><p>Some architectures specialize in separating complex core logic from miscellaneous details to make the <em>core</em> independent and reusable under changing conditions. In most cases the core contains monolithic business logic but that may vary among patterns. This family of topologies is prevalent in long-living or highly customizable products whose codebases are too expensive to rewrite to address every trend or fad.</p><h4>Plugin Architecture</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*d3Q1WxyHziVftFO6bfg9cg.png" /></figure><p><a href="https://metapatterns.io/implementation-metapatterns/plugins/"><em>Plugins</em></a> are external components which supply predefined parts of a host component’s workflow. They may be created by the company that makes the product, often for the sake of selling several <em>flavors</em> with limited or specialized functionality. Or they may come from external programmers, as codecs in video players or customizations for accounting software, to extend the usefulness of a product without overburdening its core codebase.</p><h4>Separated Presentation</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*13iEebQBeFny5wMnOrGmeA.png" /></figure><p><a href="https://metapatterns.io/implementation-metapatterns/hexagonal-architecture/#upper-half-separated-presentation-open-host-service"><em>Separated Presentation</em></a> extracts the user or network interface functionality into a dedicated layer which is often further subdivided. This makes the main codebase reusable in different environments:</p><ul><li>The <a href="https://metapatterns.io/implementation-metapatterns/hexagonal-architecture/#model-view-controller-mvc-action-domain-responder-adr-resource-method-representation-rmr-model-2-mvc2-game-development-engine"><em>Model-View-Controller</em></a> family of patterns has separate modules for platform-specific input and display output which is beneficial when there is no web or GUI framework that can provide a unified high-level user interface.</li><li>The <a href="https://metapatterns.io/implementation-metapatterns/hexagonal-architecture/#model-view-presenter-mvp-model-view-adapter-mva-model-view-viewmodel-mvvm-model-1-mvc1-document-view"><em>Model-View-Presenter</em></a> family builds on top of a pre-existing platform-specific presentation layer. Most of these patterns add an intermediate <a href="https://metapatterns.io/extension-metapatterns/proxy/#adapter-anticorruption-layer-abstraction-layer-open-host-service-gateway-message-translator-api-service-cell-gateway-inexact-backend-for-frontend-database-access-layer-data-mapper-repository-driver"><em>Adapter</em></a> between the platform-dependent code and the core application.</li></ul><h4>Control patterns</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*l_WjPWAJ5IkmPhL-kieR4g.png" /></figure><p>A couple of topologies originate with embedded or systems programming where it is important to abstract the business logic from the hardware components which tend to quickly go out of production and thus need to be replaced with incompatible models:</p><ul><li><a href="https://metapatterns.io/implementation-metapatterns/hexagonal-architecture/#pedestal"><em>Pedestal</em></a> wraps each hardware component in a system with a dedicated driver to reduce the dependency of the business logic on hardware specifications thus allowing for the software to be reused for different hardware setups.</li><li><a href="https://metapatterns.io/implementation-metapatterns/microkernel/"><em>Microkernel Architecture</em></a> relies on an eponymous layer to mediate between resource consumers and resource producers which implement generic interfaces and thus are replaceable. This approach is surprisingly ubiquitous:<br>- <a href="https://metapatterns.io/implementation-metapatterns/microkernel/#operating-system"><em>Operating systems</em></a> are the origin of <a href="https://metapatterns.io/implementation-metapatterns/microkernel/"><em>Microkernel</em></a>, with user space applications competing for system resources owned by the device drivers.<br>- <a href="https://metapatterns.io/implementation-metapatterns/microkernel/#interpreter-script-domain-specific-language-dsl"><em>Interpreters</em></a> run user scripts in a sandbox and provide them access to installed libraries.<br>- <a href="https://metapatterns.io/implementation-metapatterns/microkernel/#software-framework-pluggable-component-framework"><em>Software frameworks</em></a> follow a similar approach, building a <a href="https://refactoring.guru/design-patterns/facade"><em>Facade</em></a> to grant user code a managed access to the framework’s internal components.<br>- <a href="https://metapatterns.io/implementation-metapatterns/microkernel/#virtualizer-hypervisor-container-orchestrator-distributed-runtime"><em>Hypervisors</em>, <em>Virtualizers</em>, and <em>Distributed Runtimes</em></a> abstract a guest operating system or applications from the platform they run on.</li></ul><h4>Hexagonal Architecture</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_LrcsiAbcRmtkBjiD5MGTA.png" /></figure><p>A few architectures fully isolate business logic from its environment, resulting in great portability, simpler automated testing and improved separation of concerns:</p><ul><li><a href="https://metapatterns.io/implementation-metapatterns/hexagonal-architecture/#ports-and-adapters-hexagonal-architecture"><em>Ports and Adapters</em></a> (the original <a href="https://metapatterns.io/implementation-metapatterns/hexagonal-architecture/"><em>Hexagonal Architecture</em></a>) inserts an <a href="https://metapatterns.io/extension-metapatterns/proxy/#adapter-anticorruption-layer-abstraction-layer-open-host-service-gateway-message-translator-api-service-cell-gateway-inexact-backend-for-frontend-database-access-layer-data-mapper-repository-driver"><em>Adapter</em></a> into every communication pathway in or out of its business logic core but does not specify the structure of the core itself, which makes the pattern universally applicable.</li><li><a href="https://metapatterns.io/implementation-metapatterns/hexagonal-architecture/#ddd-style-hexagonal-architecture-onion-architecture-clean-architecture"><em>Onion Architecture</em> or <em>Clean Architecture</em></a> structures the core in accordance with the <a href="https://metapatterns.io/basic-metapatterns/layers/#domain-driven-design-ddd-layers">rules of <em>Domain-Driven Design</em></a>, limiting the applicability of this topology to enterprise systems or complex backends.</li></ul><h4>Cell</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*wSLr3rriq55yHrTVTkHmRQ.png" /></figure><p><a href="https://metapatterns.io/implementation-metapatterns/hexagonal-architecture/#cell-cluster-domain"><em>Cell</em></a> is a building block of huge systems that follow <a href="https://metapatterns.io/fragmented-metapatterns/service-oriented-architecture--soa-/#domain-oriented-microservice-architecture-doma"><em>Domain-Oriented Microservice Architecture</em></a> or <a href="https://metapatterns.io/fragmented-metapatterns/hierarchy/#in-depth-hierarchy-cell-based-microservice-architecture-wso2-version-segmented-microservice-architecture-services-of-services-clusters-of-services"><em>Cell-Based Architecture</em></a>. It is a kind of <a href="https://metapatterns.io/implementation-metapatterns/hexagonal-architecture/"><em>Hexagonal Architecture</em></a> with a modular and often distributed core. The internals of a <em>Cell</em> are hidden behind a <a href="https://metapatterns.io/extension-metapatterns/proxy/#adapter-anticorruption-layer-abstraction-layer-open-host-service-gateway-message-translator-api-service-cell-gateway-inexact-backend-for-frontend-database-access-layer-data-mapper-repository-driver"><em>Cell Gateway</em></a> which implements the <em>Cell</em>’s public interface. Any outgoing communication, initiated from inside the <em>Cell</em>, goes through its <a href="https://metapatterns.io/extension-metapatterns/proxy/#adapter-anticorruption-layer-abstraction-layer-open-host-service-gateway-message-translator-api-service-cell-gateway-inexact-backend-for-frontend-database-access-layer-data-mapper-repository-driver"><em>Adapters</em></a> or through <a href="https://metapatterns.io/implementation-metapatterns/plugins/#ambassador-plugin-logic-extension"><em>Plugins</em> supplied by peer <em>Cells</em></a>.</p><h3>Services area</h3><p>Partitioning a system into <a href="https://metapatterns.io/basic-metapatterns/services/#synchronous-modules-modular-monolith-modulith"><em>modules</em></a> or <a href="https://metapatterns.io/basic-metapatterns/services/#distributed-services-service-based-architecture-space-based-architecture-microservices"><em>services</em></a> which match its subdomains and assigning the components to dedicated teams greatly reduces the cognitive load that the programmers face as each person needs to comprehend only the service they work on. Given that it is <a href="https://realmensch.org/2018/05/04/we-are-all-10x-developers/">cognitive load that determines development speed</a>, most large projects have service-based topologies.</p><p>However, full domain partitioning [<a href="https://metapatterns.io/appendices/books-referenced/#fsa">FSA</a>] is beneficial <a href="https://metapatterns.io/foundations-of-software-architecture/modules-and-complexity/#coupling-and-cohesion">only when the system’s subdomains are weakly coupled</a> along every level of their functionality, which is why many real-world topologies mix cohesive system-wide layers and decoupled subdomain services.</p><h4>Barebone services</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*o7lcDzFkkLHUKEggYRxR2Q.png" /></figure><p>A few architectures are completely segmented into subdomains:</p><ul><li><a href="https://metapatterns.io/basic-metapatterns/services/#distributed-services-service-based-architecture-space-based-architecture-microservices">Distributed <em>Services</em></a> or <a href="https://metapatterns.io/basic-metapatterns/services/#synchronous-modules-modular-monolith-modulith">in-process <em>Modules</em></a> rely on <a href="https://metapatterns.io/foundations-of-software-architecture/arranging-communication/orchestration/#mutual-orchestration"><em>mutual orchestration</em></a>. They come in several kinds:<br>- <a href="https://metapatterns.io/basic-metapatterns/services/#service-based-architecture-sba-macroservices"><em>Service-Based Architecture</em></a> tends to employ single instances of services which cover entire subdomains. It is used for multi-team server-side projects with no special performance considerations.<br>- <a href="https://metapatterns.io/basic-metapatterns/services/#synchronous-modules-modular-monolith-modulith"><em>Modulith</em></a> (<em>Modular Monolith</em>) runs subdomain-sized components in a single process, sacrificing fault tolerance for consistency and operational costs. This architecture fits smaller Internet businesses.<br>- <a href="https://metapatterns.io/basic-metapatterns/services/#microservices"><em>Microservices</em></a> with highly scalable sub-subdomain components implement high load and high budget systems with well-established domain knowledge but frequently changing business needs.<br>- <a href="https://metapatterns.io/basic-metapatterns/services/#actors"><em>Actors</em></a> are asynchronous objects used for real-time tasks that range from embedded telephony to instant messengers to financial systems. Consider them if you benefit from modeling every user of your system as a lightweight independently acting entity.</li><li><a href="https://metapatterns.io/fragmented-metapatterns/layered-services/#orchestrated-three-layered-services"><em>Three-Layered Services</em></a> subdivide each service into the <a href="https://metapatterns.io/basic-metapatterns/layers/#application-use-cases-or-integration"><em>use cases</em></a>, <a href="https://metapatterns.io/basic-metapatterns/layers/#domain-business-rules-or-model"><em>domain logic</em></a>, and <a href="https://metapatterns.io/basic-metapatterns/layers/#data-persistence"><em>persistence</em></a> layers, allowing for further specialization of staff and technologies.</li><li><a href="https://metapatterns.io/basic-metapatterns/pipeline/"><em>Pipeline</em></a> is a <a href="https://metapatterns.io/foundations-of-software-architecture/arranging-communication/choreography/"><em>choreographed</em></a> system where each component implements a single stage of data or event processing:<br>- <a href="https://metapatterns.io/basic-metapatterns/pipeline/#pipes-and-filters-workflow-system"><em>Pipes and Filters</em></a> is a local and usually linear <a href="https://metapatterns.io/basic-metapatterns/pipeline/"><em>Pipeline</em></a> that processes a data stream. It is the architecture of choice for systems with customizable workflows and polymorphic algorithms such as video capture or replay.<br>- <a href="https://metapatterns.io/basic-metapatterns/pipeline/#choreographed-broker-topology-event-driven-architecture-eda-event-collaboration"><em>Choreographed Event-Driven Architecture</em></a> runs multiple branched <a href="https://metapatterns.io/basic-metapatterns/pipeline/"><em>Pipelines</em></a>, each implementing a single use case, over a shared set of services. It is an easily extendable alternative to <a href="https://metapatterns.io/basic-metapatterns/services/#microservices"><em>Microservices</em></a> for domains with a few highly loaded yet simple scenarios.<br>- <a href="https://metapatterns.io/basic-metapatterns/pipeline/#data-mesh"><em>Data Mesh</em></a> collects, transforms, and processes analytical data from a system of services.</li><li><a href="https://metapatterns.io/fragmented-metapatterns/layered-services/#choreographed-two-layered-services"><em>Two-Layered Services</em></a> split each component of a <a href="https://metapatterns.io/basic-metapatterns/pipeline/"><em>Pipeline</em></a> (usually a <a href="https://metapatterns.io/basic-metapatterns/pipeline/#choreographed-broker-topology-event-driven-architecture-eda-event-collaboration"><em>Choreographed Event-Driven Architecture</em></a>) into <a href="https://metapatterns.io/basic-metapatterns/layers/#domain-business-rules-or-model"><em>domain logic</em></a> and <a href="https://metapatterns.io/basic-metapatterns/layers/#data-persistence"><em>persistence</em></a> layers, emphasizing the use of databases private to their services. Noticeably, the <a href="https://metapatterns.io/basic-metapatterns/layers/#application-use-cases-or-integration"><em>use case logic</em></a> is represented as the connections between the services.</li></ul><h4>Services with extensions</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*OaRvSFLsqIATIb7gWEd_aw.png" /></figure><p>Services become simpler when common aspects are extracted to a dedicated layer:</p><ul><li><a href="https://metapatterns.io/basic-metapatterns/services/"><em>Services</em></a><em> with a </em><a href="https://metapatterns.io/extension-metapatterns/middleware/"><em>Middleware</em></a> rely on an external transport and deployment layer which is usually a framework available off-the-shelf:<br>- <a href="https://metapatterns.io/extension-metapatterns/middleware/#service-mesh"><em>Service Mesh</em></a> is a distributed <a href="https://metapatterns.io/extension-metapatterns/middleware/"><em>Middleware</em></a> for highly scalable systems.<br>- <a href="https://metapatterns.io/extension-metapatterns/middleware/#message-bus"><em>Message Bus</em></a> interconnects services that use different communication technologies by translating between their protocols. It is useful in integration of legacy systems.<br>- <a href="https://metapatterns.io/extension-metapatterns/middleware/#event-mediator"><em>Event Mediator</em></a> drives communication in <a href="https://metapatterns.io/basic-metapatterns/pipeline/#choreographed-broker-topology-event-driven-architecture-eda-event-collaboration"><em>Event-Driven Architectures</em></a>.<br>- <a href="https://metapatterns.io/extension-metapatterns/middleware/#enterprise-service-bus-esb"><em>Enterprise Service Bus</em></a> is an <a href="https://metapatterns.io/foundations-of-software-architecture/arranging-communication/orchestration/"><em>orchestrating</em></a> <a href="https://metapatterns.io/extension-metapatterns/middleware/"><em>Middleware</em></a> that unites several historically separate subsystems into an <a href="https://metapatterns.io/fragmented-metapatterns/service-oriented-architecture--soa-/#enterprise-soa"><em>Enterprise Service-Oriented Architecture</em></a>.</li><li><a href="https://metapatterns.io/basic-metapatterns/services/"><em>Services</em></a><em> with a </em><a href="https://metapatterns.io/extension-metapatterns/shared-repository/"><em>Shared Repository</em></a> share a <a href="https://metapatterns.io/basic-metapatterns/layers/#data-persistence">data storage or exchange layer</a> and are eligible to implement data-centric domains:<br>- <a href="https://metapatterns.io/extension-metapatterns/shared-repository/#shared-database-integration-database-data-domain-database-of-service-based-architecture"><em>Shared Database</em></a> simplifies architectural design and data synchronization (see <a href="https://metapatterns.io/extension-metapatterns/sandwich/#service-based-architecture"><em>Service-Based Architecture</em></a>).<br>- <a href="https://metapatterns.io/extension-metapatterns/shared-repository/#shared-file-system"><em>Shared File System</em></a> is among the simplest methods of organizing <a href="https://metapatterns.io/basic-metapatterns/pipeline/"><em>Pipelines</em></a> for processing large volumes of data records.<br>- <a href="https://metapatterns.io/extension-metapatterns/shared-repository/#shared-memory"><em>Shared Memory</em></a> is the fastest method of data exchange especially suitable for low latency software.<br>- <a href="https://metapatterns.io/extension-metapatterns/shared-repository/#data-grid-of-space-based-architecture-sba-replicated-cache-distributed-cache"><em>Data Grid</em></a> is a highly scalable, distributed in-memory datastore of <a href="https://metapatterns.io/extension-metapatterns/sandwich/#space-based-architecture"><em>Space-Based Architecture</em></a>.</li><li><a href="https://metapatterns.io/basic-metapatterns/services/"><em>Services</em></a><em> with </em><a href="https://metapatterns.io/fragmented-metapatterns/polyglot-persistence/"><em>Polyglot Persistence</em></a> employ several databases, usually to improve performance by using each database in the role it is optimized for.</li><li><a href="https://metapatterns.io/basic-metapatterns/services/"><em>Services</em></a><em> with a </em><a href="https://metapatterns.io/extension-metapatterns/proxy/#adapter-anticorruption-layer-abstraction-layer-open-host-service-gateway-message-translator-api-service-cell-gateway-inexact-backend-for-frontend-database-access-layer-data-mapper-repository-driver"><em>Gateway</em></a> rely on a shared <a href="https://metapatterns.io/extension-metapatterns/proxy/"><em>Proxy</em></a> layer to handle communication with clients. Third-party <em>Proxies</em> reliably cover security and networking concerns with very little effort from the programmers’ side.</li><li>In <a href="https://metapatterns.io/extension-metapatterns/orchestrator/"><em>Orchestrated Services</em></a> it is the <a href="https://metapatterns.io/basic-metapatterns/layers/#application-use-cases-or-integration"><em>use cases</em></a> which are extracted into a system-wide layer. Such subdivision of business logic saves the day when there are many complex system-wide scenarios while the business rules are specific to particular subdomains.</li><li><a href="https://metapatterns.io/basic-metapatterns/services/"><em>Services</em></a><em> with an </em><a href="https://metapatterns.io/extension-metapatterns/orchestrator/#api-gateway"><em>API Gateway</em></a> implement public-API-related tasks — both <a href="https://metapatterns.io/basic-metapatterns/layers/#interface-api-or-ui">protocol support</a> and <a href="https://metapatterns.io/basic-metapatterns/layers/#application-use-cases-or-integration">basic orchestration</a> — in a single component which calls underlying services containing the domain logic. This is a simplified architecture for ordinary server-side systems.</li><li><a href="https://metapatterns.io/basic-metapatterns/services/"><em>Services</em></a><em> with </em><a href="https://metapatterns.io/fragmented-metapatterns/backends-for-frontends--bff-/"><em>Backends for Frontends</em></a> have a layer of client-specific components that encapsulate clients’ protocols and/or scenarios and are useful when a system serves drastically different kinds of clients.</li></ul><h4>Hierarchies of services</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*dB_k41wa6wr20-hn0JP5pg.png" /></figure><p>Services are building blocks for a couple of <a href="https://metapatterns.io/fragmented-metapatterns/hierarchy/">hierarchical architectures</a> used in huge projects:</p><ul><li><a href="https://metapatterns.io/fragmented-metapatterns/hierarchy/#in-depth-hierarchy-cell-based-microservice-architecture-wso2-version-segmented-microservice-architecture-services-of-services-clusters-of-services"><em>Cell-Based Architecture</em></a> is a system of clusters of (often co-deployed) services called <a href="https://metapatterns.io/implementation-metapatterns/hexagonal-architecture/#cell-cluster-domain"><em>Cells</em></a>. Recursive decomposition lowers the top-level system complexity and decouples the subdomains by making their interdependencies explicit.</li><li><a href="https://metapatterns.io/fragmented-metapatterns/hierarchy/#bottom-up-hierarchy-bus-of-buses-network-of-networks"><em>Hierarchical Middleware</em></a> interconnects several subsystems of services which belong to different organizations or physical networks.</li></ul><h4>Partially merged services</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CwGI8YGbQVRlqtvpUfXBMQ.png" /></figure><p>There are systems in-between <a href="https://metapatterns.io/basic-metapatterns/services/"><em>Services</em></a> and <a href="https://metapatterns.io/basic-metapatterns/monolith/"><em>Monolith</em></a> or <a href="https://metapatterns.io/basic-metapatterns/layers/"><em>Layers</em></a>:</p><ul><li>In <a href="https://metapatterns.io/basic-metapatterns/services/#synchronous-modules-modular-monolith-modulith"><em>Modulith</em></a><em> with shared code</em> the business logic is split into subdomains but still relies on a shared codebase. It is a transitional architecture often seen in growing projects that <a href="https://martinfowler.com/bliki/MonolithFirst.html">explore subdomain boundaries</a>.</li><li>In <a href="https://metapatterns.io/extension-metapatterns/sandwich/"><em>Sandwich</em></a> only the <a href="https://metapatterns.io/basic-metapatterns/layers/#domain-business-rules-or-model"><em>domain logic</em> layer</a>, which is usually the largest part of the codebase, is segmented into subdomains. This is the most natural subdivision for many real-world systems and which inspires multiple architectures:<br>- <a href="https://metapatterns.io/extension-metapatterns/sandwich/#service-based-architecture"><em>Service-Based Architecture</em></a> — the pragmatic approach to server-side development — often uses a <a href="https://metapatterns.io/extension-metapatterns/shared-repository/#shared-database-integration-database-data-domain-database-of-service-based-architecture"><em>Shared Database</em></a> and an <a href="https://metapatterns.io/extension-metapatterns/proxy/#api-gateway"><em>API Gateway</em></a>.<br>- <a href="https://metapatterns.io/extension-metapatterns/sandwich/#space-based-architecture"><em>Space-Based Architecture</em></a> provides unparalleled elasticity and scalability for data-centric domains with its <em>replicated cache</em> called <a href="https://metapatterns.io/extension-metapatterns/shared-repository/#data-grid-of-space-based-architecture-sba-replicated-cache-distributed-cache"><em>Data Grid</em></a>.<br>- <a href="https://metapatterns.io/extension-metapatterns/sandwich/#blackboard-system"><em>Blackboard Architecture</em></a> schedules specialized algorithms to solve ill-structured problems.<br>- <a href="https://metapatterns.io/extension-metapatterns/sandwich/#nanoservices"><em>Nanoservices</em></a> are independently scalable functions that run in a cloud and share an <a href="https://metapatterns.io/extension-metapatterns/proxy/#api-gateway"><em>(API) Gateway</em></a> and a <a href="https://metapatterns.io/basic-metapatterns/layers/#data-persistence">database</a>.</li></ul><h3>Fragmented patterns</h3><p>Finally, some architectures are subdivided into both layers of abstraction and subdomains, resulting in topologies containing many small components. This happens when interacting parts of a system <a href="https://metapatterns.io/foundations-of-software-architecture/forces--asynchronicity--and-distribution/#conflicting-forces">vary in their qualities and technologies</a> and thus should stay separate, ordinary decomposition results in components too large for comfortable development, or both.</p><h4>Layers of services</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*JCWryvQMF8ssfVIct6Q3lw.png" /></figure><p>A few topologies are made of layers, each of which is subdivided into services:</p><ul><li>In <a href="https://metapatterns.io/fragmented-metapatterns/polyglot-persistence/"><em>Services with Polyglot Persistence</em></a> there are several specialized databases with shared access. This topology may emerge from <a href="https://metapatterns.io/appendices/evolutions-of-architectures/evolutions-of-a-shared-repository/#deploy-specialized-databases">performance optimization</a> of <a href="https://metapatterns.io/basic-metapatterns/services/"><em>Services</em></a><em> with a </em><a href="https://metapatterns.io/extension-metapatterns/shared-repository/"><em>Shared Repository</em></a>.</li><li><a href="https://metapatterns.io/fragmented-metapatterns/backends-for-frontends--bff-/"><em>Services with Backends for Frontends</em></a> employ a dedicated <a href="https://metapatterns.io/extension-metapatterns/proxy/"><em>Proxy</em></a>, <a href="https://metapatterns.io/extension-metapatterns/orchestrator/"><em>Orchestrator</em></a>, or <a href="https://metapatterns.io/extension-metapatterns/orchestrator/#api-gateway"><em>API Gateway</em></a> for each kind of client. This makes sense when the system’s clients have very little in common.</li><li><a href="https://metapatterns.io/fragmented-metapatterns/service-oriented-architecture--soa-/"><em>Service-Oriented Architecture</em></a> features fragmented application, domain, and utility layers, with each component of a higher level calling multiple components from a layer below it. It enables code reuse, for better or worse, and has reasonably small services even in huge projects but suffers from slow development caused by extensive interdependencies between teams.</li></ul><h4>Layered services</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6bTrt19du9whBRCLua-fnQ.png" /></figure><p>More often than not, services are layered internally:</p><ul><li><a href="https://metapatterns.io/fragmented-metapatterns/layered-services/#orchestrated-three-layered-services"><em>Orchestrated Three-Layered Services</em></a> distinguish between the <a href="https://metapatterns.io/basic-metapatterns/layers/#application-use-cases-or-integration"><em>application</em></a> (use cases), <a href="https://metapatterns.io/basic-metapatterns/layers/#domain-business-rules-or-model"><em>domain</em></a> (business rules), and <a href="https://metapatterns.io/basic-metapatterns/layers/#data-persistence"><em>persistence</em></a> (database) layers.</li><li><a href="https://metapatterns.io/fragmented-metapatterns/layered-services/#choreographed-two-layered-services"><em>Choreographed Two-Layered Services</em></a> contain only the <a href="https://metapatterns.io/basic-metapatterns/layers/#domain-business-rules-or-model"><em>domain</em></a> and <a href="https://metapatterns.io/basic-metapatterns/layers/#data-persistence"><em>persistence</em></a> layers because the <a href="https://metapatterns.io/basic-metapatterns/layers/#application-use-cases-or-integration"><em>application</em></a> logic resides in the graph of connections between the services.</li></ul><h4>Hierarchies</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*swXZvVr_5QHB4SceapKkzA.png" /></figure><p>Finally, there are <a href="https://metapatterns.io/fragmented-metapatterns/hierarchy/">hierarchical topologies</a> with recursive partitioning:</p><ul><li><a href="https://metapatterns.io/fragmented-metapatterns/hierarchy/#top-down-hierarchy-orchestrator-of-orchestrators-presentation-abstraction-control-pac-hierarchical-model-view-controller-hmvc"><em>Top-Down Hierarchy</em></a> is arguably the best way to implement a system that involves many kinds of somewhat related entities. It emerges in domains as diverse as compilers, industrial automation, graphical user interfaces, and online marketplaces.</li><li><a href="https://metapatterns.io/fragmented-metapatterns/hierarchy/#bottom-up-hierarchy-bus-of-buses-network-of-networks"><em>Hierarchical Middleware</em></a> interconnects subsystems that differ in their communication protocols.</li><li><a href="https://metapatterns.io/fragmented-metapatterns/hierarchy/#in-depth-hierarchy-cell-based-microservice-architecture-wso2-version-segmented-microservice-architecture-services-of-services-clusters-of-services"><em>Cell-Based Architecture</em></a> splits every large subdomain service into a group of subservices encapsulated with a <a href="https://metapatterns.io/extension-metapatterns/proxy/#adapter-anticorruption-layer-abstraction-layer-open-host-service-gateway-message-translator-api-service-cell-gateway-inexact-backend-for-frontend-database-access-layer-data-mapper-repository-driver"><em>Cell Gateway</em></a>. This keeps individual services small without spreading hundreds of them into the system level.</li></ul><h3>Common motifs</h3><p>Every area of the topologies map highlights certain design principles:</p><ul><li>Small and simple systems may stay cohesive as <a href="https://metapatterns.io/basic-metapatterns/monolith/"><em>Monoliths</em></a> or <a href="https://metapatterns.io/basic-metapatterns/shards/"><em>Shards</em></a>.</li><li>Medium-sized software benefits from functional partitioning [<a href="https://metapatterns.io/appendices/books-referenced/#fsa">FSA</a>] into <a href="https://metapatterns.io/basic-metapatterns/layers/"><em>Layers</em></a>.</li><li>Long-lived projects become stabilized by extracting any volatile code into expendable modules. Different applications of this principle yield <a href="https://metapatterns.io/implementation-metapatterns/plugins/"><em>Plugins</em></a>, <a href="https://metapatterns.io/implementation-metapatterns/hexagonal-architecture/"><em>Hexagonal Architecture</em></a>, and <a href="https://metapatterns.io/implementation-metapatterns/microkernel/"><em>Microkernel</em></a>.</li><li>Large software is decomposed into subdomains owned by dedicated teams. See <a href="https://metapatterns.io/basic-metapatterns/services/"><em>Services</em></a> and <a href="https://metapatterns.io/basic-metapatterns/pipeline/"><em>Pipeline</em></a>.</li><li>Huge systems require recursive decomposition as found in <a href="https://metapatterns.io/fragmented-metapatterns/service-oriented-architecture--soa-/"><em>Service-Oriented Architecture</em></a> and <a href="https://metapatterns.io/fragmented-metapatterns/hierarchy/"><em>Hierarchy</em></a>.</li></ul><p>Other motifs are harder to notice as they apply to both scaled monolithic or layered systems and those subdivided into services:</p><ul><li>There is often a <em>managing layer</em> that makes use of underlying components:<br>- A <a href="https://metapatterns.io/extension-metapatterns/proxy/"><em>Proxy</em></a> is an <a href="https://metapatterns.io/basic-metapatterns/layers/#interface-api-or-ui"><em>interface</em></a> that receives and pre-processes client input, then forwards the resulting request to whatever is behind it.<br>- An <a href="https://metapatterns.io/extension-metapatterns/orchestrator/"><em>Orchestrator</em></a> is an <a href="https://metapatterns.io/basic-metapatterns/layers/#application-use-cases-or-integration"><em>application</em></a> that implements complex use cases which turn a single event or client request into a chain of calls to the lower layer.<br>- <a href="https://metapatterns.io/fragmented-metapatterns/backends-for-frontends--bff-/"><em>Backends for Frontends</em></a> segment a managing layer into client-specific services.</li><li>A <em>platform layer</em> provides some functionality to other system components:<br>- A <a href="https://metapatterns.io/extension-metapatterns/middleware/"><em>Middleware</em></a> deploys and <a href="https://metapatterns.io/basic-metapatterns/layers/#communication-middleware">interconnects</a> <a href="https://metapatterns.io/basic-metapatterns/services/"><em>Services</em></a> or <a href="https://metapatterns.io/basic-metapatterns/shards/#persistent-copy-replica"><em>Replicas</em></a>.<br>- A <a href="https://metapatterns.io/extension-metapatterns/shared-repository/"><em>Shared Repository</em></a> stores the <a href="https://metapatterns.io/basic-metapatterns/layers/#data-persistence">system’s data</a>, offering consistency and persistence.<br>- <a href="https://metapatterns.io/fragmented-metapatterns/polyglot-persistence/"><em>Polyglot Persistence</em></a> subdivides a <a href="https://metapatterns.io/extension-metapatterns/shared-repository/"><em>Shared Repository</em></a> layer.</li><li><a href="https://metapatterns.io/extension-metapatterns/sandwich/"><em>Sandwich</em></a> wraps <a href="https://metapatterns.io/basic-metapatterns/services/"><em>Services</em></a> or <a href="https://metapatterns.io/basic-metapatterns/shards/#persistent-copy-replica"><em>Replicas</em></a> with both managing and platform layers.</li><li>A <a href="https://metapatterns.io/implementation-metapatterns/mesh/"><em>Mesh</em></a> interconnects any components that use it.</li></ul><p>Obviously, <a href="https://metapatterns.io/introduction/metapatterns/">metapatterns</a> emerge as archetypes shared among system topologies.</p><h3>Summary</h3><p>There are many system topologies with various degrees of segregation into layers and subdomains. No single architecture is a silver bullet, each topology has its use depending on the circumstances. The following chapters of this book explore archetypes shared among topologies which are called <em>metapatterns</em>.</p><blockquote><em>Editor: Lars Noodén</em></blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e2d3d0b89618" width="1" height="1" alt=""><hr><p><a href="https://itnext.io/the-map-of-system-topologies-e2d3d0b89618">The Map of System Topologies</a> was originally published in <a href="https://itnext.io">ITNEXT</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Cell]]></title>
            <link>https://itnext.io/cell-777e87543e93?source=rss-7d4e79c3c009------2</link>
            <guid isPermaLink="false">https://medium.com/p/777e87543e93</guid>
            <category><![CDATA[design-patterns]]></category>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[software-design]]></category>
            <category><![CDATA[hexagonal-architecture]]></category>
            <dc:creator><![CDATA[Denys Poltorak]]></dc:creator>
            <pubDate>Wed, 25 Feb 2026 21:34:51 GMT</pubDate>
            <atom:updated>2026-02-25T21:34:51.233Z</atom:updated>
            <cc:license>http://creativecommons.org/licenses/by/4.0/</cc:license>
            <content:encoded><![CDATA[<h4>An architectural pattern</h4><p>Application of the isolation principle behind <a href="https://metapatterns.io/implementation-metapatterns/hexagonal-architecture/"><em>Hexagonal Architecture</em></a> to a distributed subsystem results in a <a href="https://github.com/wso2/reference-architecture/blob/master/reference-architecture-cell-based.md"><em>Cell</em></a> (<a href="https://metapatterns.io/analytics/ambiguous-patterns/#cells">according to WSO2, not Amazon</a>) — an encapsulated cluster of <a href="https://metapatterns.io/basic-metapatterns/services/"><em>Services</em></a> which implements a subdomain and is usually deployed as a single unit.</p><p>In the simplest implementation a <em>Cell</em>’s contents are hidden from the <em>Cell</em>’s clients by a <a href="https://metapatterns.io/extension-metapatterns/proxy/#adapter-anticorruption-layer-abstraction-layer-open-host-service-gateway-message-translator-api-service-cell-gateway-inexact-backend-for-frontend-database-access-layer-data-mapper-repository"><em>Cell Gateway</em></a> which acts as an <a href="https://metapatterns.io/extension-metapatterns/proxy/#adapter-anticorruption-layer-abstraction-layer-open-host-service-gateway-message-translator-api-service-cell-gateway-inexact-backend-for-frontend-database-access-layer-data-mapper-repository"><em>Open Host Service</em></a> [DDD], allowing for anything inside the <em>Cell</em> to be changed at will with no effect on the outside world.</p><p>Better developed <em>Cells</em> employ <a href="https://metapatterns.io/extension-metapatterns/proxy/#adapter-anticorruption-layer-abstraction-layer-open-host-service-gateway-message-translator-api-service-cell-gateway-inexact-backend-for-frontend-database-access-layer-data-mapper-repository"><em>Adapters</em></a> [GoF, DDS] and <a href="https://metapatterns.io/implementation-metapatterns/plugins/"><em>Plugins</em></a> [FSA, PEAA] for outgoing requests to build an <a href="https://metapatterns.io/extension-metapatterns/proxy/#adapter-anticorruption-layer-abstraction-layer-open-host-service-gateway-message-translator-api-service-cell-gateway-inexact-backend-for-frontend-database-access-layer-data-mapper-repository"><em>Anticorruption Layer</em></a> [DDD] that protects the <em>Cell</em>’s contents from changes in its environment.</p><p>This dichotomy is similar to that between <a href="https://metapatterns.io/implementation-metapatterns/hexagonal-architecture/#examples--separated-presentation"><em>Separated Presentation</em></a> (indirection between the system and its users or clients) and <a href="https://metapatterns.io/implementation-metapatterns/hexagonal-architecture/#examples--hexagonal-architecture"><em>Ports and Adapters</em></a> (full isolation of the business logic from its environment).</p><blockquote>In practice there are three kinds of outgoing traffic: responses to incoming client requests, pub/sub notifications, and requests to external services. In a <em>Cell</em>, <em>responses</em> are sure to pass through or be generated by the <em>Cell Gateway</em>. Indeed, a response usually reuses the request’s transport, therefore if a request arrives at the <em>Gateway</em>, the corresponding response should also start there. <em>Notifications</em> are harder to pinpoint: on one hand, they are a part of the <em>Cell</em>’s API which the <em>Gateway</em> takes care of. However, that means that the <em>Cell</em>’s internals must be aware of the <em>Gateway</em>’s existence to use it for notifications, thus creating a dependency that violates the <a href="https://metapatterns.io/basic-metapatterns/layers/#dependencies">normal order for a <em>layered system</em></a>. Finally, <em>outgoing requests</em> bypass the <em>Cell Gateway</em> whose role is limited to the <em>Cell’</em>s API.</blockquote><p><em>Cells</em> facilitate recursive decomposition by subdomain. They are the building blocks for the following patterns:</p><ul><li><a href="https://metapatterns.io/fragmented-metapatterns/hierarchy/#in-depth-hierarchy-cell-based-microservice-architecture-wso2-version-segmented-microservice-architecture-services-of-services-clusters-of-services"><em>Cell-Based Architecture</em></a> which is <a href="https://metapatterns.io/fragmented-metapatterns/hierarchy/"><em>hierarchical</em></a> <a href="https://metapatterns.io/basic-metapatterns/services/"><em>Services</em></a>.</li><li><a href="https://metapatterns.io/fragmented-metapatterns/service-oriented-architecture--soa-/#domain-oriented-microservice-architecture-doma"><em>Domain-Oriented Microservice Architecture</em></a> which is a <a href="https://metapatterns.io/fragmented-metapatterns/service-oriented-architecture--soa-/"><em>SOA</em></a> boosted by advanced <em>Cell</em> features.</li></ul><h3>Basic Cell, Cluster</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-MCIYuuMyWCitseKFuX-Cw.png" /></figure><p>A <a href="https://github.com/wso2/reference-architecture/blob/master/reference-architecture-cell-based.md"><em>Cell</em></a> (WSO2 definition) or <em>Cluster</em> [DEDS] may naturally emerge when a <a href="https://metapatterns.io/basic-metapatterns/services/#whole-subdomain-sub-domain-services"><em>subdomain service</em></a> becomes too large for comfortable development, which usually means that at least its <a href="https://metapatterns.io/basic-metapatterns/layers/#domain-business-rules-or-model"><em>domain</em> layer</a> (already limited to a single subdomain) is to be subdivided into subsubdomain components. If other layers remain intact, this leads to a <a href="https://medium.com/itnext/sandwich-architecture-3d0de71503f6"><em>Sandwich</em></a>, otherwise the result is a subsystem of <a href="https://metapatterns.io/basic-metapatterns/services/"><em>Services</em></a> or a <a href="https://metapatterns.io/basic-metapatterns/pipeline/"><em>Pipeline</em></a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*qinF_1h1JJkPwVh2eUaHrw.png" /></figure><p>As it is undesirable to let the new components appear at the top system level because that would increase the system’s integration complexity:</p><ul><li>The newly created subservices are hidden behind a <a href="https://metapatterns.io/extension-metapatterns/proxy/#adapter-anticorruption-layer-abstraction-layer-open-host-service-gateway-message-translator-api-service-cell-gateway-inexact-backend-for-frontend-database-access-layer-data-mapper-repository"><em>Cell Gateway</em></a> (which coincides with the topmost layer in case of a <a href="https://medium.com/itnext/sandwich-architecture-3d0de71503f6"><em>Sandwich</em></a>) so that everything outside of the <em>Cell</em> remains ignorant of what is within it, and the <em>Cell</em> contents will thus retain the freedom to change.</li><li>Everything within a <em>Cell</em> is deployed and scaled together to avoid the overhead of versioning and keep the number of system components small (the entire <em>Cell</em> is operated as a single service).</li><li><a href="https://learn.microsoft.com/en-us/azure/architecture/patterns/choreography">As a rule</a> [DEDS], the communication inside a <em>Cell</em> remains synchronous, allowing for complex <a href="https://metapatterns.io/foundations-of-software-architecture/arranging-communication/orchestration/"><em>orchestrated</em></a> use cases that involve many tightly coupled <em>Cell</em> components. Contrariwise, there is usually asynchronous messaging between loosely coupled <em>Cells</em>, which make a <a href="https://metapatterns.io/foundations-of-software-architecture/arranging-communication/choreography/"><em>choreographed</em></a> system.</li></ul><p>As a matter of fact, forming a <em>Cell</em> tackles the complexity of an overgrown service without leaking any implementation details to its clients or committing to irrevocable architectural decisions. We will be able to make gradual changes to our <em>Cell</em>’s code and structure as our clients see only the <em>Published Language</em> [DDD] of our <em>Cell</em>’s API via its <em>Cell Gateway</em>, which thus becomes an <a href="https://metapatterns.io/extension-metapatterns/proxy/#adapter-anticorruption-layer-abstraction-layer-open-host-service-gateway-message-translator-api-service-cell-gateway-inexact-backend-for-frontend-database-access-layer-data-mapper-repository"><em>Open Host Service</em></a> [DDD].</p><p>Another way a <em>Cell</em> can arise is when architects have overcommitted themselves to <a href="https://metapatterns.io/basic-metapatterns/services/#part-of-a-subdomain-microservices"><em>Microservices</em></a>, gradually <a href="https://www.uber.com/en-UA/blog/microservice-architecture/">introducing hundreds of them</a> and turning their project into a <a href="https://www.reddit.com/r/programming/comments/10xvltx/microservice_hell/"><em>Microservice Hell</em></a>. Now they need to group their services to:</p><ul><li>Have a clear high-level picture of what is going on in the system.</li><li>Cut accidental dependencies between their services and the teams behind them.</li><li>Improve latency by co-locating the services that interact intensely.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*1xbocfqb1l3oF68CQw1B0Q.png" /></figure><p>Basic <em>Cells</em> have a downside: even though we have protected our clients from changes in our implementation, our code is still vulnerable to changes in any external services which it uses. To fix that, we will need to add a layer of indirection for outgoing communication as well:</p><h3>Full-Featured Cell, Domain</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-4X8GalyU5TYsi0BECA8sw.png" /></figure><p>Regardless of how a <a href="https://github.com/wso2/reference-architecture/blob/master/reference-architecture-cell-based.md"><em>Cell</em></a> emerges, the isolation of its contents can be improved through the addition of <a href="https://metapatterns.io/extension-metapatterns/proxy/#adapter-anticorruption-layer-abstraction-layer-open-host-service-gateway-message-translator-api-service-cell-gateway-inexact-backend-for-frontend-database-access-layer-data-mapper-repository"><em>Adapters</em></a> [GoF, DDS] for any external services used by the <em>Cell</em>. Please note that, unlike in<em> </em><a href="https://metapatterns.io/implementation-metapatterns/hexagonal-architecture/#hexagonal-architecture-ports-and-adapters"><em>Ports and Adapters</em></a>, there is no <em>Adapter</em> for a Cell’s database(s) as it is inside the <em>Cell</em>’s perimeter.</p><p>Another improvement, popularized by Uber’s <a href="https://www.uber.com/en-UA/blog/microservice-architecture/"><em>Domains</em></a>, is the use of <a href="https://metapatterns.io/extension-metapatterns/proxy/#on-the-client-side-ambassador"><em>Ambassador</em></a> [DDS] <a href="https://metapatterns.io/implementation-metapatterns/plugins/"><em>Plugins</em></a> [FSA, PEAA] which run other services’ business logic inside your <em>Cell</em>. That both avoids slow intercell calls and boosts the system’s fault tolerance as each <em>Cell</em> can now operate independently.</p><blockquote>In Uber the service responsible for a driver’s status accepts <em>Plugins</em> from other services, such as safety checks or compliance, which can block the driver from appearing in the system and responding to ride requests.</blockquote><p>The <em>Adapters</em> and <em>Plugins</em> make the Cell’s <a href="https://metapatterns.io/extension-metapatterns/proxy/#adapter-anticorruption-layer-abstraction-layer-open-host-service-gateway-message-translator-api-service-cell-gateway-inexact-backend-for-frontend-database-access-layer-data-mapper-repository"><em>Anticorruption Layer</em></a> [DDD], completing the <em>Cell</em>’s boundary that allows for the <em>Cell</em>’s logic to be implemented and tested in isolation from the external environment.</p><h3>Summary</h3><p><em>Cell</em> applies the principles of <a href="https://metapatterns.io/implementation-metapatterns/hexagonal-architecture/"><em>Hexagonal Architecture</em></a> to a distributed subsystem. It allows for recursive decomposition of software into subsubdomain components while preserving the high-level system complexity at a moderate level.</p><h3>References</h3><p><strong>DDD</strong> — Domain-Driven Design: Tackling Complexity in the Heart of Software. <em>Eric Evans. Addison-Wesley (2003).</em></p><p><strong>DDS</strong> — Designing Distributed Systems: Patterns and Paradigms for Scalable, Reliable Services. <em>Brendan Burns. O’Reilly Media, Inc. (2018).</em></p><p><strong>DEDS</strong><em> — </em>Designing Event-Driven Systems: Concepts and Patterns for Streaming Services with Apache Kafka. <em>Ben Stopford. O’Reilly Media, Inc. (2018).</em></p><p><strong>FSA</strong> — Fundamentals of Software Architecture: An Engineering Approach. <em>Mark Richards and Neal Ford. O’Reilly Media, Inc. (2020).</em></p><p><strong>GoF</strong> — Design Patterns: Elements of Reusable Object-Oriented Software. <em>Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. Addison-Wesley (1994).</em></p><p><strong>PEAA</strong> — Patterns of Enterprise Application Architecture. <em>Martin Fowler. Addison-Wesley Professional (2002).</em></p><blockquote>This is an early version of a section from my book <a href="https://leanpub.com/metapatterns"><em>Architectural Metapatterns</em></a>. It will appear in the upcoming version 1.2 which is to be released in about a month. Meanwhile, feel free to check the version 1.1 which is available <a href="https://metapatterns.io/">online</a> and <a href="https://github.com/denyspoltorak/metapatterns?tab=readme-ov-file">on GitHub</a>.</blockquote><blockquote><strong>Editor: Lars Noodén</strong></blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=777e87543e93" width="1" height="1" alt=""><hr><p><a href="https://itnext.io/cell-777e87543e93">Cell</a> was originally published in <a href="https://itnext.io">ITNEXT</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Sandwich Architecture]]></title>
            <link>https://itnext.io/sandwich-architecture-3d0de71503f6?source=rss-7d4e79c3c009------2</link>
            <guid isPermaLink="false">https://medium.com/p/3d0de71503f6</guid>
            <category><![CDATA[system-architecture]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[design-patterns]]></category>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[metapatterns]]></category>
            <dc:creator><![CDATA[Denys Poltorak]]></dc:creator>
            <pubDate>Wed, 18 Feb 2026 23:18:41 GMT</pubDate>
            <atom:updated>2026-02-18T23:18:41.606Z</atom:updated>
            <cc:license>http://creativecommons.org/licenses/by/4.0/</cc:license>
            <content:encoded><![CDATA[<h4>A system topology</h4><blockquote>This is an early version of a chapter from my book <a href="https://leanpub.com/metapatterns"><em>Architectural Metapatterns</em></a>. It will appear in the upcoming version 1.2 of the book which is to be released in about a month. Meanwhile, feel free to check the version 1.1 which is available <a href="https://metapatterns.io/">online</a> and <a href="https://github.com/denyspoltorak/metapatterns?tab=readme-ov-file">on GitHub</a>.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zV44CdGzJk6AkzqMWUbMBQ.png" /></figure><p><em>Follow the line of least resistance. </em>Divide where it is loosely coupled.</p><p><strong>Examples</strong>:</p><ul><li><a href="https://en.wikipedia.org/wiki/Blackboard_system">Blackboard System</a> [POSA1, POSA4],</li><li>Space-Based Architecture (SBA) [SAP, FSA],</li><li>Service-Based Architecture (SBA) [SAP],</li><li><a href="https://martinfowler.com/bliki/CQRS.html">Command Query Responsibility Segregation</a> (CQRS),</li><li>(inexact) Replicated Load-Balanced Services [DDS] / <a href="https://jesseduffield.com/Notes-On-Lambda/">Lambdas</a>.</li></ul><p><strong>Structure</strong>: A layer of domain-level services between shared integration and data layers.</p><p><strong>Type</strong>: Main, implementation.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*crbECFNxLGbd0Xdmax6Img.png" /></figure><p><strong>References</strong>: None I know of.</p><p>A <em>Sandwich</em> is a (sub)system in transition between <a href="https://metapatterns.io/basic-metapatterns/layers/"><em>Layers</em></a> and <a href="https://metapatterns.io/basic-metapatterns/services/"><em>Services</em></a>. It emerges when a <em>layered</em> component outgrows its architecture and its middle (<a href="https://metapatterns.io/basic-metapatterns/layers/#domain-business-rules-or-model"><em>domain</em></a> [DDD]) layer — which tends to be both the largest and least cohesive — is divided into subdomains while the <a href="https://metapatterns.io/basic-metapatterns/layers/#application-use-cases-or-integration"><em>application</em></a> and <a href="https://metapatterns.io/basic-metapatterns/layers/#data-persistence"><em>data</em></a> layers remain intact. Another, less common, origin is a (sub)system of <em>(Micro)Services</em> which becomes so tightly coupled that it needs to be partially merged.</p><p>A <em>Sandwich</em> includes the following components:</p><ul><li>A shared <a href="https://metapatterns.io/basic-metapatterns/layers/#application-use-cases-or-integration"><em>integration layer</em></a> which receives client requests and dispatches them to the underlying <em>domain-level services</em>. Though this layer may either implement use cases as an <a href="https://metapatterns.io/extension-metapatterns/orchestrator/"><em>Orchestrator</em></a> or just forward each client action to a matching service as a <a href="https://metapatterns.io/extension-metapatterns/proxy/"><em>Proxy</em></a>, it remains the component that ties the entire system together.</li><li><a href="https://metapatterns.io/basic-metapatterns/layers/#domain-business-rules-or-model"><em>Domain-level</em></a><em> </em><a href="https://metapatterns.io/basic-metapatterns/services/#distributed-services-service-based-architecture-space-based-architecture-microservices"><em>services</em></a> (if distributed) or <a href="https://metapatterns.io/basic-metapatterns/services/#synchronous-modules-modular-monolith-modulith"><em>modules</em></a> (otherwise) that implement the bulk of the system’s business logic and thus contain most of the system’s code.</li><li>A shared <a href="https://metapatterns.io/basic-metapatterns/layers/#data-persistence"><em>data layer</em></a> which the upper layer’s services operate on. It may be a database (provide persistence) or an in-memory application state.</li></ul><p><em>Sandwiches</em> often occur naturally without being recognized as a distinct architecture. In fact, I had to make up a name for this system topology.</p><h3>Performance</h3><p>As <a href="https://metapatterns.io/basic-metapatterns/layers/#domain-business-rules-or-model"><em>domain</em>-level</a> services rarely interact among themselves, the performance of a <em>Sandwich</em> is similar to <a href="https://metapatterns.io/basic-metapatterns/layers/#performance">that of <em>Layers</em></a> with the same kind of deployment (components of a <em>Sandwich</em> may or may not be colocated).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Xlrxnt3wgm-RDE1Dwz5wyA.png" /></figure><h3>Dependencies</h3><p>The <em>Sandwich</em>’s <em>integration</em> layer depends on every service inside the <em>Sandwich</em>. The services themselves depend on the <em>data</em> layer.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*GXyAIlSafg_aTOtCejy1vg.png" /></figure><p>Having two shared layers provides three options for invoking the <em>domain</em> components:</p><ul><li>The most common approach is <a href="https://metapatterns.io/foundations-of-software-architecture/arranging-communication/orchestration/"><em>orchestration</em></a> by the integration layer.</li><li>Data-centric domains may rely on <a href="https://metapatterns.io/foundations-of-software-architecture/arranging-communication/shared-data/#full-featured"><em>data change notifications</em></a>.</li><li><a href="https://metapatterns.io/foundations-of-software-architecture/arranging-communication/choreography/"><em>Choreography</em></a> via publish/subscribe is rare because it is inferior to the other two options:</li><li>- It does not help to decouple the subdomain services which remain bound together by the shared layers.</li><li><em>- Publish/subscribe</em> requires additional libraries and setup, while the datastore, which often supports notifications, is already in place.</li><li>- Furthermore, <em>orchestration</em> <a href="https://metapatterns.io/foundations-of-software-architecture/arranging-communication/comparison-of-communication-styles/">allows for much better control</a> over use case logic and error handling than <em>choreography</em>.</li></ul><h3>Applicability</h3><p><em>Sandwich</em> <strong>fits</strong>:</p><ul><li><em>Medium-sized projects with complex domain logic.</em> The subdivision of the <em>domain</em> layer keeps the code complexity under control and supports development by multiple teams with little increase of operational burden.</li><li><em>Rapid development of ordinary systems.</em> If you don’t face any challenging forces, you should keep your architecture <a href="https://en.wikipedia.org/wiki/KISS_principle">simple and stupid</a> but still flexible — which is the pragmatic <em>Sandwich</em>. You will be able to evolve it in the future if needed.</li><li><em>Data-centric domains.</em> This architecture allows all the services to work on the same dataset, each reading and writing the parts that are involved in its business logic.</li></ul><p><em>Sandwich</em> <strong>does not help</strong>:</p><ul><li><em>Projects with a large number of use cases.</em> As the <em>integration</em> layer remains monolithic, it still can grow out of control, requiring the system to transform into <a href="https://metapatterns.io/fragmented-metapatterns/layered-services/"><em>Layered Services</em></a>.</li><li><em>Huge systems.</em> Both the <em>integration</em> and <em>data</em> layers are cumbersome in that case.</li><li><em>Demanding forces.</em> The <em>Sandwich</em> architecture is a jack of all trades, master of none. In general, it is an average backend, and is neither highly elastic, flexible, nor low latency.</li></ul><h3>Relations</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*1xhbt4Jjl7kjjRf2a6FBAg.png" /></figure><p><em>Sandwich</em>:</p><ul><li>Is a system in transition between <a href="https://metapatterns.io/basic-metapatterns/layers/"><em>Layers</em></a> and <a href="https://metapatterns.io/basic-metapatterns/services/"><em>Services</em></a>.</li><li>Is <em>Layers</em> with a middle layer split into services or <em>Services</em> sandwiched between layers.</li><li>May implement a <a href="https://metapatterns.io/basic-metapatterns/monolith/"><em>Monolith</em></a> or <em>Service</em>.</li><li>Often provides the internals of a <a href="https://metapatterns.io/basic-metapatterns/services/#cell-wso2-definition-service-of-services-domain-uber-definition-cluster"><em>Cell</em></a>.</li><li>Includes a <a href="https://metapatterns.io/extension-metapatterns/shared-repository/"><em>Shared Repository</em></a> and an <a href="https://metapatterns.io/extension-metapatterns/orchestrator/"><em>Orchestrator</em></a> and/or <a href="https://metapatterns.io/extension-metapatterns/proxy/"><em>Proxy</em></a>.</li></ul><blockquote>A <em>Cell</em> encapsulates several services so that they can be treated as a single entity with the goal of reducing the number of top-level system components. Typically, interdependent and closely communicating services are clustered into a single <em>Cell</em>, predisposing the <em>Cell</em>’s internals for further merging to reduce the communication overhead and the amount of boilerplate code. Such a scenario often results in a <em>Sandwich</em> trapped inside a <em>Cell</em>.</blockquote><h3>Examples</h3><p>Though most real-world <em>Sandwiches</em> stay beneath the radar as non-standard architectures, there are two well-documented and highly specialized occurrences of this topology in data-centric domains and a few less stringent generic cases:</p><h4><a href="https://metapatterns.io/extension-metapatterns/shared-repository/#blackboard">Blackboard System</a></h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*KKUOzZpWzb8ZG_Rc5-YVuw.png" /></figure><p>Some domains are <a href="http://i.stanford.edu/pub/cstr/reports/cs/tr/86/1123/CS-TR-86-1123.pdf">complex and ill-structured</a>: there is only a vague understanding of how the inputs relate to outputs, therefore you cannot write a single algorithm to solve it. If you are lucky to have a huge labeled dataset, you can attempt training a neural network. If there are not so many examples, you are in trouble.</p><p><a href="https://en.wikipedia.org/wiki/Blackboard_system"><em>Blackboard Systems</em></a> [POSA1, POSA4] were invented half a century ago to tackle non-deterministic problems: speech or image recognition, X-ray crystallography of proteins, or even tracking enemy submarines or stealth aircraft. In these cases inputs are noisy and scarce and outputs can vary indefinitely, therefore one must go through trial and error proposing, refining, and comparing many possible solutions to arrive at something plausible.</p><p>The system consists of:</p><ul><li>A <a href="https://metapatterns.io/extension-metapatterns/shared-repository/#blackboard"><em>blackboard</em></a> — a <a href="https://metapatterns.io/extension-metapatterns/shared-repository/"><em>shared data store</em></a> that contains all the current knowledge about the problem, namely inputs and hypotheses. It is subdivided into abstraction levels which range from the original inputs through multiple intermediate representations to the output data structure. Each level usually contains multiple solution attempts.</li><li><em>Knowledge sources</em> — independent, specialized components that process data from a lower level to create a higher-level hypothesis. For example, in voice recognition, a knowledge source may read a sound wave and write a letter which that wave encodes. Another knowledge source may read letters and output English words, while another one tries to find French words. And the final one collects words into sentences.</li><li>A <a href="https://metapatterns.io/extension-metapatterns/orchestrator/"><em>control</em></a> — a <a href="https://metapatterns.io/extension-metapatterns/proxy/#load-balancer-sharding-proxy-cell-router-messaging-grid-scheduler"><em>scheduler</em></a> that assigns processor time to knowledge sources. It balances the quality and speed of the solution attempts based on the current progress and remaining time.</li></ul><p>This architecture makes best use of every system layer:</p><ul><li>The <em>control</em> is required to prune the exponential growth of possible solutions because there are not enough system resources to check all of them.</li><li>The independent <em>knowledge sources</em> are easy to add or remove, allowing the developers to try various algorithms with no changes to other components.</li><li>The <em>blackboard</em> enables the cooperation of knowledge sources, each of which is limited to a small part of the overall solution.</li></ul><h4><a href="https://metapatterns.io/implementation-metapatterns/mesh/#space-based-architecture">Space-Based Architecture</a> (SBA)</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bhE9awxT4wwJK3KGceJtqA.png" /></figure><p><em>Space-Based Architecture</em> (<em>SBA</em>) [SAP, FSA] is an extremely elastic alternative to <a href="https://metapatterns.io/basic-metapatterns/services/#microservices"><em>Microservices</em></a> which works for data-centric domains. Each <em>processing unit</em> — a domain-level service — is co-located with an in-memory replica of the entire system’s data, which makes both data access and creation of new instances of <em>processing units</em> blazingly fast. As is common for <em>Sandwiches</em>, <em>processing units</em> can be <a href="https://metapatterns.io/foundations-of-software-architecture/arranging-communication/orchestration/"><em>orchestrated</em></a> by the <em>processing grid</em> or they can <a href="https://metapatterns.io/foundations-of-software-architecture/arranging-communication/shared-data/#full-featured"><em>subscribe to changes</em></a> in the shared <a href="https://metapatterns.io/extension-metapatterns/shared-repository/#data-grid-of-space-based-architecture-sba-replicated-cache-distributed-cache"><em>data grid</em></a>, this architecture being flexible enough to allow for choosing a <a href="https://metapatterns.io/foundations-of-software-architecture/arranging-communication/">communication paradigm</a> on per request basis.</p><p>Aside from <em>processing units</em>, which contain the main business logic, <em>SBA</em> involves:</p><ul><li>A <em>messaging grid</em> which is a <a href="https://metapatterns.io/extension-metapatterns/proxy/"><em>Proxy</em></a> (combination of <a href="https://metapatterns.io/extension-metapatterns/proxy/#adapter-anticorruption-layer-abstraction-layer-open-host-service-gateway-message-translator-api-service-cell-gateway-inexact-backend-for-frontend-database-access-layer-data-mapper-repository"><em>Gateway</em></a>, <a href="https://metapatterns.io/extension-metapatterns/proxy/#dispatcher-reverse-proxy-ingress-controller-edge-service-microgateway"><em>Dispatcher</em></a>, and <a href="https://metapatterns.io/extension-metapatterns/proxy/#load-balancer-sharding-proxy-cell-router-messaging-grid-scheduler"><em>Load Balancer</em></a>) that receives, preprocesses, and persists client requests. Simple requests are forwarded to the least loaded <em>processing unit</em> (service with domain logic) while anything complicated goes to the <em>processing grid</em>.</li><li>A <em>processing grid</em> is an optional <a href="https://metapatterns.io/extension-metapatterns/orchestrator/"><em>Orchestrator</em></a> which manages multi-step workflows for complicated requests that involve branching and error handling.</li><li>A <a href="https://metapatterns.io/extension-metapatterns/shared-repository/#data-grid-of-space-based-architecture-sba-replicated-cache-distributed-cache"><em>data grid</em></a> is a distributed in-memory database. It is built of caching <em>Mesh</em> nodes which are co-located with instances of <em>processing units</em>, making database access extremely fast. However, the speed and scalability is paid for with stability — any data in memory is prone to disappearing. Therefore the <em>data grid</em> backs up all the changes to a slower <em>persistent database</em>.</li><li>A <em>deployment manager</em> is a <a href="https://metapatterns.io/extension-metapatterns/middleware/"><em>Middleware</em></a> that creates and destroys instances of <em>processing units</em> (which are paired to the nodes of the <em>data grid</em>), just like <a href="https://metapatterns.io/extension-metapatterns/middleware/#service-mesh"><em>Service Mesh</em></a> does for <a href="https://metapatterns.io/basic-metapatterns/services/#microservices"><em>Microservices</em></a> (which are paired to <a href="https://metapatterns.io/extension-metapatterns/proxy/#on-the-system-side-sidecar"><em>Sidecars</em></a><em> </em>[DDS]). However, in contrast to <em>Service Mesh</em>, it does not provide a messaging infrastructure because <em>processing</em> <em>units</em> communicate by sharing data via the <em>data grid</em>, not by sending messages.</li></ul><p>As <em>SBA</em> runs every component in a <a href="https://metapatterns.io/implementation-metapatterns/mesh/"><em>Mesh</em></a>, it avoids the fault tolerance and database performance drawbacks inherent to <em>Sandwich</em>, trading them for possibility of write conflicts when multiple clients cause changes to the same piece of data simultaneously.</p><h4><a href="https://metapatterns.io/basic-metapatterns/services/#service-based-architecture-sba">Service-Based Architecture</a> (SBA)</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*BidFG4Um1SIvjQy7eg0Tow.png" /></figure><p><em>Service-Based Architecture</em> (<em>SBA</em>) [FSA] is the most pragmatic and loosely defined of topologies based on <a href="https://metapatterns.io/basic-metapatterns/services/"><em>Services</em></a> (hence the name). In its most basic shape, <em>SBA</em>’s <a href="https://metapatterns.io/basic-metapatterns/services/#whole-subdomain-sub-domain-services"><em>subdomain services</em></a> are integrated by a <a href="https://metapatterns.io/extension-metapatterns/proxy/#user-interface-presentation-layer-separated-presentation-command-line-interface-cli-graphical-user-interface-gui-frontend-human-machine-interface-hmi-man-machine-interface-mmi-operator-interface"><em>User Interface</em></a> layer, usually a <em>Frontend</em>, and there is a single <a href="https://metapatterns.io/extension-metapatterns/shared-repository/#shared-database-integration-database-data-domain-database-of-service-based-architecture"><em>Shared Database</em></a>. However, as there are no rules for <em>SBA</em>, multiple databases or finer-grained <em>GUI</em>s may be used for programmers’ convenience, disintegrating the <em>Sandwich</em> architecture for the sake of less coupled <a href="https://metapatterns.io/fragmented-metapatterns/layered-services/"><em>Layered Service</em>s</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*TXOZnB0hhSHs_8ysezjsgg.png" /></figure><h4><a href="https://metapatterns.io/fragmented-metapatterns/layered-services/#command-query-responsibility-segregation-cqrs">Command Query Responsibility Segregation</a> (CQRS)</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*38pK3gs4zLtIIu1M41MgsA.png" /></figure><p><a href="https://martinfowler.com/bliki/CQRS.html"><em>Command Query Responsibility Segregation</em></a> (<em>CQRS</em>) is a principle which calls for separation of components that process <em>commands</em> (requests that change the system’s data) and <em>queries</em> (requests that analyze the data). The subdivision necessarily happens at the <a href="https://metapatterns.io/basic-metapatterns/layers/#domain-business-rules-or-model"><em>domain</em></a> (<em>model</em>) level, resulting in separate <a href="https://learn.microsoft.com/en-us/azure/architecture/patterns/cqrs"><em>Write Model</em></a> (<a href="https://martinfowler.com/bliki/CQRS.html"><em>Command Model</em></a>) and <a href="https://learn.microsoft.com/en-us/azure/architecture/patterns/cqrs"><em>Read Model</em></a> (<a href="https://martinfowler.com/bliki/CQRS.html"><em>Query Model</em></a>, <a href="https://cqrs.wordpress.com/wp-content/uploads/2010/11/cqrs_documents.pdf"><em>Thin Read Layer</em></a>).</p><p>In the simplest case the <a href="https://metapatterns.io/basic-metapatterns/layers/#data-persistence"><em>data</em> layer</a> is kept monolithic, as shown in the diagram above. That helps decouple the logic-heavy object-oriented code which maintains data consistency and business constraints during editing from the search and aggregation code that needs direct database access to run complex SQL queries. If that is not enough, it is possible to trade complexity for performance by employing specialized databases: <a href="https://en.wikipedia.org/wiki/Online_transaction_processing"><em>OLTP</em></a> for use with the <em>Write Model</em> and <a href="https://en.wikipedia.org/wiki/Online_analytical_processing"><em>OLAP</em></a> for the <em>Read Model</em>, as <a href="https://metapatterns.io/fragmented-metapatterns/layered-services/#command-query-responsibility-segregation-cqrs">described in <em>Layered Services</em></a>:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*c-R6zO4mlhlgYYaZ9a4AIw.png" /></figure><h4>(inexact) <a href="https://metapatterns.io/basic-metapatterns/shards/#stateless-pool-instances-replicated-stateless-services-work-queue-lambdas">Replicated Load-Balanced Services, Lambdas</a></h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*wqY31zbi2408Y-RKUIynmg.png" /></figure><p>Replicating a system’s <a href="https://metapatterns.io/basic-metapatterns/layers/#domain-business-rules-or-model"><em>domain</em></a> <a href="https://metapatterns.io/basic-metapatterns/layers/#three-tier-architecture"><em>tier</em></a> along the <a href="https://metapatterns.io/introduction/metapatterns/#the-system-of-coordinates"><em>sharding</em> axis</a> also results in a <em>Sandwich</em>-like topology, albeit with altered properties: while the original <em>Sandwich</em>’s subdivision of the codebase along the <a href="https://metapatterns.io/introduction/metapatterns/#the-system-of-coordinates"><em>subdomain</em> axis</a> allows for multiteam development and easy integration of new functionality, replication along the <a href="https://metapatterns.io/introduction/metapatterns/#the-system-of-coordinates"><em>sharding</em> axis</a> only makes it simple to add or remove instances of the middle tier as the system load changes.</p><p><em>Replicated Load-Balanced Services</em> [DDS] is the general name for running multiple instances of a stateless service that <a href="https://metapatterns.io/extension-metapatterns/shared-repository/#shared-database-integration-database-data-domain-database-of-service-based-architecture"><em>share a database</em></a> and run under a <a href="https://metapatterns.io/extension-metapatterns/proxy/#load-balancer-sharding-proxy-cell-router-messaging-grid-scheduler"><em>Load Balancer</em></a>. <a href="https://jesseduffield.com/Notes-On-Lambda/"><em>Lambdas</em></a> is a synonym for a similar setup from cloud computing providers.</p><h3>Evolutions</h3><p>The components of a <em>Sandwich</em> provide plenty of ways to alter the system:</p><h4>Primary evolutions</h4><p>Some evolutions involve the system’s domain logic or its topology:</p><ul><li>The <em>domain-level services</em> are independent enough to be easily added or removed.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4du-aY4RhvDhyG9zE0-lnQ.png" /></figure><ul><li>In most cases they share technologies, allowing for splitting or merging of the services.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*JsT5nbNcbXMDJf1LL_o9Zg.png" /></figure><ul><li>If the services are found to be strongly coupled, they can be merged into a monolithic layer, likely to be subdivided in a better way later on.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4AjjjVrtvOtpGZzsMa9_hA.png" /></figure><ul><li>Alternatively, the subdomains can be further decoupled.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*1YLYgXCBWygDMm4uVu4DiA.png" /></figure><h4>Evolutions of the data layer</h4><p>If the <em>data </em>layer becomes a performance bottleneck, it can be <a href="https://metapatterns.io/extension-metapatterns/shared-repository/#evolutions">split as a <em>Shared Repository</em></a>:</p><ul><li><a href="https://metapatterns.io/basic-metapatterns/shards/#persistent-slice-sharding-shards-partitions-multitenancy-cells-amazon-definition"><em>Shard</em></a> the database if its records are mutually independent or <a href="https://metapatterns.io/basic-metapatterns/shards/#persistent-copy-replica"><em>replicate</em></a> it if it is the read traffic which overloads the system.</li><li>Apply <a href="https://metapatterns.io/extension-metapatterns/shared-repository/#data-grid-of-space-based-architecture-sba-replicated-cache-distributed-cache"><em>Space-Based Architecture</em></a> if elasticity is more important than consistency.</li><li>Divide the data into databases, private to domain-level services, transforming the system into <a href="https://metapatterns.io/extension-metapatterns/orchestrator/"><em>Orchestrated Services</em></a>.</li><li>Deploy specialized databases (<a href="https://metapatterns.io/fragmented-metapatterns/polyglot-persistence/"><em>Polyglot Persistence</em></a>).</li></ul><h4>Evolutions of the application layer</h4><p>If the <em>integration </em>layer contains use cases and becomes cumbersome, it should be subdivided following the <a href="https://metapatterns.io/extension-metapatterns/orchestrator/#evolutions">evolutions of <em>Orchestrator</em></a>:</p><ul><li>Into <a href="https://metapatterns.io/fragmented-metapatterns/layered-services/#orchestrated-three-layered-services"><em>Services</em></a> if the use cases cluster around subdomains.</li><li>Into <a href="https://metapatterns.io/extension-metapatterns/orchestrator/#a-service-per-client-type-backends-for-frontends"><em>Backends for Frontends</em></a> if the system serves several kinds of clients.</li><li>Into <a href="https://metapatterns.io/extension-metapatterns/orchestrator/#layered"><em>Layers</em></a> if some use cases are simple while others are complicated.</li><li>Into a <a href="https://metapatterns.io/extension-metapatterns/orchestrator/#a-service-per-subdomain-hierarchy"><em>Hierarchy</em></a> if the use cases include both generic and specialized logic.</li></ul><h3>Summary</h3><p><em>Sandwich</em> is a pragmatic architecture midway between <a href="https://metapatterns.io/basic-metapatterns/layers/"><em>Layers</em></a> and <a href="https://metapatterns.io/basic-metapatterns/services/"><em>Services</em></a>. It combines simplicity and flexibility, avoiding unnecessary effort for the present while retaining many paths to evolve in the future.</p><h3>References</h3><p><strong>DDD</strong> — Domain-Driven Design: Tackling Complexity in the Heart of Software. <em>Eric Evans. Addison-Wesley (2003).</em></p><p><strong>DDS</strong> — Designing Distributed Systems: Patterns and Paradigms for Scalable, Reliable Services. <em>Brendan Burns. O’Reilly Media, Inc. (2018).</em></p><p><strong>FSA</strong> — Fundamentals of Software Architecture: An Engineering Approach. <em>Mark Richards and Neal Ford. O’Reilly Media, Inc. (2020).</em></p><p><strong>POSA1</strong> — Pattern-Oriented Software Architecture Volume 1: A System of Patterns. <em>Frank Buschmann, Regine Meunier, Hans Rohnert, Peter Sommerlad and Michael Stal. John Wiley &amp; Sons, Inc. (1996).</em></p><p><strong>POSA4</strong> — Pattern-Oriented Software Architecture Volume 4: A Pattern Language for Distributed Computing. <em>Frank Buschmann, Kevlin Henney, Douglas C. Schmidt. John Wiley &amp; Sons, Ltd. (2007).</em></p><p><strong>SAP</strong> — Software Architecture Patterns. <em>Mark Richards. O’Reilly Media, Inc. (2015).</em> (All of the architectures referenced here are in [FSA] as well, but [SAP] is free)</p><blockquote>Editor: Lars Noodén</blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3d0de71503f6" width="1" height="1" alt=""><hr><p><a href="https://itnext.io/sandwich-architecture-3d0de71503f6">Sandwich Architecture</a> was originally published in <a href="https://itnext.io">ITNEXT</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Presentations for Architectural Metapatterns]]></title>
            <link>https://denyspoltorak.medium.com/presentations-for-architectural-metapatterns-cd42923292b4?source=rss-7d4e79c3c009------2</link>
            <guid isPermaLink="false">https://medium.com/p/cd42923292b4</guid>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[system-architecture]]></category>
            <category><![CDATA[design-patterns]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[metapatterns]]></category>
            <dc:creator><![CDATA[Denys Poltorak]]></dc:creator>
            <pubDate>Wed, 24 Dec 2025 18:45:34 GMT</pubDate>
            <atom:updated>2025-12-24T18:45:34.952Z</atom:updated>
            <cc:license>https://creativecommons.org/licenses/by-nc-sa/4.0/</cc:license>
            <content:encoded><![CDATA[<p>Here are <a href="https://speakerdeck.com/denyspoltorak">presentations</a> that summarize the main content of my book <a href="https://leanpub.com/metapatterns"><em>Architectural Metapatterns</em></a> (which is, surprisingly, an overview of architectural patterns):</p><h4><a href="https://speakerdeck.com/denyspoltorak/patterns-of-patterns-c322149c-fcdd-4df6-8c6c-f273c7ab17dd"><strong>Patterns of Patterns</strong></a>, and why we need them:</h4><ul><li>The misery of having thousands of patterns.</li><li>Local and distributed architectures are not dissimilar.</li><li>Structure determines function.</li><li>There are only so many elementary geometries.</li><li>Which means that hundreds of patterns condense into several metapatterns.</li></ul><h4><a href="https://speakerdeck.com/denyspoltorak/basic-architectures"><strong>Basic Architectures</strong></a>, the building blocks for complex systems:</h4><ul><li><em>Monolith</em> — a cohesive codebase.</li><li><em>Shards</em> — multiple instances of a (sub)system.</li><li><em>Layers</em> — subdivision by the level of abstractness.</li><li><em>Services</em> — components, dedicated to subdomains.</li><li><em>Pipeline</em> — a chain of data processing steps.</li></ul><p>… and common variants of each of the architectures.</p><h4><a href="https://speakerdeck.com/denyspoltorak/architectural-extensions-c3e506c0-6472-4e2c-8113-b3d8ffa20d63"><strong>Architectural Extensions</strong></a>. Making use of specialized components:</h4><ul><li><em>Middleware</em> — communication and deployment.</li><li><em>Shared Repository</em> — persistence and synchronization.</li><li><em>Proxy</em> — protocols, routing, and security.</li><li><em>Orchestrator</em> — integration and use cases.</li><li><em>Combined Component</em> — multiple aspects.</li></ul><h4><a href="https://speakerdeck.com/denyspoltorak/fragmented-architectures-bf4d129f-4cd1-46bf-9fb0-248879872b25"><strong>Fragmented Architectures</strong></a>. Patterns with smaller components:</h4><ul><li><em>Layered Services</em> — divide into services, then into layers.</li><li><em>Polyglot Persistence</em> — employ multiple databases.</li><li><em>Backends for Frontends</em> (<em>BFF</em>) — dedicate a service to each kind of client.</li><li><em>Service-Oriented Architecture</em> (<em>SOA</em>) — divide into layers, then into services.</li><li><em>Hierarchy</em> — recursive subdivision.</li></ul><h4><a href="https://speakerdeck.com/denyspoltorak/implementation-patterns"><strong>Implementation Patterns</strong></a>. The high-level design of system components:</h4><ul><li><em>Plugins</em> customize the component’s behavior.</li><li><em>Hexagonal Architecture</em> isolates the business logic from external dependencies.</li><li><em>Microkernel</em> mediates between resource providers and resource consumers.</li><li><em>Mesh</em> maintains a decentralized system.</li></ul><p>I hope that the presentations will help you quickly find out if you are interested in the book.</p><p>Merry Christmas!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=cd42923292b4" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Patterns of Patterns]]></title>
            <link>https://denyspoltorak.medium.com/patterns-of-patterns-dc7ef7507427?source=rss-7d4e79c3c009------2</link>
            <guid isPermaLink="false">https://medium.com/p/dc7ef7507427</guid>
            <category><![CDATA[system-architecture]]></category>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[design-patterns]]></category>
            <category><![CDATA[metapatterns]]></category>
            <dc:creator><![CDATA[Denys Poltorak]]></dc:creator>
            <pubDate>Fri, 07 Nov 2025 19:30:40 GMT</pubDate>
            <atom:updated>2025-12-24T17:29:12.925Z</atom:updated>
            <cc:license>https://creativecommons.org/licenses/by-nc/4.0/</cc:license>
            <content:encoded><![CDATA[<h4>And why we need them</h4><p><a href="https://speakerdeck.com/denyspoltorak/patterns-of-patterns-c322149c-fcdd-4df6-8c6c-f273c7ab17dd">Here is a brief presentation</a> of the main ideas from my book <a href="https://leanpub.com/metapatterns">Architectural Metapatterns</a>:</p><ul><li>The misery of having thousands of patterns.</li><li>Local and distributed architectures are not dissimilar.</li><li>Structure determines function.</li><li>There are only so many elementary geometries.</li><li>Which means that hundreds of patterns condense into several metapatterns.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*pETf571ZmGvFSs5I8OIh1Q.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=dc7ef7507427" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Metapatterns website is ready]]></title>
            <link>https://denyspoltorak.medium.com/the-metepatterns-website-is-ready-5509c4b2d088?source=rss-7d4e79c3c009------2</link>
            <guid isPermaLink="false">https://medium.com/p/5509c4b2d088</guid>
            <category><![CDATA[design-patterns]]></category>
            <category><![CDATA[system-architecture]]></category>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[software-engineering]]></category>
            <dc:creator><![CDATA[Denys Poltorak]]></dc:creator>
            <pubDate>Fri, 24 Oct 2025 14:47:47 GMT</pubDate>
            <atom:updated>2025-10-25T16:30:09.044Z</atom:updated>
            <cc:license>http://creativecommons.org/licenses/by/4.0/</cc:license>
            <content:encoded><![CDATA[<p>I finished turning <a href="https://leanpub.com/metapatterns">my book Architectural Metapatterns</a> into a website. It took three months and a <a href="https://github.com/denyspoltorak/odt2wiki">couple of thousand lines of Python code</a>.</p><p>The website shows how patterns of software architecture work together and relate to each other. It’s lightweight, <a href="https://pagespeed.web.dev/analysis/https-metapatterns-io/adyvnt28lb?form_factor=mobile">blazingly fast</a> and modile-friendly. There is a native dark theme:</p><figure><img alt="Screenshot of the website’s main page with thedark theme" src="https://cdn-images-1.medium.com/max/1024/1*Rh2wT2-zByjiXbsj_WrdDA.png" /></figure><p>Each page is dedicated to a basic principle of software architecture or to a cluster of related architectural patterns. It’s an updated version of everything I have published on Medium.</p><p><em>Enjoy!</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5509c4b2d088" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Architectural Patterns Wiki]]></title>
            <link>https://denyspoltorak.medium.com/architectural-patterns-wiki-bb5e87a7a569?source=rss-7d4e79c3c009------2</link>
            <guid isPermaLink="false">https://medium.com/p/bb5e87a7a569</guid>
            <category><![CDATA[system-architecture]]></category>
            <category><![CDATA[design-patterns]]></category>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[architectural-patterns]]></category>
            <category><![CDATA[free-books]]></category>
            <dc:creator><![CDATA[Denys Poltorak]]></dc:creator>
            <pubDate>Sat, 23 Aug 2025 13:55:05 GMT</pubDate>
            <atom:updated>2025-08-23T13:55:05.481Z</atom:updated>
            <cc:license>http://creativecommons.org/licenses/by/4.0/</cc:license>
            <content:encoded><![CDATA[<h4>An online version of the Architectural Metapatterns book</h4><p>The latest version (1.1) of my book <a href="https://leanpub.com/metapatterns">Architectural Metapatterns</a> is now <a href="https://github.com/denyspoltorak/metapatterns/wiki">available online</a>, hosted by GitHub wiki. <a href="https://github.com/denyspoltorak/metapatterns/wiki/Appendix%20I.%20Index%20of%20patterns">Here is the index of patterns</a> it describes.</p><p>The wiki was generated with <a href="https://github.com/denyspoltorak/odt2wiki">odt2wiki</a> — a small utility which converts ODT (LibreOffice/OpenOffice text documents) to the GitHub wiki format, splitting the document into multiple web pages and matching images from the document to files in your local folder.</p><p>Next I am going to try transforming the book into a static web site, likely through <a href="https://hugo-book-demo.netlify.app/docs/example/">Hugo Book</a> or <a href="https://sphinx-book-theme.readthedocs.io/en/stable/index.html">Sphinx Book Theme</a>. Any advice is welcome.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=bb5e87a7a569" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Guide on converting a Google Docs text into an eBook]]></title>
            <link>https://denyspoltorak.medium.com/guide-on-converting-a-google-docs-text-into-an-ebook-5b1abc65f69d?source=rss-7d4e79c3c009------2</link>
            <guid isPermaLink="false">https://medium.com/p/5b1abc65f69d</guid>
            <category><![CDATA[self-publishing]]></category>
            <category><![CDATA[leanpub]]></category>
            <category><![CDATA[guides-and-tutorials]]></category>
            <category><![CDATA[ebook-publishing]]></category>
            <category><![CDATA[calibre]]></category>
            <dc:creator><![CDATA[Denys Poltorak]]></dc:creator>
            <pubDate>Mon, 21 Jul 2025 19:19:02 GMT</pubDate>
            <atom:updated>2025-08-30T14:47:25.520Z</atom:updated>
            <cc:license>https://creativecommons.org/licenses/by-nc-sa/4.0/</cc:license>
            <content:encoded><![CDATA[<h4>Producing well-structured PDF and EPUB files with free software</h4><p>While it is convenient to write a book in Google Docs, transforming it into a high-quality eBook is complicated. Please find below the steps which one should take to make a pair of PDB and EPUB files from a Google Docs document using free software.</p><blockquote>I have Ubuntu 22.04 / MATE 1.26, LibreOffice 7.3.7.2, and Calibre 5.37.</blockquote><h3>Why Google Docs</h3><p>I used Google Docs for writing a <a href="https://github.com/denyspoltorak/publications/releases/tag/v1.1">compendium</a> which contained hundreds of pages, hundreds of diagrams, and thousands of cross-links.</p><h4>Benefits</h4><ul><li>Online collaboration</li><li>Decent UX</li><li>Decent stability (few bugs, no data corruption)</li><li>Performance (Google Docs seems to be faster than LibreOffice Writer)</li><li>Instant backup</li><li>You probably don’t need to learn it</li></ul><h4>Drawbacks</h4><ul><li>Supports only basic editing</li><li>Exporting is basic as well</li><li>No integration with version control systems</li><li>Unavailable offline</li></ul><h4>The troubles you may encounter</h4><ul><li>Google Docs has a hard time saving the table of contents into a PDF (as an outline) or EPUB file. Older versions did not generate it at all, whilst the newer ones may be buggy and provide next to no control over the structure of the table of contents.</li><li>The resulting EPUB is not optimized. It may take too long to open and section breaks may be at the wrong granularity level.</li></ul><h4>Use specialized software</h4><p>It makes sense to rely on specialized tools:</p><ul><li>Google Docs for editing and collaboration</li><li>Calibre for conversion to EPUB</li><li>LibreOffice for conversion to PDF</li></ul><h3>Exporting from Google Docs to LibreOffice Writer</h3><p>Even though Google Docs and LibreOffice Writer are about the same thing, they differ in many details. I suppose that you have perfected your book in Google Docs and now want it to look the same in the output PDF file.</p><p>So you just go to File -&gt; Download -&gt; OpenDocument Format (.odt) in your Google Docs, wait for the download to complete, open the downloaded document with LibreOffice and compare it to the original. I looked at the lengths of the documents - they should match. If they don&#39;t, you should probably check the length of every chapter to find the differences. A few hints are below:</p><blockquote>UPDATE: Google Docs became too slow to generate an .ODT from my book. It fails silently (the file is never downloaded). I have to download it as a .DOCX, open the DOSX with LibreOffice and save it as an .ODT file.</blockquote><h4>Fonts</h4><p>The Google Docs set of fonts differs from that in OpenOffice Writer. I used Oswald in the explanation sections of my book only to find out that LibreOffice Writer silently replaces it with a default font.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/616/1*J7Ic4_bMsq9WzZEYAFXECw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/784/1*R9ac10cSoW36i3eFqfDN5A.png" /></figure><p>Therefore, please check all kinds of text styles which you use throughout your book. If anything looks wrong, you may have to download a corresponding font from Google and install it on your computer.</p><h4>Document structure</h4><p>Google Docs uses header text style for chapters and sections. With LibreOffice Writer styles and structure are separate.</p><p>You will need to:</p><ul><li>open the “Styles and Formatting” right-side panel and right-click and Modify... the header styles there or</li><li>right-click on each kind of header in your document and choose Paragraph -&gt; Edit Style... to set up the outline levels. The outline levels are set up in the Outline &amp; List paragraph style tab.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8F_Td-TVAByC-t7ZZz_qrw.png" /></figure><p>For example, in my book there are:</p><ol><li>Title style for book parts — it gets outline level 1</li><li>Heading 1 style for chapters — outline level 2</li><li>Heading 2 style for groups of sections — outline level 3</li><li>Heading 2 style for individual sections — outline level 4</li></ol><p>Please be aware that now your book’s title or blank lines from the title page may appear as stray chapters in the table of contents, unless you change their styles to default and set up their font sizes manually.</p><h4>Orphaned lines</h4><p>Google Docs prevents single lines of text from appearing at the top or bottom of the page. LibreOffice Writer has two controls for that: Orphan control and Widow control. Both are in the Text Flow tab of the paragraph style dialog.</p><p>You have to enable both of them for the default paragraph style. Please note that they are already enabled for headings.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jIJ4UQqQYRcXHhzA7dr9rA.png" /></figure><p>There is also a subtle difference in the logic of the feature: while Google Docs keeps a header, diagram, and the following caption line together, LibreOffice Writer does not consider them to be a single paragraph, thus you may see a caption separated from its diagrams or a section header together with a diagram separated from the section’s text. Fixing that will likely require manual changes which may be as simple as inserting a blank line before every diagram with a caption.</p><h4>Tables</h4><p>Google Docs seems to generate tables with no padding. While the tables look good in Google Docs, in LibreOffice Writer the spacing between cells is smaller than the spacing between lines of text inside a cell.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/601/1*Q85sow4ADfjcKG08UwUy_Q.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/605/1*-xZ1FLAGuk1-qfZZmjkYWA.png" /></figure><p>Thus you may need to increase padding in the Table Properties -&gt; Borders dialog for each table in your document. There seems to be no easy way to select all the tables - you&#39;ll have to edit each of them manually.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*KNgC3K4kJ_KKU45qxPY-eg.png" /></figure><h4>Transparency</h4><p>I used transparency to reduce the contrast of the background image on the title page of my book.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/807/1*YubwwslH-7Ia4ZeLT7dCkA.png" /></figure><p>LibreOffice Writer does not support transparency for images, only for page areas. I had to delete the cover image and re-insert it through Page Style -&gt; Area -&gt; Image to make it semi-transparent via Page Style -&gt; Transparency.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/879/1*YYLLThchn7sLN5-CokKeyA.png" /></figure><h4>Bullets and fonts</h4><p>If you use multiple fonts in a list, the list’s bullets will differ in size. You’ll need to left-click a bullet (this selects all the bullets in the list) and choose a font which will apply to all the bullets.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/591/1*rxEaxZo6qYD3olrGOq-XkQ.png" /></figure><h4>Known bugs</h4><p>There are several LibreOffice Writer bugs (as of 7.3.7.2) that cause inconveniences:</p><ul><li>Recovery of a document after a crash may corrupt suggestions — additions become deletions. This is a point against offline collaboration via ODT files.</li><li>Autosave (recovery backup) cannot be disabled via Options -&gt; Load/Save -&gt; General -&gt; Save AutoRecovery information. This is really annoying for large documents as the saving takes half a minute and happens every 10 minutes.</li><li>Paragraph Style -&gt; Text Flow -&gt; Keep with next paragraph setting is not applied when a document is loaded. Opening the style dialog for a header and just pressing OK will reformat the document and may change its number of pages and the PDF output.</li></ul><h3>Exporting to a PDF</h3><p>This is straightforward:</p><ul><li>Run File -&gt; Export As -&gt; Export as PDF... in LibreOffice Writer.</li><li>Be sure that the Archive (PDF/A, ISO 19005) box is checked.</li><li>The Export outlines checkbox is responsible for creation of the table of contents.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/798/1*o2vjVqBjDgdfK7NiAJ5L0w.png" /></figure><p>Now you have your PDF with a nice table of contents!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jvvLwDc7Get-UXs-qRNXXQ.png" /></figure><h3>Making a EPUB</h3><p>This part is complicated.</p><p>You will probably want to make a copy of your document as the steps below involve destructive modifications.</p><h4>Get rid of the title page</h4><p>The EPUB includes the cover as a stand-alone image. Therefore you should delete the cover page from your document to avoid its being duplicated. Which is not that easy because the title page’s properties differ from those of other pages, therefore merely deleting the cover page’s text and image does not work — the second page becomes the new title page.</p><p>I found the following workaround:</p><ul><li>Delete the contents of your title page. Your second page will become your title page.</li><li>Select Format -&gt; Title Page... -&gt; Make Title Pages -&gt; Insert new title pages. Press OK - that should insert a blank default-style title page in front of the document</li><li>Now delete the newly inserted blank lines to pull the text from your second page into the first page.</li><li>Save the updated document.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/437/1*MiZlG3JM-O4T2i3tmFoA_w.png" /></figure><h4>Generate the cover image</h4><p>Now you need to create the cover (printout of your title page) for your EPUB. There are two ways:</p><ul><li>KISS: Make a screenshot of your title page in Google Docs or LibreOffice Writer.</li><li>The knightly path: Extract it from the PDF file generated in the previous section. Assuming you are on Linux, run pdftoppm -singlefile -png YourBook.pdf &gt; Cover.png</li></ul><h4>Create the EPUB</h4><p>You will need Calibre. Install it.</p><p>Open your ODT file without the title page with Calibre (that should be possible through right-clicking the file and choosing Open with other application).</p><p>Right-click on the newly created book in Calibre’s library (its main page) and select Edit metadata -&gt; Edit metadata individually.</p><ul><li>Set the book’s cover from the image generated in the previous step.</li><li>Fill in the title and author(s).</li><li>You can add tags, but I don’t know if they appear in the published book, or are internal to Calibre.</li><li>Apply the changes.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*XmqbGrlKWmp-y-Y6cGLEIw.png" /></figure><p>Right-click on your book. Convert books -&gt; Convert individually.</p><ul><li>Choose ODT as input and EPUB as output format.</li></ul><p>Fonts tab of the Look and Feel dialog:</p><ul><li>Check Embed all fonts</li><li>Check Subset all embedded fonts</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/912/1*yoVicGOttPG1m7hKJlscCA.png" /></figure><p>There is some magic under the Structure detection dialog:</p><ul><li>Detect chapters works with //*[name()=&#39;h1&#39; or name()=&#39;h2&#39; or name()=&#39;h3&#39; or name()=&#39;h4&#39;] - This probably is related to the table of contents. Calibre&#39;s table of contents is limited to 3 levels, however.</li><li>Insert page breaks before should detect every kind of section if we want every section to appear on a new page: //*[name()=&#39;h1&#39; or name()=&#39;h2&#39; or name()=&#39;h3&#39; or name()=&#39;h4&#39;].</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/859/1*8NUTEI18GiAQHZh_gm_eJQ.png" /></figure><p>The Table of Contents dialog also needs your attention:</p><ul><li>Change the Number of links to add to a big number like 500.</li><li>The levels are required for a multi-level (hierarchical) table of contents:</li><li>Set Level 1 TOC to //*[name()=&#39;h1&#39;]</li><li>Set Level 2 TOC to //*[name()=&#39;h2&#39;]</li><li>Set Level 3 TOC to //*[name()=&#39;h3&#39;]</li><li>Check Manually fine-tune the ToC after conversion.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/804/1*oMYnz3htoXzzAvVOnqeJag.png" /></figure><p>Click OK and wait for a couple of minutes.</p><p>Enjoy the preview of your table of contents. You can edit it manually or delete and regenerate it with the buttons on the right side of the dialog.</p><p>Alternatively, you can delete the generated table of contents by pressing Ctrl+A and del and create a new full-depth table of contents by using the Create table of contents from all headers button (and choosing Include duplicates if a pop-up appears). This allows for making a 4-level table of contents and also adds introductory sections.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*XVi-dx8VIndviPVhld-1ew.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hoKxpafAmmQsbIde409d_Q.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kD6K84-Mq0Dx8oke38aE-A.png" /></figure><p>If you work on the table of contents for a couple of minutes, there will appear a pop-up warning about a ToC creation timeout. It is safe to ignore.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*tybaJgUXoY09YHDgEl2DqQ.png" /></figure><p>Right-Click on your book. Choose Open containing folder. Enjoy the EPUB you&#39;ve created!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/910/1*RtV_mecak1g7_z3721J27w.png" /></figure><h4>Issues with Calibre’s EPUB</h4><p>There are a couple of troubles with the Calibre’s output:</p><p>It uses &lt;class=&quot;calibre&quot;&gt; in a non-standard place which results in errors from EPUB validation tools. If your publisher insists on fixing the errors (PublishDrive does), you should:</p><ul><li>Install Sigil.</li><li>Open the EPUB with Sigil.</li><li>Find class=&quot;calibre&quot;&gt; and replace it with &gt; throughout the EPUB contents (All HTML Files).</li></ul><p>Lists are not well-aligned. Fixing that requires knowledge of CSS.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/618/1*qD-zHQfEocypoljlddv6ew.png" /></figure><h3>Publish the book</h3><p>I tried Leanpub (PDF and EPUB) and PublishDrive (EPUB only).</p><p>PublishDrive is stringent on errors. You will need to fix the EPUB created by Calibre (see above).</p><p>Leanpub accepts everything, but it has a couple of peculiarities:</p><h4>Generating the table of contents for Leanpub</h4><p>Leanpub expects you to generate the table of contents of your book as a HTML list. You will need to do the following:</p><ul><li>Open your EPUB (3 ToC levels) or PDF (4 ToC levels but it may take forever to open) file with Calibre’s E-book viewer.</li><li>Right-click on the table of contents in the viewer and select Copy Table of Contents to clipboard.</li><li>Paste the table of contents into your favorite plain text editor and save it as a TXT file. You may also edit the contents if needed.</li><li>Download <a href="https://github.com/denyspoltorak/publications/blob/main/tools/toc_to_html.py">my converter</a> (a tiny Python script) and run it (the following works on Linux, for Windows you may have to prepend `python`): ./toc_to_html.py toc.txt toc.html</li><li>Open the generated HTML file with a plain text editor and copy-paste its contents into your book’s Leanpub page.</li></ul><h4>Generating a sample chapter</h4><p>You will probably want Leanpub to offer prospective readers to download a sample chapter from your book. However, that requires you to prepare the corresponding PDF and EPUB files:</p><ul><li>Clone the book in Google Docs</li><li>Edit the cover</li><li>Delete everything except the table of contents, the chapter you will use for promotion and, probably, a few appendixes.</li><li>Unlink any cross-references to the deleted chapters throughout the remaining text, including the table of contents.</li><li>Download the sample as ODT.</li><li>Repeat all the steps which you did for your book:</li><li>Fix the ODT with LibreOffice Writer.</li><li>Convert it to PDF.</li><li>Convert it to EPUB with Calibre.</li></ul><p>That’s it. Enjoy your book.</p><p>Please feel free to <a href="https://www.linkedin.com/in/denyspoltorak/">contact me</a> if you have any improvements for this instruction.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5b1abc65f69d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Architectural Metapatterns (free eBook on software architecture) — release 1.1]]></title>
            <link>https://denyspoltorak.medium.com/architectural-metapatterns-free-ebook-on-software-architecture-release-1-1-381a7e15f092?source=rss-7d4e79c3c009------2</link>
            <guid isPermaLink="false">https://medium.com/p/381a7e15f092</guid>
            <category><![CDATA[design-patterns]]></category>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[system-architecture]]></category>
            <category><![CDATA[software-design]]></category>
            <category><![CDATA[free-books]]></category>
            <dc:creator><![CDATA[Denys Poltorak]]></dc:creator>
            <pubDate>Fri, 18 Jul 2025 14:15:21 GMT</pubDate>
            <atom:updated>2025-07-18T14:15:21.784Z</atom:updated>
            <cc:license>https://creativecommons.org/licenses/by-nc-sa/4.0/</cc:license>
            <content:encoded><![CDATA[<h3>Architectural Metapatterns (free eBook on software architecture) — release 1.1</h3><p>This is a bugfix release made possible by Lars Noodén who volunteered to edit the book. Now its English and styling are better.</p><h4>What’s inside?</h4><p>The book is a taxonomy and compendium of architectural patterns with hundreds of NoUML diagrams. Available as PDF and EPUB.</p><h4>How much does it cost?</h4><p>It’s free, distributed under the CC-BY license. You can download the book from <a href="https://github.com/denyspoltorak/publications/releases/tag/v1.1">GitHub</a> or <a href="https://leanpub.com/metapatterns">Leanpub</a>.</p><h4>Are there any testimonials?</h4><p>Yes, including one from Mark Richards. Please see the book’s <a href="https://leanpub.com/metapatterns">Leanpub page</a>.</p><h4>How can I help?</h4><ol><li>Tell your friends about the book.</li><li>Propose corrections, improvements or patterns which I missed.</li><li>Become a co-author — the book needs one or two <a href="https://martinfowler.com/bliki/DuplexBook.html">case studies</a>.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fYt21QNt5Xql4ZFYpSzGuA.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=381a7e15f092" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Architectural Metapatterns: the Pattern Language of Software Architecture — final release]]></title>
            <link>https://denyspoltorak.medium.com/architectural-metapatterns-the-pattern-language-of-software-architecture-final-release-d2d69b619d59?source=rss-7d4e79c3c009------2</link>
            <guid isPermaLink="false">https://medium.com/p/d2d69b619d59</guid>
            <category><![CDATA[design-patterns]]></category>
            <category><![CDATA[system-architecture]]></category>
            <category><![CDATA[software-design]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[software-architecture]]></category>
            <dc:creator><![CDATA[Denys Poltorak]]></dc:creator>
            <pubDate>Wed, 16 Apr 2025 13:57:29 GMT</pubDate>
            <atom:updated>2025-04-16T13:57:29.777Z</atom:updated>
            <cc:license>http://creativecommons.org/licenses/by/4.0/</cc:license>
            <content:encoded><![CDATA[<h3>Architectural Metapatterns: the Pattern Language of Software Architecture — final release</h3><p><a href="https://leanpub.com/metapatterns">The book is ready</a>. Now it contains everything I wanted it to have and much more:</p><ul><li>An intuitive classification of architectural patterns.</li><li>A universal pattern language that interconnects hundreds of patterns.</li><li>Lots of diagrams to skim through — they make a parallel narrative.</li><li>Basic principles of software architecture.</li><li>Comparison of approaches to select aspects of software design.</li></ul><p>It collected praise from experts, including Mark Richards, whose books I relied on. I asked for critical reviews to improve my book — and received testimonials for publishing it instead.</p><p>Looking back, I don’t believe that I have written it. It is too complex and daring, solving the long-standing issue of pattern classification and unifying software and system architecture. God installed the idea and led me through writing it down. Now it’s over. I am yet another unemployed programmer from Ukraine.</p><p>Something new lies ahead. I have nothing to aspire after in software engineering anymore. Let’s wait and see.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*XDqwof_uZxfREhW8tNT13A.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d2d69b619d59" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>