<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Lorenzo Arribas</title>
    <description>The latest articles on DEV Community by Lorenzo Arribas (@larribas).</description>
    <link>https://dev.to/larribas</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F108538%2Fabc95295-74eb-445e-99b1-8251580136b0.jpg</url>
      <title>DEV Community: Lorenzo Arribas</title>
      <link>https://dev.to/larribas</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/larribas"/>
    <language>en</language>
    <item>
      <title>Colmena, an Architecture for Highly-Scalable Web Services</title>
      <dc:creator>Lorenzo Arribas</dc:creator>
      <pubDate>Tue, 06 Nov 2018 13:49:53 +0000</pubDate>
      <link>https://dev.to/larribas/colmena-an-architecture-for-highly-scalable-web-services-2mlo</link>
      <guid>https://dev.to/larribas/colmena-an-architecture-for-highly-scalable-web-services-2mlo</guid>
      <description>&lt;p&gt;About 3 years ago, our startup pivoted from a Q&amp;amp;A app for doctors to an education platform (which we named &lt;a href="https://schoolhouse.io/en/" rel="noopener noreferrer"&gt;SchoolHouse.io&lt;/a&gt;). It was a big product shift, and we knew many technical changes would follow.&lt;/p&gt;

&lt;p&gt;At the time, we had a 1-year-old Python+Django codebase that was &lt;em&gt;already&lt;/em&gt; getting rusty and hard to maintain. How did we cross the legacy line so fast?&lt;/p&gt;

&lt;p&gt;(sigh)&lt;/p&gt;

&lt;p&gt;We were clearly doing something wrong, and we wanted to understand &lt;em&gt;what&lt;/em&gt;, so we made a list of our &lt;strong&gt;main pain points&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;To understand how a feature worked, we needed to jump a lot between our code and the framework's, sometimes through long inheritance hierarchies, decorators, hooks and conventions documented somewhere. Thus, every time we needed to trace a bug or make a change we needed to put on our Indiana Jones hat.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It wasn't obvious where many changes (like some permissions, relationships or validations) belonged. This generated a lot of interesting but ultimately time-wasting debates.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Unit tests were ridden with stubs and mocks, and when they weren't, they had to be busy understanding HTTP parameters or making sure the database was clean.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffsrk1362b9pw7kct0m1j.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffsrk1362b9pw7kct0m1j.jpg" alt="We're good. This framework is DRY" width="661" height="500"&gt;&lt;/a&gt;&lt;/p&gt;
We tried to be DRY, but working on our codebase felt like drowning.



&lt;h2&gt;
  
  
  We ditched MVC frameworks and did it our way
&lt;/h2&gt;

&lt;p&gt;Those issues made us unproductive and made our codebase messy over time.&lt;/p&gt;

&lt;p&gt;On top of that, we suspected we wouldn't be able to solve our pain points if we kept using an MVC framework by the book, so we set out to &lt;strong&gt;design our own architecture&lt;sup id="fnref1"&gt;1&lt;/sup&gt;, optimized for long-term productivity and maintainability&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  ... So, was it worth it?
&lt;/h2&gt;

&lt;p&gt;3 years later, we've seen our product change A LOT, fell in love with functional languages like Elm and Haskell, and went beyond full-stack, taking care of graphic design, frontend engineering, system administration, and data science. And despite all these changes, we believe something extraordinary has happened: &lt;strong&gt;We are as comfortable with our backend as the first day (no large refactors!).&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Our architectural choices have consistently made our lives easier, and now we'd like to share what we've learned with the community. We've also published &lt;a href="https://github.com/schoolhouse-io/colmena-realworld-example-app" rel="noopener noreferrer"&gt;an implementation of the RealWorld spec&lt;/a&gt; to provide realistic code examples&lt;sup id="fnref2"&gt;2&lt;/sup&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  OK. I'm listening. What is it about?
&lt;/h2&gt;

&lt;p&gt;A &lt;em&gt;Colmena&lt;/em&gt; app is composed of multiple cells.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cells are self-contained services&lt;/strong&gt; that follow the &lt;a href="https://fideloper.com/hexagonal-architecture" rel="noopener noreferrer"&gt;hexagonal architecture&lt;/a&gt;. Each cell:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Has a clear purpose and responsibility.&lt;/li&gt;
&lt;li&gt;Has some internal domain that represents, validates and transforms the cell's state.&lt;/li&gt;
&lt;li&gt;Relies on a series of interfaces to receive input from (and send output to) external services and technologies.&lt;/li&gt;
&lt;li&gt;Exposes a public API (a contract stating what it can do).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fadv0g1vr5198qnu0bpjy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fadv0g1vr5198qnu0bpjy.png" alt="A basic authentication cell exposes operations to create new credentials, check them and update them. It also needs to communicate with an Oauth service and a database." width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can think of cells as &lt;strong&gt;very small microservices&lt;/strong&gt;. In fact, we encourage you to try to make your cells as small as possible. In our experience, granulating your domain around entities and relationships helps you understand, test and maintain the codebase in the long run. These are the cells of the &lt;a href="https://github.com/schoolhouse-io/colmena-realworld-example-app" rel="noopener noreferrer"&gt;RealWorld backend&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;user&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;auth&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;follow&lt;/strong&gt; (user)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;article&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;tag&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;comment&lt;/strong&gt; (article)&lt;/li&gt;
&lt;li&gt;(article) &lt;strong&gt;feed&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If we told you our app is a blogging platform, the purpose of each cell becomes pretty clear. It would only take a glance at the &lt;a href="https://github.com/schoolhouse-io/colmena-realworld-example-app/tree/master/lib/real_world" rel="noopener noreferrer"&gt;&lt;code&gt;lib/real_world&lt;/code&gt; directory&lt;/a&gt; to find out where a certain feature might be defined. From there, a developer can quickly look at the API to learn about the operations it supports and navigate the implementation in a very gradual and natural way.&lt;/p&gt;

&lt;h3&gt;
  
  
  An event-based, functional domain
&lt;/h3&gt;

&lt;p&gt;Each cell models a small domain. This domain may correspond to an entity (e.g. a user), a relationship (e.g. a user follows another), or a special feature (e.g. each user has their own materialized feed of articles).&lt;/p&gt;

&lt;p&gt;In &lt;em&gt;Colmena&lt;/em&gt;, &lt;strong&gt;changes to the domain are represented as a sequence of events&lt;/strong&gt;. This sequence of events is append-only, as events are immutable (they are &lt;em&gt;facts&lt;/em&gt; that have already taken place). In &lt;a href="https://www.youtube.com/watch?v=8JKjvY4etTY" rel="noopener noreferrer"&gt;event sourcing&lt;/a&gt;, this sequence is called a "Source of truth", and it provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An audit log of all the actions that have modified the domain.&lt;/li&gt;
&lt;li&gt;The ability for other components (in the same or different cells) to listen to certain events and react to them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The latter practice is commonly known as &lt;em&gt;event-driven&lt;/em&gt; or &lt;em&gt;reactive programming&lt;/em&gt;, and it has proven a really useful way to implement certain features with very low coupling.&lt;/p&gt;

&lt;p&gt;Moreover, since we have a sequence of immutable data, &lt;strong&gt;everything the domain does can be conceived as a pure function&lt;/strong&gt; (no side effects, just deterministic data transformations). In Ruby (or any other object-oriented language for that matter), this translates to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No classes, class instances, or methods.&lt;/li&gt;
&lt;li&gt;No calls to any external technology or service.&lt;/li&gt;
&lt;li&gt;No need for stubs, mocks, or any other test artifacts that make our tests slow or complicated.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;We can &lt;a href="https://github.com/schoolhouse-io/colmena-realworld-example-app/blob/master/lib/real_world/follow/domain.rb" rel="noopener noreferrer"&gt;validate and describe our app's behavior&lt;/a&gt; in a way that is both simple and very powerful, forgetting about the noise.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8g3yip8vmel3uk6cu6eo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8g3yip8vmel3uk6cu6eo.png" alt="A functional, evented domain takes a current state (pure data), some arguments (pure data) and produces a deterministic output (pure data)." width="800" height="578"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  A public contract
&lt;/h3&gt;

&lt;p&gt;Every &lt;em&gt;useful&lt;/em&gt; application needs to let the world do something with it. We'll continue with our RealWorld example.&lt;/p&gt;

&lt;p&gt;Our &lt;code&gt;follow&lt;/code&gt; cell is there to fulfill a few use cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A user follows another profile.&lt;/li&gt;
&lt;li&gt;A user stops following another profile.&lt;/li&gt;
&lt;li&gt;Someone wants to know whether a particular user follows a particular profile.&lt;/li&gt;
&lt;li&gt;Someone wants to know which profiles a user is following.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You'll notice the first two use cases are actions that &lt;em&gt;may&lt;/em&gt; (if validation rules allow it) change the cell's state, whereas the last two use cases are just querying the current state.&lt;/p&gt;

&lt;p&gt;In &lt;em&gt;Colmena&lt;/em&gt;, we call the former &lt;em&gt;commands&lt;/em&gt; and the latter &lt;em&gt;queries&lt;/em&gt;, and we deal with them in a slightly different way. This pattern is called &lt;a href="https://martinfowler.com/bliki/CQRS.html" rel="noopener noreferrer"&gt;CQRS (command-query responsibility segregation)&lt;/a&gt;. The linked article does a very good job at explaining the pros and cons of this approach, so we'll focus on our particular implementation for this RealWorld codebase:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmt7c0q9q5ywhjnxu0tad.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmt7c0q9q5ywhjnxu0tad.png" alt="A query reads from a database (which could be optimized for a particular kind of read operation), whereas a command might need to read from a database, find out what to do and store the changes, all of this within a transaction." width="800" height="642"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is extremely valuable for a project to &lt;strong&gt;make sure the contracts for all these public-facing components are properly documented and semantically versioned&lt;/strong&gt;. Developers need to be able to learn and trust, at any point:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What types of events does this cell publish? What data do they contain?&lt;/li&gt;
&lt;li&gt;Which are the arguments to this command? How about this query?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Keep ACID properties in mind
&lt;/h3&gt;

&lt;p&gt;Given that this is a distributed architecture with many components and cells working separately, it's fair to wonder... Are changes atomic? How do we keep them consistent?&lt;/p&gt;

&lt;p&gt;When commands need to be atomic (they usually do), they are decorated by a transaction. This transaction is responsible for publishing the sequence of events the command generates and running the proper materializers. In turn, these &lt;strong&gt;materializers enforce consistency and integrity&lt;/strong&gt;. A materializer takes a sequence of events and propagates their changes to the several "read models" the queries use.&lt;/p&gt;

&lt;p&gt;For instance, the transaction in the previous diagram might call these materializers:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9irn6z2y1g2rp57h88b1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9irn6z2y1g2rp57h88b1.png" alt="A transaction makes sure the events are materialized in different ways." width="800" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's try with a second example as well. We're dealing with &lt;em&gt;articles&lt;/em&gt; now. A materializer might get the following sequence of events:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;article_published(...)
article_tagged(...)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And perform the following operations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Store the whole article in a document-oriented database (e.g. MongoDB) to optimize read operations.&lt;/li&gt;
&lt;li&gt;Store the article in a reverse index of &lt;code&gt;tag -&amp;gt; articles&lt;/code&gt; to fetch articles with certain tags.&lt;/li&gt;
&lt;li&gt;Store the article's title and description in a database optimized for search (e.g. ElasticSearch).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some parts of this materialization process must happen synchronously (if consistency is a requirement). Others may happen asynchronously (when &lt;a href="http://guide.couchdb.org/draft/consistency.html" rel="noopener noreferrer"&gt;eventual consistency&lt;/a&gt; is enough).&lt;/p&gt;

&lt;h3&gt;
  
  
  Rely on interfaces, not concrete implementations
&lt;/h3&gt;

&lt;p&gt;At this point, our cell accepts requests from a potentially untrusted source, stores and retrieves data from a database, and may need to call other cells.&lt;/p&gt;

&lt;p&gt;These operations are the weak links of software development. The network can fail, databases can be corrupted and public APIs can't be trusted. So, what can we do to minimize these risks?&lt;/p&gt;

&lt;p&gt;In &lt;em&gt;Colmena&lt;/em&gt;, &lt;strong&gt;we define every input/output component as an interface (a port in the hexagonal jargon)&lt;/strong&gt;. A particular cell might rely on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;repository&lt;/code&gt; port, which persists and reads domain data.&lt;/li&gt;
&lt;li&gt;An &lt;code&gt;event publisher&lt;/code&gt; port, which allows events to be made public.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;router&lt;/code&gt; port, which communicates with other cells.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In Ruby, we specify the behavior these interfaces should satisfy with a &lt;a href="https://github.com/schoolhouse-io/colmena-realworld-example-app/blob/master/lib/real_world/follow/ports/repository/spec_shared_examples.rb" rel="noopener noreferrer"&gt;shared example&lt;/a&gt;. All implementations (adapters in the hexagonal jargon) must comply with the spec if they are to be trusted, and provide explicit error handling so that risks can be gracefully handled, logged, and mitigated.&lt;/p&gt;

&lt;p&gt;Relying on interfaces is one of the most basic design principles, and it has immediate practical benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We can write a single test for multiple components.&lt;/li&gt;
&lt;li&gt;We can apply the &lt;a href="https://softwareengineering.stackexchange.com/questions/234747/dependency-inversion-principle-vs-program-to-an-interface-not-an-implementatio" rel="noopener noreferrer"&gt;dependency inversion principle&lt;/a&gt; to inject the adapters we need for each environment (e.g. a fast SQLite database for testing and a fully scalable cloud database in production).&lt;sup id="fnref3"&gt;3&lt;/sup&gt;
&lt;/li&gt;
&lt;li&gt;We can switch to a different technology without changing our cell's code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Your application is made up of multiple cells
&lt;/h3&gt;

&lt;p&gt;Cells have clearly defined boundaries, but they still need to communicate with one another. In &lt;em&gt;Colmena&lt;/em&gt;, cells can talk to each other in two different ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Synchronously, invoking a command or query on the other cell. This is a traditional &lt;a href="https://en.wikipedia.org/wiki/Remote_procedure_call" rel="noopener noreferrer"&gt;remote procedure call&lt;/a&gt; we perform through a &lt;a href="https://microservices.io/patterns/service-registry.html" rel="noopener noreferrer"&gt;central service registry&lt;/a&gt; we call &lt;a href="https://github.com/schoolhouse-io/colmena-realworld-example-app/blob/master/lib/real_world/ports/router/in_memory.rb" rel="noopener noreferrer"&gt;&lt;em&gt;the router&lt;/em&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Asynchronously, listening to events produced by the other cell and reacting to them. We do this through an &lt;a href="https://github.com/schoolhouse-io/colmena-realworld-example-app/blob/master/lib/real_world/ports/event_broker/in_memory.rb" rel="noopener noreferrer"&gt;event broker&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;In our example app, both the router and event broker ports are implemented in-memory. The beauty of these interfaces is that they can be implemented by a service like RabbitMQ or Amazon Kinesis and connect cells deployed on different parts of the world; or even cells written in different programming languages!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here are a few examples of how we glue cells together in this RealWorld service:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;a href="https://github.com/schoolhouse-io/colmena-realworld-example-app/blob/master/lib/real_world/tag/listeners/counter.rb" rel="noopener noreferrer"&gt;counter listener&lt;/a&gt; reacts to tags being added to or removed from an article and it updates a total count on the times a tag has been used. All the while, the &lt;code&gt;article&lt;/code&gt; cell doesn't even know the &lt;code&gt;tag&lt;/code&gt; cell exists.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;api&lt;/code&gt; cell is a bit special. It exposes some of the behavior of all cells in a RESTful HTTP API. As such, it needs to deal with authentication and authorization, hiding private data and aggregating several operations into &lt;a href="https://github.com/schoolhouse-io/colmena-realworld-example-app/blob/master/lib/real_world/api/commands/api_register.rb" rel="noopener noreferrer"&gt;a more useful endpoint&lt;/a&gt;, making several sub-calls to other cells in the process. We've recently found out this pattern &lt;a href="https://microservices.io/patterns/data/api-composition.html" rel="noopener noreferrer"&gt;has its own name&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk5g2oxrj439yn2njfhmw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk5g2oxrj439yn2njfhmw.png" alt="In the hexagonal architecture, a cell has several layers. The outmost layer is the framework layer, where we interface with specific tools, services or libraries. Beneath it is the aplication layer, where we expose all public-facing features (commands, queries and listeners in our case). Beneath the application is the domain." width="800" height="313"&gt;&lt;/a&gt;&lt;/p&gt;
The layers in the hexagonal architecture, as applied to the concepts in Colmena.



&lt;h2&gt;
  
  
  Hence, &lt;em&gt;Colmena&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;We felt it was better to start explaining this architecture from the bottom up, so we haven't had the time to explain properly what the heck a &lt;em&gt;Colmena&lt;/em&gt; is.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Colmena&lt;/em&gt; means Beehive in Spanish. Like our architecture, 🐝-hives are composed of many small hexagonal units that are isolated from one another but work together as a powerful system. Isn't that beautiful?&lt;/p&gt;

&lt;p&gt;Hence, the name.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F56m1aae7gcyz3ngkrrui.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F56m1aae7gcyz3ngkrrui.jpg" alt="A beehive is made up of many hexagonal cells that work together" width="600" height="450"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;In this article, we've presented an overview of the Colmena architecture and the reasons that brought us to use it in the first place.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;In the next ones, we'll zoom into some of the main features and provide more details and code examples.&lt;/em&gt;&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;By what we mean, do a lot of research and combine the ideas we liked the most with our own use cases ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;The example app is written in Ruby, but we've applied the same ideas to codebases in Go and Haskell, with the same effects. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;Just remember to &lt;strong&gt;test every adapter&lt;/strong&gt; before releasing to production, not just the ones you use for your development environment. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>webdev</category>
      <category>ruby</category>
      <category>microservices</category>
      <category>scalability</category>
    </item>
    <item>
      <title>5 ways to make your codebase withstand the test of time</title>
      <dc:creator>Lorenzo Arribas</dc:creator>
      <pubDate>Thu, 18 Oct 2018 16:38:15 +0000</pubDate>
      <link>https://dev.to/larribas/5-ways-to-make-your-codebase-withstand-the-test-of-time-3652</link>
      <guid>https://dev.to/larribas/5-ways-to-make-your-codebase-withstand-the-test-of-time-3652</guid>
      <description>&lt;p&gt;&lt;em&gt;This is the first in a series of articles where &lt;a class="mentioned-user" href="https://dev.to/hecrj"&gt;@hecrj&lt;/a&gt; and I share what we have learned after working on a large, fast-changing codebase for the past 3 years, and being perfectly happy with the result!&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;If you are a web developer, you are probably used to having new frameworks, libraries and technologies come out every other week.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We are on a never-ending quest to find better tools and patterns, but does that mean our code is doomed to become old and wrinkly?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvbwjbdh0bgptapx5omjv.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvbwjbdh0bgptapx5omjv.jpeg" alt="Your decisions will always impact many other people" width="500" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How do you anchor your project so that it resists the &lt;em&gt;Winds of Trend&lt;/em&gt;? Here are 5 tips that have worked out pretty well for us.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Split your code based on domain concepts, not tech concepts
&lt;/h2&gt;

&lt;p&gt;One of the first questions you may have when starting a new project is how should you structure it. There are two popular schools of thought here: Either we split our files by tech concepts, or by domain concepts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    # Split by tech concepts        # Split by domain concepts

    |- src                          |- auth
    |  |- controllers               |  |- controllers
    |  |  |- auth                   |  |- models
    |  |  |- profile                |  |- views
    |  |  |- article                |  |- tests
    |  |- models                    |- profile
    |  |- views                     |- article
    |- test                         (...)
    |  |- controllers
    |  |  |- auth
    (...)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you’ve read the header you might have an idea of what we’ll recommend, but let’s back that up with a few thoughts.&lt;/p&gt;

&lt;p&gt;Say you arrive at the root of a project with a specific goal (hunting down a bug, adding a feature, removing it, etc.). You need to find the appropriate code, navigate through related files, take a look at the tests, and when you feel confident enough, make those changes to the codebase.&lt;/p&gt;

&lt;p&gt;As developers, this process is our bread and butter, so we better make it efficient.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What is easier to maintain, a codebase with 10 files or one with 100 files?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Splitting code by domain concepts allows you to focus on a small part of your codebase, whereas doing it by tech concept forces you to jump around.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Provide a public contract (API) for all your domain concepts
&lt;/h2&gt;

&lt;p&gt;Imagine your project has a &lt;code&gt;payments&lt;/code&gt; directory where you keep all 💰-related code. We have a series of components to store our payments in a database or connect to 3rd-party services like &lt;em&gt;Stripe&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;All &lt;strong&gt;those components are there to fulfill a contract&lt;/strong&gt;, that is, to make sure &lt;code&gt;payments&lt;/code&gt; behave they way they should.&lt;/p&gt;

&lt;p&gt;Just to be clear, we are &lt;em&gt;not&lt;/em&gt; talking about the HTTP API your mobile app will call to charge users. We are talking about an internal API that turns your payments directory into its own “microservice” (using the term freely).&lt;/p&gt;

&lt;p&gt;Why, you ask?&lt;/p&gt;

&lt;p&gt;Because having an explicit API provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A clear picture of the expected behavior.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A minimum test coverage everyone can agree upon and commit to.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The freedom to change anything from the underlying implementation.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Furthermore, &lt;strong&gt;it is important for this API to know as little as possible of external concepts such as users, permissions or environments&lt;/strong&gt;. These are not part of the domain. They are the way we solve a problem with the communication layer (a public HTTP endpoint is inherently insecure) or our development workflow.&lt;/p&gt;

&lt;p&gt;For instance, we can imagine having:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A public-facing API that exposes &lt;em&gt;some&lt;/em&gt; of the domain behavior and controls authentication and authorization.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A private admin API + panel to provide easy customer support and look into bugs without ever touching any database or console.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A really easy way to write fixtures, examples and migrations.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Rely on small interfaces
&lt;/h2&gt;

&lt;p&gt;This one is pretty popular. As developers, we are constantly reminded to rely on abstractions instead of concrete implementations, &lt;a href="https://en.wikipedia.org/wiki/Interface_segregation_principle" rel="noopener noreferrer"&gt;segregate our interfaces&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Dependency_inversion_principle" rel="noopener noreferrer"&gt;invert our dependencies&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can easily find plenty of material covering the theory, so let’s focus on some practical examples. Our &lt;code&gt;Payments&lt;/code&gt; app might need to talk to these interfaces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;An event publisher&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An event subscriber&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A credit card charger&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An email sender&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All these interfaces have a small and clearly defined role. Later on, we will inject the particular implementations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;production&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Payments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="ss"&gt;event_publisher: &lt;/span&gt;&lt;span class="n"&gt;rabbitmq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;event_subscriber: &lt;/span&gt;&lt;span class="n"&gt;rabbitmq_replicas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;credit_card_charger: &lt;/span&gt;&lt;span class="n"&gt;stripe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;email_sender: &lt;/span&gt;&lt;span class="n"&gt;mailgun&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;development&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Payments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="ss"&gt;event_publisher: &lt;/span&gt;&lt;span class="n"&gt;in_memory_bus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;event_subscriber: &lt;/span&gt;&lt;span class="n"&gt;in_memory_bus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;credit_card_charger: &lt;/span&gt;&lt;span class="n"&gt;stripe_test_mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;email_sender: &lt;/span&gt;&lt;span class="n"&gt;muted_mailer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, small interfaces allow us to create well-defined tests and choose the best strategy for each action depending on the environment. On the other hand, we usually write implementations based on particular technologies, to centralize all the knowledge and helper functions around them.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Decouple your data from your storage strategy
&lt;/h2&gt;

&lt;p&gt;Let’s get it out of the way: We think ORMs are wrong (or maybe it’s people who are doing them wrong). Take a look at this &lt;em&gt;Ruby on Rails&lt;/em&gt; code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Article&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt;
  &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:comments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;dependent: :destroy&lt;/span&gt;

  &lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="ss"&gt;:authored_by&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;user: &lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;username: &lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;validates&lt;/span&gt; &lt;span class="ss"&gt;:title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;presence: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;allow_blank: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;
  &lt;span class="n"&gt;validates&lt;/span&gt; &lt;span class="ss"&gt;:body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;presence: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;allow_blank: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;

  &lt;span class="n"&gt;before_validation&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slug&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="c1"&gt;#{title.to_s.parameterize}-#{rand(36**6).to_s(36)}”&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There’s a lot to unpack here.&lt;/p&gt;

&lt;p&gt;First, we notice this object is describing relationships, cascade deletion and nullable attributes. Exactly what you would expect from an Object-Relational Mapper. Quite transparent!&lt;/p&gt;

&lt;p&gt;Next, let’s consider for a moment. What is important for us when representing an Article?:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;We should be able to harness the full power of the language we are using&lt;/strong&gt;. When we are using Java, we want to be able to use OO patterns and inheritance freely. When we are using Haskell, we want to use union types and records.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;We should be able to store our data in different formats and databases&lt;/strong&gt;. This allows us to use ElasticSearch for performant searches, PostgreSQL for a consistent state and Redis to keep our autosave feature fast enough.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ORM models offer neither, because they are just a way to interface with a SQL database. We still need to represent and manipulate our data somewhere else. The problem is, once you accept this statement, using an ORM seems awkward or overkill. This is what we mean:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Let's say we have a series of entities in our domain that we use to represent an article.&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Article&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="c1"&gt;# The big picture&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Tag&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RichText&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="c1"&gt;# Headings, bold, cross-references, …&lt;/span&gt;


&lt;span class="c1"&gt;# Now we need an interface to store the article's content in our SQL database.&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ArticleStore&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:)&lt;/span&gt;
    &lt;span class="c1"&gt;# Ruby doesn't have explicit interfaces, but you get the point&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="no"&gt;NotImplementedError&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;


&lt;span class="c1"&gt;# Using an ORM creates an additional level of indirection that looks pointless&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ArticleORMStore&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ArticleStore&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:)&lt;/span&gt;
    &lt;span class="no"&gt;ArticleModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;title: &lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;body: &lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;tags: &lt;/span&gt;&lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;author: &lt;/span&gt;&lt;span class="no"&gt;UserModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;


&lt;span class="c1"&gt;# A low-level SQL library feels simpler in comparison.&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ArticleSimpleStore&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ArticleStore&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:)&lt;/span&gt;
    &lt;span class="n"&gt;article_table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;title: &lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;body: &lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;tags: &lt;/span&gt;&lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;author: &lt;/span&gt;&lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bottom line here is: &lt;strong&gt;You can use ORMs, but don’t use them as the only way to represent and manipulate your data&lt;/strong&gt;. That’s far from their purpose.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Use events to keep your application connected and your code decoupled
&lt;/h2&gt;

&lt;p&gt;If two parts of an application are connected, the code must connected somehow, right?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://martinfowler.com/articles/201701-event-driven.html" rel="noopener noreferrer"&gt;Event-driven&lt;/a&gt; programming does a wonderful job at keeping your app interconnected, but your code easy to write and maintain. In fact it does such a good job that similar ideas have become pervasive in mobile and frontend development under the name of &lt;a href="https://medium.com/exploring-code/what-is-reactive-programming-da37c1611382" rel="noopener noreferrer"&gt;Reactive Programming&lt;/a&gt;, and in the operations world, with &lt;a href="https://thenewstack.io/event-driven-architecture-wave-future/" rel="noopener noreferrer"&gt;cloud providers and companies betting hard on it&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The basic idea is that every change to your domain is represented as an atomic event.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    article_published(…) 1 minute ago
    article_draft_created(…) 5 minutes ago
    user_signed_in(…) 25 minutes ago
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All events are published through some kind of event bus, and random observers can subscribe and react to interesting events without bothering the other components too much.&lt;/p&gt;

&lt;p&gt;It takes a bit of an extra effort at first, as you need to lay the foundation for the event bus and think about the properties and atomicity of each event, but in the long run it’s definitely worth it.&lt;/p&gt;

&lt;p&gt;Here are some examples of features that are very easy to implement with event-driven architectures, and hard to think about and maintain otherwise:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Listen for comments on an article and increase a counter (purpose: faster comment counts).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Send a welcome email to a new user.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Notify the author of an article that it has new comments.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Try to imagine how you would do each of these tasks in an imperative way vs. a reactive way.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Event-driven programming avoids long functions with many different side effects, and makes your tests nicer and more isolated.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;In the next article we’ll explain how we put all these pieces together to create our own architecture.&lt;/p&gt;

&lt;p&gt;We’d be happy to see what you think of these ideas in the comment section!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>architecture</category>
      <category>designpatterns</category>
      <category>legacy</category>
    </item>
  </channel>
</rss>
