- What are microservices?
- What is monolithic code?
- Why would you choose the former or the latter architecture? Until what stage?
- Do they go hand in hand?
- Is one the opposite of the other?
- What is architecture?
- How “micro” should micro be?
These are all mind-boggling questions for a junior DevOps developer with a brain-frying learning curve. I will try to answer them for you based on my own research but first, let me paint the picture.
Everything starts with an idea. Even better if it’s a good one, right? You get up one day and figure it all out: You want to build an e-commerce website and sell meaningful products to people that might make a positive change. Or you simply want to make money, both require a complex full stack web app, that’s for sure. You sit down with your like-minded buddies, open your remote repository, start developing your web app and code pours out of the team.
That’s awesome! After about a week, you get the first running version up on localhost.
You are all junior developers and dive head first into the fray with no pads, no helmets, armed only with your enthusiasm. Even though the developer console is full of warnings and errors in the browser, you get the first whiff of success. You all open a few beers that evening and brainstorm ideas into the night. This is a pet project, so you have the luxury of time.
You don’t even think about hosting your project yet but that’s not in the scope of this article anyway. Last night’s brainstorming brought a sizable note of ideas which you compiled a to-do list of features to put in place and problems to solve. Let's begin!
Weeks go by, your web app looks promising, and features begin to appear and even work as intended. One of your friends, let’s call him Billy, realizes that the code base is getting bigger, like a thick boy, hard to manage. Without him knowing, he looks at this small thing called architecture. No, I don’t mean building bridges and skyscrapers. We are talking about software architecture.
Apparently, that exists as well, and you and the boys will feel its absence. So software architecture. After entering “help my codebase is becoming huge and difficult to handle" into the search bar, he stumbles upon this small thing known as microservices. He shares his findings with the team but everyone else is happy with the way things are going.
Everyone agrees that this will have to be dealt with some day but let that be tomorrow's problem. Modularity? Robustness? Ownership? Flexibility? Nah, not now. Let's focus on development. It's easier to test our code like this in any case, a monolith it is.
Poor Billy, they didn’t listen to him…
Some more weeks go by, and the project is looking even better but at this point managing the codebase is getting difficult. Not now, though, there is another idea! Let’s promote! The team agrees on implementing the typical buy one, get one free deal for the coming grand opening. How original.
You concluded that it would be easy to add some more logic to the cart function which subtracts the cost of the cheapest product. Easy-peasy lemon-squeezy! You commit, push and bang on your chest.
Your friend says that statistics are a must and he’s right, you all realize that it is needed to track sales impact. Wait a minute, this is a no brainer too, add some code into the cart logic that sets a Boolean to true in a new column of the sales database so you can track that the given sale was part of the promotion. Done and dusted, carry on.
Your other buddy discovers that it is beneficial to have this available only one time per customer. I mean, you don’t want to be bankrupt at the beginning, right? You need to flag your users somehow. So, another line of code in the cart function, another Boolean in the database, but we are still OK.
You also need to hide the promotion banner on the front-end for the users who have used this, send emails for those users who haven’t used the promo yet and while we are at it, making statistics of newsletters for marketing purposes would come in handy. These are all very effective ideas the team implemented. I mean, good job guys but there is a problem!
The team stares at the cart function with a cold poker face while the constant buzz of the fans in the computers grows ever louder in your heads. In addition, they realize that the cart function is over 500 lines of code. That’s too long, you think.
Also, remember that was one extra feature! The decision has been made, the app is live, and business flows in. What could make things wrong?
Well, a lot, apparently. After one year and some more features later, the transactions database grew way too large. A completely new and revised database is urgently needed. Unfortunately, the old database is referenced all over the code which also becomes completely unmanageable at this stage. Changing all the references to the new database is a major overhaul of the entire project and boom, goes the dynamite. It turns out the path of least resistance will only take you so far without major pain in the long run.
Now, the team could have listened to Billy, yes but I am not saying monolithic code is unsuitable. It’s about whether it is done right or chosen for a suitable use case. It is used only at a certain point during the first growth phase of a business. For some businesses with certain requirements and use cases it’s a wise choice even in the long run. You might have a burning question on your mind:
What is monolithic code?
This is a form of software architecture that refers to one standalone unified software application that is self-contained and depends on no other software application(s). The codebase itself usually exists in one repository, using a common build system and common libraries. It has three major components. Client-side user interface, server-side application and data interface, all interacting with one database. As you can guess, flexibility and loose coupling are not the order of the day here. The next thing on your mind is surely:
What is software architecture?
When we say software architecture, we refer to the fundamental structure, the skeleton of a software system. We also refer to the discipline of creating such structures and complex systems. It is the blueprint of an intricate software system where all structures consist of software elements, relations among them and properties of both elements and relations. This blueprint of the development project itself can be used to extrapolate the tasks necessary to be executed by teams, developers and all parties involved. Doesn’t that sound complicated and sexy at the same time?
Yeah. You could say it's a high level view, design and orchestration of an entire software system and development project. It is also a metaphor analogous to building architecture.
Let’s see what Billy was talking about in the beginning…
What are microservices?
Microservice architecture is an architectural pattern that structures a software application as a collection of loosely-coupled, fine-grained services. Microservices implement a very specific end-to-end domain or business capability within a certain context boundary. They are created and deployed independently. Imagine each service as a part of a software system or application with a single, limited responsibility based on the aforementioned pre-set context boundary.
Almost like an object in the OOP paradigm in this sense, in which all objects (among other principles) should have one, pre-defined responsibility built up on the SOLID programming principle. These objects/components also communicate with each other based on specific communication protocols and requirements. In contrast to monolithic architecture, we can see here that an entire system is divided into parts, like Lego blocks.
Flexibility and loose coupling are key parts of development discipline and design.
Let’s compare…
It's not exactly right to say that microservices are the opposite of monoliths. Instead, they are both different ways of designing software and solving problems while keeping requirements in mind.
In a nutshell, a monolithic architecture is suitable for simple applications that are not subject to change often or minimally. This includes word processors or most kernels like Linux OSs. Some of the advantages of this type of architecture are easier testing, debugging and simplicity. You only have one self-contained application to deploy, test and track. Doing the same with microservices-based software can be challenging and time-consuming.
Performance is a huge factor in which monolithic code excels as system calls can be made without the overhead of communication between individual components. One serious drawback is the one example above. It can get out of hand very quickly if it is chosen for the wrong use case or implemented poorly. Despite starting from scratch being easier and faster with a monolithic architecture, our story sums up all the disadvantages. Lack of flexibility, poor integrability with updated features or new technology.
What about reliability though? One single error or misconfiguration could bring down the entire web app like dominoes falling instead of one part breaking down but all else still functioning as intended. For example, if we are talking about separate microservices, if the reviews do not load because of a bug, customers could still use the site to make purchases or use other features. But, building a complex software system consisting of microservices can be tricky and very finicky.
Also, think about the higher and costly network usage and the time-consuming, extensive testing it would need. What about maintenance and operations? Both are long drawn out in both architectures. Maintainability of an overgrown and coupled monolith can be painful. However, running a complex microservice architecture system is generally more complicated due to its nature. It all comes down to choice. Where to use what architecture? Choose wisely.
To summarize, nothing is better than the other in a general sense. Both architectures have pros and cons, and they are two different worlds. Keep that in mind! Planning is key; you must plan your move forward.
Ask yourself: what are my exact goals and requirements? Do your research and then decide how to proceed. Give Billy a call. You might want him on your team, he’s smart.
How micro should micro be?
Oh, yes, the hot topic. You see, this can always spark a steamy debate among engineers and alike. Based on the knowledge I have gathered so far, I’ll place my bet below. First, the term microservices is a misnomer. What is “micro”? We are all unique human beings with different viewpoints and experiences, so it mostly depends on perspective and use case.
With this type of architecture there are no clear boundaries and no set rules to this either therefore, it would help me find my inner peace if we would just say: services but if not on this, we can agree on disagreeing.
I will call two of my closest allies for help again, the OOP paradigm and the SOLID principles. Great stuff! It is crucial not to get overboard with this. This means that making services “too small” defeats the purpose of modular code. The logic and data of your service should make sense as a whole, much like class data and its methods. To turn towards classes again for an excellent analogy, you could consider the file object in Java and all its methods.
You may .read() and .write() to your file objects, for example. Having a separate FileWriter or FileReader classes could be considered over-modularization and that means going overboard and your micro got way too micro. In a real life scenario, however, this is much more challenging and more complicated to see where that thin and fine line is between over-modularization and giving too large a scope to your services. This is why getting the size and scope of a job right is an art.
Don’t make them as small as possible for its sake. Some services can be enormous in lines of code. However, the most important thing to watch for is whether a single service performs two or more unrelated things. That will be your problem and a major headache later! As we saw from the hypothetical example of the boys and their e-commerce website above, taking the path of least resistance will only work at some point.
If you have to apply a change or add a feature that doesn’t fit in with one of your existing services, make a new one if it is possible.
Monoliths are an effective and simple way to start but services, otherwise known as microservices are a way to manage complex and mature or maturing systems and it can become a natural choice to move forward as the organization grows and adds to its business capabilities. Understanding how to keep or put in place systems in this architecture can help you stay competitive and make you more valuable to your company. That’s all, my peeps!
The moral of the story is always:
Do your research, think it through, expect the unexpected and have a plan.