
Should that be a microservice? Factors to keep in mind - jbkavungal
https://content.pivotal.io/blog/should-that-be-a-microservice-keep-these-six-factors-in-mind
======
dajonker
The article does not address any of the technical complexities of
microservices. If you use microservices you are developing a distributed
computing system with a lot of technical challenges: additional network delay
for each rpc, error propagation, consistency, etc. Addressing such technical
challenges will often consume lots of time and requires a lot of knowledge
that most developers do not have. It's a huge investment with a very high
risk.

Furthermore this article fails to list any sensible alternatives. For example,
if you have different rates of change you simply need a good separation of
concerns with clearly defined boundaries and interfaces. You can do this
equally well in a monolithic application, with none of the distributed
computing issues.

~~~
lugg
Agreed, microservices is literally a last resort in my book.

It's the thing you reach for when you're hiring a new team worth of developers
every other week and can't avoid developer blockage any other way.

It's not even a good architecture for most of the things it ends up being used
on.

There are very few problem sets that a microservices arch actually excells at.

Almost always a monolithic with some SOA and clear domain boundaries is going
to work better for static/slow growth teams.

It might be exciting for some but I wouldn't wish it on anyone.

~~~
dragonwriter
> Almost always a monolithic with some SOA and clear domain boundaries is
> going to work better for static/slow growth teams.

If it has “some SOA and clear domain boundaries” its not a monolith, even if
it isn't decomposed so far as to be microservices.

“Right-sized services” isn't a catchy meme-spreading label, but it's probably
the synthesis pointed to by microservices as the antithesis to monoliths.

~~~
lugg
Monolithic just means it can carry out all it's required functionality alone,
i.e. it's [major] dependencies are internalized.

It doesn't say anything about not being able to be broken into modularized
sections, services, or domain boundaries.

Neither does it reject any setups where satellite systems, micro or otherwise
make use of the monolith programmatically or otherwise, hell it's kond of part
of the definition of a monolith that it has multiple access points (i.e. cli,
sdk, rest, rpc, events.)

------
axaxs
I was an early preacher of microservices. In theory, it was great.
Independently scalable, rewriteable in any language, and of course a fault in
one piece won't bring down the others.

I learned the hard way what it really meant. A fault in one affects the
others. What should be a simple bug fix requires changing code and deploying
in multiple applications of various states of disrepair. A true nightmare.

In large enough teams for applications under development, I still think
microservices are a good choice. But for myself and my small team, monolith
applications are so much easier and faster to maintain.

~~~
staticassertion
You say you were using microservices, but you say that a bug in one service
led to redeploying many services. That sounds really odd, and like you weren't
doing microservices at all, but actually just a monolith with many pieces.

I think "Can I deploy a bugfix without redeploying the world" is one of the
base criteria for determining if you have implemented microservices or not.

~~~
speedplane
> You say you were using microservices, but you say that a bug in one service
> led to redeploying many services. That sounds really odd, and like you
> weren't doing microservices at all, but actually just a monolith with many
> pieces.

But the problem with microservices is that there is nothing to prevent you
from creating these types of potentially incompatible dependencies. If you are
separating functionality using functions, the compiler helps you spot
problems. If using classes or libraries, the linker can help spot problems.

With microservices, there aren't good tools for preventing these types of
problems from arising. Maybe one day Docker, kubernetes, or something else
will make it easy to create and enforce real boundaries. However, as long as
microservices are just an "idea" without a set of tools that help you enforce
that idea, it's very easy to introduce dependencies and bugs in ostensibly
"independent" microservices.

~~~
staticassertion
> But the problem with microservices is that there is nothing to prevent you
> from creating these types of potentially incompatible dependencies.

Sure, it's totally a matter of idiom - this is why I stated that a big problem
with microservices is people jumping into it thinking it's SOA. Microservices,
as a discipline, requires some care. It could be argued that the care required
is too high to be worth it though.

> If you are separating functionality using functions, the compiler helps you
> spot problems. If using classes or libraries, the linker can help spot
> problems.

Maybe you could be more specific? I don't see how a compiler will help prevent
coupling of modules/ internal components. What problems are you referring to?

I agree about microservices being an idea without an obvious implementation -
that's a fair criticism.

~~~
speedplane
>> If you are separating functionality using functions, the compiler helps you
spot problems.

> Maybe you could be more specific? I don't see how a compiler will help
> prevent coupling of modules/ internal components.

A super simple but effective way compilers prevent bad behavior is by
preventing circular includes/imports. In a programming language, if module A
imports module B, then module B can't easily import module A.* The
compiler/interpreter will complain about circular/infinite imports. This
general rule motivates developers to organize their code hierarchically, from
high level abstractions down to lower level, and militates against inter-
dependencies.

In contrast, there's nothing to stop microservice A from contacting
microservice B, which in turn contacts back to microservice A. It's so easy to
do, that many will do it without even realizing it. If you're developing
microservice B, you may not even know that microservice A is using it.

Designed correctly, microservices can be another great way to separate
functionality. The problem is actually designing them correctly, and keeping
that design enforced.

* Sure, there are ways of effectively doing circular imports in programming languages, but they usually require some active choice by the developer. It's hard to do it by accident.

------
jdleesmiller
I appreciate the effort that the authors have put in to synthesise all these
points into this article, but I think I disagree with almost every one of the
technical points.

1\. Multiple Rates of Change: Why must changing one module in a monolith take
longer than changing the same module in its own service? Perhaps a better use
of time would be to improve CI+CD on the monolith.

2\. Independent Life Cycles: Ditto. If the tests partition neatly across
modules, why not just run the tests for those modules? If they don't, not
running all your tests seems more likely to let bugs through, wasting the
investment in writing said tests.

3\. Independent Scalability: How bad is it to have a few more copies of the
code for account administration module loaded even if it's not serving a lot
of requests? The hot endpoints determine how many servers you need; the cold
ones don't matter much. And load is stochastic: what is hot and what is cold
will change over time and is not trivial to predict. If you separate the
services, you have to over-provision every service to account for its
variability individually, with no opportunity to take advantage of inversely
correlated loads on different modules in the monolith.

4\. Isolated Failure: Why not wrap the flaky external service in a library
within the monolith? And if another persistence store is needed to cache, it
is no harder to hook that up to a monolith.

5\. Simplify Interactions: Ditto. The Façade pattern works just as well in a
library.

6\. Freedom to choose the right tech: This is true, but as they say having all
these extra technologies comes with a lot of extra dev training, dev hiring
and ops costs. Maybe it would have been better to use a 'second best'
technology that the team already has rather than the best technology that it
doesn't, once those costs are accounted for.

The cultural points are largely valid for large organisations, but I feel like
it positions microservices as an antidote to waterfall methods and long
release cycles, which I think could be more effectively addressed with agile
practices and CI+CD. Splitting out a service might certainly be a good way for
a large organisation to experiment with those practices, however.

~~~
mwcampbell
> 6\. Freedom to choose the right tech: This is true, but as they say having
> all these extra technologies comes with a lot of extra dev training, dev
> hiring and ops costs. Maybe it would have been better to use a 'second best'
> technology that the team already has rather than the best technology that it
> doesn't, once those costs are accounted for.

A variation of this pushed me to implement a couple parts of an application as
micro-services even though I wanted to stick with a monolith. I wanted to use
existing open-source packages written in languages other than the primary one
that I had chosen for my monolith. It's really a shame that a cross-language,
in-process ABI like COM didn't catch on outside of Windows.

~~~
lalaland1125
A cross language, in process ABI does exist for all platforms. It's called the
C ABI. Almost every programming language can export and import C ABI functions
and data.

~~~
mwcampbell
Sure, but that's lower level than COM or WinRT. And in practice, does anyone
embed, say, a Node.js module inside a JVM application via a C library?

------
Daishiman
This all looks good on paper.

In practice, this assumes that all of the concerns presented there will
necessarily become bottlenecks. And that is simply not true.

You can have modules with completely different deployment lifecycles, speed of
development and performance characteristics as part of a single service and,
for the most part, things will be totally fine.

This really reeks of premature optimization. A badly separated service is a
gigantic hassle down the line.

In general, service boundaries become obvious to developers when they start
seeing the friction. But the default answer should always be a no unless there
is proof that friction is there. The overhead of maintaining multiple
services, repos, CIs and so on is not trivial for s team of 10 people or less.

~~~
threeseed
It really is trivial to automate the process of creating a new service with a
corresponding repo and CI pipeline. And with tools like giter8 it's not that
hard to standardise on service layout and components as well. You could easily
do it in a few hours.

Likewise just using modules looks good on paper but in practice most languages
make it too easy to reference code in other modules. And so very quickly you
end up with spaghetti code. So regardless of whether you use modules or
services you still need to do a lot of upfront work in setting and enforcing
some design/architectural rules.

~~~
clintonb
Agreed. We built cookiecutter templates at edX for the basic Django service
and Ansible playbook. We built shared libraries for OAuth and other shared
functionality.

That said, much of this did not come into place until we were on the third
microservice. Starting with templates and libraries for the very first service
would have definitely been premature optimization, and have resulted in wasted
time and later rework.

------
not_kurt_godel
I would agree people are a bit too enthusiastic about microservices these
days. The stack I work on is, IMO, broken into too many microservices
(admittedly, I had a large part in the decisions that resulted in that). I
wouldn't say it's made things terrible but it has slowed down velocity and
makes the system as a whole harder to reason about. If I were to re-architect
from scratch, I'd probably slash about at least a third of the microservices
we have. In the future I'd be inclined to keep sufficiently modular such that
various components could be broken out as separate services if needed, but
only do so if compelling reasons to do so presented themselves.

~~~
mooreds
So would you consider more of an SOA approach in the future, as compared to
micro services?

Also, when your team architected the microservices originally, how many
previous microservices systems had y'all built? I haven't built any and am
just trying to get a feel for the learning curve.

~~~
lucidone
As someone on a dev team with little experience with microservices, including
myself initially, you're going to make a big mess before you know how to clean
it up. Take eventual consistency seriously. Limit rpc across services as much
as possible. Agree on standards and your source of truth as early as possible.
CI/CD the small stuff that doesn't matter (linting, test running). Also, have
a good integration/e2e testing set up early - mock tests ended up being very
brittle for us.

~~~
not_kurt_godel
Agree with all of this, especially:

> have a good integration/e2e testing set up early - mock tests ended up being
> very brittle for us.

Unfortunately microservices also can make good integration testing difficult
when it comes to testing full e2e functionality. The results of testing e2e,
by nature, rely on the sum of the services interacting with each other
properly, thus creating testing dependencies between services that negate some
of the advantages of having separated them in the first place.

------
jupp0r
Is it only me or are they missing the most important question: will this
service have an API that provides a reasonable abstraction and is stable
enough to provide backwards compatibility to its consumers?

If not, a lot of the independent deployment niceness will become a major
nightmare when consumers of the service's API need to be adapted (if that's
even possible).

------
flibble
> Independent Scalability

This reason for microservices comes up over and over but I’ve never understood
it.

If you scale a monolith, only the hot code paths will use any resources.
Having a monolith makes it _easier_ to scale as you can just scale a single
app and it will be perfectly utilized. If you have microservices you need to
make sure every single one has headroom for increased load.

Scaling up a whole monolith only to increase capacity for one code path
doesn’t have any unnecessary overhead as far as I can see. Remembering that if
your microservice is on a VM then you are scaling up the OS too which has
millions of lines of code - something no one (rightly) is concerned about.

Am I missing something?

~~~
IneffablePigeon
I think you're right that this point is often overstated.

It does isolate each service from the scaling _issues_ of the others somewhat
- if one service gets overloaded and crashes or hangs then other components
are less likely to get brought down with it. In the best case if work is
piling onto a queue and the overloaded component can be scaled fast enough
even dependent components might not notice too much disruption.

Another advantage is that you can scale the hardware in heterogeneous ways -
one part of the app may need fast I/O and the rest of the app might not care
about disk speed much at all, so you can have different hardware for those
components without overspending on the storage for the rest of the app. I
think that's a minor advantage in most cases though.

A sort of in-between house is to have multiple copies of a monolith which are
specialised through load balancing and/or configuration values and put onto
different hardware, but all running the same code. Probably not that widely
useful a technique but one that we've found useful when running similar long
running tasks in both interactive and scheduled contexts.

------
redact207
DDD isn't synonymous with microservices. Although it does help decouple a lot
of your internal components so that they _can_ be split into isolated services
later on, there's nothing stopping you from hosting them in a single monolith.
In fact there's very little downside of doing it that way.

The number of merge conflicts is reduced because the code has good internal
separation. Scaling can be done on the entirity of the monolith that is
simpler than trying to do this on a microservice level.

I'm working on a DDD typescript framework at
[https://www.npmjs.com/package/@node-
ts/ddd](https://www.npmjs.com/package/@node-ts/ddd) that helps better
structure node apps for domain driven design

------
bvrmn
There is a 7th main factor. You should have multiple teams. It's sad how most
of pro-microservice articles forget to mention this point explicitly. For most
IT companies microservices don't make sense at all.

~~~
majewsky
Exactly this. Conway's Law should be taken not as an observation, but as
advice. "Sure, you can have a service structure that doesn't match your org
structure, but it's gonna cost ya."

------
bdcravens
It’s worth noting that you can accomplish a lot of the same goals via a single
repo but separate out execution and deployment with distinct Dockerfiles.

~~~
scarface74
It’s still over complicating things. If you just want a separation of
concerns, reduced merge conflicts, and the optionality of separating a module
out into a separate microservice later, you can accomplish that a lot easier
in a monorepo with (speaking in C# terms, choose the equivalent for your
language of choice) one solution, separate projects for separate “services”
(domain contexts), exposing the assembly/module via public interfaces and
using DI.

------
eskpe
The problem is that you will not be able to run a monolith without a
microservice. In fact, you'd be able to run an entire project without a lot of
trouble. This is so much easier to debug and debug. Even with simple tools,
it's almost impossible to debug code without refactoring a few dozen layers
and building up another microservice. The question is what does the
microservice plan on doing? When it needs to scale, it's an issue of how much
time is spent on the development of the project. If the micro service plan is
a waste of time, it will be a problem. This is especially true if you only
have 2 servers running the microservice, and you can use docker containers to
build and maintain your own servers which support everything (apache, docker);
for your projects, it probably takes less than 5 minutes to figure it out, and
when you start getting serious about running them with one or more different
pieces of infrastructure you don't think twice about spending that much time
in production. I'm not a huge fan of microservices: I think they will be hard
to scale even before they become more of a problem.

~~~
speedplane
A microservice seems to be just another level of abstraction. They follow in
line from functions, to classes, modules, packages, and libraries. It's just
the next higher level of abstraction, this time separated by network calls.

The positive side of microservies is that they can be scaled and updated
independently. The inherit downside is that adding network calls can add race
conditions and failure states.

However, the real trouble with microservices starts when they are misused. If
service A calls to service B which calls to service C, which in turn modifies
the state of service A, you can easily enter a world of pain. This type of
behavior can happen with any abstraction (e.g., functions, classes, modules),
but unfortunately, it is very easy to do with microservices, and happens all
the time.

I do like the idea of separating truly independent services for scaling, but
today we still need a better way to enforce or clarify that separation so that
these types of dangerous dependencies don't creep up.

Just spit-balling here, but this type of dependency enforcement could happen
at the container or container orchestration level. Perhaps Docker or
kubernetes could prevent a service from accessing a resource if another
upstream service accessed that same service.

If you need two services that talk to each other to also read and write to
another service, you aren't really building microservices, you're building a
distributed system.

------
bcrosby95
I've never quite understood the logic behind #3. Why wouldn't I just scale my
monolith up and down instead? I could see some instances where being able to
do it independently would be useful (e.g. when the feature has unique resource
requirements), but I would guess that, for us, 9 out of 10 times, it has been
fine to just scale the monolith as a whole up and down as necessary.

~~~
staticassertion
Cost is the easy answer - as with any optimization, I guess.

It can also be really annoying sometimes to scale a monolith - a big one can
have a lot of different parts like multiple threadpools/ database pools. One
component hits a threshold, you add more instances, now your other component
is overprovisioned, maybe even failing due to too many DB connections, or you
hit weird thread contention issues.

I've had some pain in the past scaling monoliths in similar situations.

------
Animats
I just installed a Python package for a chatbot. Here are its dependencies:

"Installing collected packages: asn1crypto, six, pycparser, cffi,
cryptography, PyMySQL, future, certifi, python-telegram-bot, beautifulsoup4,
idna, urllib3, chardet, requests, wikipedia, lxml, requests-toolbelt,
pymessenger, autocorrect, line-bot-sdk, click, Werkzeug, itsdangerous,
MarkupSafe, Jinja2, Flask, python-engineio, python-socketio, Flask-SocketIO,
pymongo, PyYAML, pytz, tzlocal, setuptools, APScheduler, SQLAlchemy, kik,
nltk, textblob, emoji, PyJWT, pysocks, twilio, websocket-client, slackclient,
oauthlib, requests-oauthlib, tweepy, wget, MetOffer, redis, viberbot, python-
dateutil, sleekxmpp, programy".

Monolithic package. Has nailed-in support for all possible ways to communicate
with it.

I'd be happier if the part that does the work was decoupled from all those
interfaces. Especially after struggling with a build problem where it was
building its own crypto library.

------
bartimus
I'm still not convinced microservices and SOA are different paradigms. We were
doing SOA with REST ages ago. Everything always boils down to common sense. It
seems to me both paradigms lead to similar results.

Microservices are just a buzzword for the same thing we did before using
current day technologies (node instances, cloud, Docker, Kubernetes,
serverless etc).

------
cperciva
I'll add another: Is it independently reusable?

Even if _you_ aren't going to use it for something else, separating some of
your code and releasing it as open source is a great way to get more people to
test it -- and find bugs before they affect you in production.

~~~
clintonb
This depends on what you are releasing, and how much support you’re willing to
offer to the community. For example, the microservices and libraries I worked
on at edX were used by the Open edX community, but rarely at the scale at
which edX uses them. The community offered new features, but edX did much of
the big fixing because we had more extensive knowledge and use of the
software.

~~~
mooreds
Is this a microservices issue or a scale issue in general? Seems like any open
source tool that had users that operated at different scales would run into
this issue, no matter the architecture, but I don't know what I am missing.

~~~
clintonb
Project scale and scope. edX does most of its development in public repos. Not
all of the features and functionality are used by every open source user. The
scale of edX’s user base is so much larger than others’ that edX finds issues
well before other users. Also, by the time a formal Open edX release is
announced, edX has run the code for weeks or months.

------
aryehof
For me the question remains... should a particular set of functionality be
written as a "separate program". After all, isn't a microservice just an
independent program that communicates with others using an industry standard
protocol?

------
jrs95
Should you even use microservices? I'd argue probably not. In my experience
most people start looking at this because they hate their existing code (often
for good reason) and just want to spend less time working with that code. It's
just easier to do than refactor a monolith with serious problems...but then
you have all the issues of a distributed system, and it's never been worth it
in my experience.

If you find yourself in this situation, I'd recommend identifying the problems
you have with your current monolith and hopefully refactor it, otherwise it's
a lot more sane to gradually migrate to a new monolith by slowly moving
responsibilities to it rather than attempting to go down the microservices
route.

------
davidhyde
I am convinced that I am doomed to spend the next 10 years of my professional
career converting micro services back into monoliths. 5 of those years will
have to be incognito because microservices are not quite considered over just
yet. it has already begun.

------
discreteevent
It's interesting that this [1] came up just a couple of days ago. Just like
Linux 90% of the problems that microservices are trying to solve can be solved
with modules and not have the non-trivial problems that microservices
introduce.

[1]
[https://news.ycombinator.com/item?id=19689341](https://news.ycombinator.com/item?id=19689341)

------
skrebbel
I know Betteridge's law of headlines wasn't designed for titles like this one,
but it's pretty on point.

