From monolithics to microservices.
This is not another post about application architectures but a software design instead. I bet you are a bit lost with the heading, keep reading, I will take you there.
First I want to let clear that by no means I intend to make this a reference to software design, I just want to address how it’s been natural for me to adopt practices that in my opinion had lead me to write better code. Here you will find just the pieces and the most important references, I will try to cover as much as I can.
Stage 1 — Plain OO
My beginnings on serious programming were with Java and Object Oriented Programming (OOP or OO), it was challenging to start thinking in matters of objects, Encapsulation, Polymorphism, Inheritance, translating real life concepts into computers language, creating Abstractions. Somehow there is a moment when you control or even master it, but life is rich and so it is OO, then a moment comes when you don’t feel quite happy with results, and you tend to think everything needs refactor, that’s a code smell you can’t obviate, you need to improve your strategy.
Working and maintainable software leads to quality in software, that simple, some will argue but those are root cause, I mean, aren’t self-reading, well structured and organized, easy to understand and to modify code, means to the same end: Maintainability?. That’s what Object Oriented Design is about (I will refer to it as OOD or just design indistinctly from now on) let’s dig into details.
As mentioned, I just started with plain OO, in my code there were lots of objects interacting each other without following rules (or a couple of ones but nothing serious), I had “Monolithics”, yeah, non-modular programs, rigid code bases with shared responsibilities everywhere.
Stage 2 — Improved collaboration between objects
It felt good for a while but some bittersweet taste after finishing some medium/large projects encouraged me to improve. For instance I found some materials speaking about Dependency Injection — DI (Or Inversion Of Control — IoC), it was incredible how sophisticated the concept was for me, I mean, after understanding OO concepts, that was the next big thing in programming for me, it’s funny how new concepts shock me, I know….., whatever, your mind changes after using IoC, “Hollywood Principle” was like addiction.
It is called Hollywood Principle “(…) Inversion of control is sometimes facetiously referred to as the “Hollywood Principle: Don’t call us, we’ll call you”. (…)”
Stage 3 — There is a lot more on object collaboration than you think
After a few years working with Java, Spring Framework, Google Guice and friends using IoC, I moved to different languages mostly dynamically typed such as Python and Ruby for several reasons that I will discuss on future posts. On these languages DI is easier, most of the times you don’t even need a IoC container; anyways, one day I discovered SOLID, thanks to Sandi Metz and her presentations and books, big fan of her work. I just realized that there were lots of more practices than just DI, great right?
SOLID stands for SOLID (single responsibility, open-closed, Liskov substitution, interface segregation and dependency inversion), The term was introduced for Michael Feathers, referring to Robert C. Martin principles.
SOLID covers a lot of design along with Demeter Law. It’s a complete tool-set, in theory, you would be able to write better code using it, but it’s hard, in practice, you are always trying. At least it will open your mind to the “art of software design”, any improvement you do according to these will have a big impact on your application.
How did I get to “Microservices”?
I see tightly plain OO transition to OO Design (OOD), as a homolog to Monolithic to Micro-services one, both are related to move to independent, easy to manage smaller units talking through messages according to contracts, isn’t this what we call Micro-services on application architectures?. I just made my point. Let’s answer the most common question on the subject:
Which is better for you? this is subjective and context dependent, so it depends, in some cases are better concise Monolithics on other cases modular and loosely coupled Units of Work, both have pros and cons. I like to think as the second as an evolution of the first. To pick one just research what are doing people with similar problems, try both approaches to understand which one is adequate for the problem and your brain capacity, yes different people deal and react differently to disperse or concrete systems and the same with levels of abstractions. Don’t try do it perfect from the beginning, spent time in the process so you can form an opinion.
TDD: Induce good or bad design?
Testing. If I don’t speak of testing this post would be incomplete. Of course is related to Design, there are a lot of discussions about how testing can induce good or bad design to your app, I won’t go deeper on this, I just will drop my opinion: Yes testing helps, even more for beginners, it will help a lot in this case to write tests first in order to discover how to Design in a way to works for them. After years of experience you can design in your head and write code first or last whatever, sometimes tests will remember you why you are doing things in a particular way, also, there are moments where you need to write code first to get the gist of the problem, whether you do it, don’t be hard with yourself regarding those tenets of TDD, just focus on the most important thing, as soon as you write the tests, is not big deal if you do it first or last you will get confident anyways, and you will learn lots of insights on Design.
Stage 4 — Play with SOLID and choose your tools, use it as it works for you
Lately I’ve been using lots of Service Object. I see Service Objects everywhere, collaborating to solve problems, lately I tend to write single method classes like this:
I also use practices like East Oriented Code discussed as well on this book both references from Jim Gay, Tell don’t ask Principle and Command Query separation , “UseCase classes” to orchestrate several services that conform a real application Use Case, Extract Configuration and Strategy patterns as addressed by Sandi Metz in Practical Object Oriented Design. I use these as well: Null Object Pattern and Maybe Pattern, if you want to read more on both research on Monads; here is a nice Ruby gem for it with fantastic documentation.
It has worked for me so far, don’t be afraid to try some, you won’t regret it.
Stage 5 — Functional programming languages and functional principles along with SOLID
I want to make one last point: There are some cross-cutting concerns on OOD you need to take care of: multithreading and/or parallelism; you need deal with thread safety on your code. Lately, there is a trend for distributed computing, multithreading, multi-processing to overcome massive volumes of data applications usually handle nowadays, yes, you need to take care of it even if you are on Rails world. Using immutable state and predictable behavior is a solution I know for thread safety or race conditions, to achieve that on OO you need yo avoid side effects and modify attributes just on constructors, forget about side effect methods or setters, period, sometimes you will have to deal also with Locks or if you use modern technologies with Actor Models, but immutability is always the center.
Let’s consider these facts: I use immutable state as addressed above, Service Objects are actionable through one public method which avoids side effects, I chain several of them to accomplish tasks; so here comes an intriguing question: isn’t this style getting closer to Functional Programming (FP) principles?, Yes, as for me concerns I like to use some functional programming styles on my OO code, sounds wired but is true, even I’m eager to learn some FP languages such as Elixir and Elm, it seems that the functional approach works for me, it provides me valuable resources to write better code even on OO languages, there is a trend to adopt FP languages in the programming world, now I understand it. I have guided you on my journey this far, if you are at this stage too, I encourage you to go and try a functional language, do it or not you should be aware of main benefits explained here, whatever language you use.
Consider strategies to migrate your code from Monolith to a Micro-services design, it will improve your code base, it’s been successful for application architectures so let’s extrapolate the concept. Don’t ever think you got it perfect and polished, there is always room for improvement, don’t get stuck, never freeze, self-improvement is rewarding.
I hope this post has helped somehow, if so, please recommend it to reach out more people.