
Microservices for the Grumpy Neckbeard - spindritf
http://www.chrisstucchio.com/blog/2014/microservices_for_the_grumpy_neckbeard.html
======
hibikir
As Chris says, in practice microservices are not really much different than
using service objects, or Akka actors: They are just a form of enforced
encapsulation, which is just happens to bring the advantages and disadvantages
of always going over a network.

The disadvantages of always paying for network costs are extremely steep, so
the minute you care about latency, either because there's a user on one side,
or because every second you wait is more money thrown the way of AWS, making
everything a microservice quickly becomes a bad tradeoff for most
applications. All the real advantages of microservices only start to pay off
at scales that you'll only reach in a few handful of companies.

I am thinking of a small startup, that had a big proponent of microservices as
the tech lead, which boldly went all in with this architecture, before any of
the real advantages of microservices ever came into play. WHen they went to
production the first time, they saw everything was slow, and quickly started
to colocate said microservices in the same machines, and made them talk to
each other directly, without serialization. In other words, they reimplemented
EJB local interfaces. At some point in this process, the microservices
champion left.

So now they have hundreds of little faux services, and instead of a monolith,
they have to worry about what happens when someone wants to change the
contract of one of those services. A ball of yarn, by a different name.
Instead of wondering whether the code will compile if they make a change, they
wonder whether it will run, in practice.

It sounds to me like they are not in any better a shape than if they had built
a monolith anyway, other than the fact that their employees can now claim they
have microservice experience.

If we go back to basics, maintainability comes down to getting lucky with your
selection of abstractions, and trying to minimize coupling. If your
abstractions are wrong, your modularization will be either incorrect or just
lacking overall, and no architectural pattern will save you.

~~~
jshen
I agree with the bulk of your comment, and want to add one thing you didn't
mention. Micro services allow you to scale the size of your engineering team.
We started with a monolith at my company and as the engineering team grew from
5 to ~50 we started pulling out independent pieces and making them services
that a team of ~5 could own, and it has worked out well.

~~~
yummyfajitas
You can do the exact same thing with service objects. You can probably also
get away with smaller teams, since most teams don't need to worry about
devops.

~~~
kyllo
But doesn't that just put you right back into RPC-land, where you don't even
know whether a method call is local or over the network, because the interface
is the same?

And if you take the suggested alternative of wrapping the return values in
'Future', then your interface just changed, so now the code that calls your
service all needs to be rewritten.

It's pretty well established that service calls are either local or remote,
and the service interface should show the difference between the two, but that
means means that changing a service from local to remote is always going to
break its clients.

That's a pain point, but it's probably better than _making every service call
remote by default_ which is what a microservices architecture does.

------
SomeCallMeTim
Isn't this just Object Oriented API Design 101?

I kept reading, looking for the punch line, but as far as I can tell he's just
describing really basic information hiding and interface design.

Maybe it's OOD For Server Programmers? There's nothing _wrong_ with it, it's
just surprising to me that it's news.

~~~
yummyfajitas
The only punch line is "hey microservice hipsters, those uncool Enterprise
Java guys already solved this problem."

~~~
valarauca1
Hasn't that been the punch line of the last 10 years of tech?

"Oh hey data hipsters, no I'm sorry our SQL data base is 200TB, no we don't
have performance problems."

"Oh no we don't need your functional restless framework, we've been using a
java framework for like 10 years, it peaks out at 1000 req/s."

"Why would we buy 4 webservers? It has 4 nics, and 8 CPU sockets. Sure it
costs 500k each, but then we can keep using our java framework."

~~~
danielweber
I find it useful to read articles by someone who will translate from hipster
to crotchety-unix-grey-beard for me.

~~~
valarauca1
c2wiki does that for you ^-^

------
amirmc
I wonder whether all the people talking about microservices have come across
the unikernel approach (c.f Mirage OS [1, 2]). It seems like these two ideas,
at some level, fit quite well together.

[1]
[http://queue.acm.org/detail.cfm?id=2566628](http://queue.acm.org/detail.cfm?id=2566628)

[2] [http://openmirage.org](http://openmirage.org)

~~~
sgrove
I was thinking the same way - taken to the extreme, they both seem to
converge.

------
tel
The scariest thing mentioned here is when Team Email switches from a Service
Object to a Micro Service. Actually, it's not that scary as part of email
where the user of that object always anticipates potential failure (and
probably has next to no recourse if failure occurs).

So instead we could pretend that it's something like MachineLearningProvider.
When this converts to a Micro Service its failure space increases by an order
of magnitude _without expressing it in the interface_.

That was the primary problem with RPC—you really don't want to confuse local
function calls from remote ones.

~~~
yummyfajitas
This is generally solved with monadic design. Results are returned wrapped in
some monad - Future[Result] in this case. The monad generally expresses the
failure modes.

When you switch from, e.g. `LocalMachineLearningProvider` to
`RemoteMachineLearningProvider`, your interface will change from
MachineLearningResult to Future[MachineLearningResult].

~~~
tel
Certainly, or even with two layers of futures. Notably, this changes the
interface.

I'm not saying it's not solvable, just that it was so silently mentioned in
the article. You should have to work to reproof your code after RPCing
something.

It can just be scary if you've spent time making it out as though
MchineLearningProvider can never fail. Interacting with an outside object can
be a painful experience.

This gives you some of the worries of a true distributed system within your
monolith.

~~~
yummyfajitas
If only there were a way of transforming F[F[X]] to F[X]. Then we could avoid
nested futures!

~~~
tel
You're being sarcastic, but I meant to suggest that there would be value in
running those layers independently so that you don't combine errors. If you
present it as F[X] then you've thrown away potentially interesting
information. IO (IO ()) is pretty valuable, for instance.

~~~
yummyfajitas
Just curious, what is the advantage? Near as I can tell EmailProvider will
return one of two sorts of errors - either a ServiceError (the microservice
was unable to send) or a NetworkError (unable to talk to micro service). These
will be represented in the class of the exception the future wraps.

What benefit does two levels of futures provide? I was sarcastic before, but
now I'm honestly asking.

~~~
yummyfajitas
Tel I have no idea why, but your reply is dead. It is a good answer, however,
and provides me with food for thought.

~~~
tel
Strange. I see it appearing twice. I will try deleting one.

------
alexchamberlain
Although generally they are, microservices don't have to be accessed over the
network: they could use shared memory or Unix domain sockets, for example. As
others have mentioned, JSON-over-HTTP is only one of many options.

------
kasey_junk
I think one of the differences between service objects and services (never
mind the micro-service distinction) is the language agnostic nature of
services (and the idea that services can be written in the language that best
solves their problem).

If you are assuming a fixed language (or at least fixed interoperability) the
post rings true. If not, there service objects are clearly not appropriate.

~~~
discreteevent
If you were starting a project do you think it would ever be a good idea to
write parts of out in different languages? Surely if you think a language is
good then it's good enough for most things and the advantages of having a
common language (review, experience, transferring devs, cognitive overhead
etc) outweigh the benefits of using the perfect language for every task (even
if you could get people to agree on what each language is - it will be hard
enough to get them to agree on one)

~~~
kasey_junk
So I have several responses to that.

\- Lots and lots of large systems are decomposed across different languages
based on the advantages they have. Some parts of the system may be extremely
latency sensitive and therefore can't afford GC based languages, other parts
may need to interact with existing enterprise systems and therefore are best
written in Java or the .NET stack. A very common split is amongst quantitative
developers who prefer languages like python vs other developers that prefer
something else. So basically yes, there are times that I've worked on systems
that were designed from the ground up to use different languages (or should
have been). That said, of course you want to make sure you aren't adding
complexity for it's own sake and a unified language is usually better.

\- A very common use of service architectures is not green field development.
It is in migrating from legacy systems or augmenting them. Lots of large web
based systems were originally written as monoliths on the LAMP stack or as
Perl/CGI. As they grow it becomes obvious that scaling will require different
technology choices, but it is almost always a mistake to do a full rewrite. In
those cases, language agnosticism can be a real boon as you can ramp up in
languages that are more popular at the time of need (or in languages that
allow you to attract good developers).

------
techmatters
I have come to the conclusion, over many years, that microservices are simply
a runtime solution to a compile-time problem. Why can we not develop code in a
modular way (to separate concerns & isolate) , but deploy it in a monolithic
way (to reduce latency/reliability concerns). This is what we did when OO was
fashionable.

I understand that we shouldn't treat RPCs like local calls, but that doesn't
mean we cannot do the reverse. If we design services properly we don't need to
tie the design and the deployment.

I just can't see the purpose of making something permanently flaky at runtime
for the sole purpose of keeping developers on track at design time.

------
cdnsteve
To clarify Microservices please have a read of Martin Folwer's article:
[http://martinfowler.com/articles/microservices.html](http://martinfowler.com/articles/microservices.html)

In particular, I like this quote: "The second approach in common use is
messaging over a lightweight message bus. The infrastructure chosen is
typically dumb (dumb as in acts as a message router only) - simple
implementations such as RabbitMQ or ZeroMQ don't do much more than provide a
reliable asynchronous fabric - the smarts still live in the end points that
are producing and consuming messages; in the services."

------
mercnet
I am still trying to wrap my head around microservers and maybe someone can
help me. Say we are building a blog platform.

1\. Would it be separated into the following services: user, post, and
comments?

2\. If I was designing this in flask or django, would each service be running
on localhost with different ports, e.g. user is localhost:8080, post is
localhost:8081, etc?

For my personal flask project, I am currently following this style
[http://mattupstate.com/python/2013/06/26/how-i-structure-
my-...](http://mattupstate.com/python/2013/06/26/how-i-structure-my-flask-
applications.html) with service layers.

~~~
derefr
> 1\. Would it be separated into the following services: user, post, and
> comments?

No; posts and comments would likely be provided by the same service. Users, on
the other hand, are likely an abstract idea implemented across several
services (an authentication service, a profile service, etc.)

An easy way to think about it: if your business logic needs to do the
equivalent of an SQL JOIN on data from both A and B to compute some common
query (e.g. displaying a page with a post and comments on it), then A and B
likely belong to the same service.

If, on the other hand, you have data/state that can be encapsulated into its
own black box that none of the rest of the code needs to know the internal
structure of (e.g. user authentication information: password hashes, 2FA token
seeds, session IDs, etc.) then that data/state can be isolated to its own
service.

~~~
djur
Using separate services for posts and comments is incredibly common, though,
considering how many sites use a third-party service like Disqus or Facebook
to provide comments. If you're expecting to load comments in JavaScript (which
is really common these days to reduce load time and the impact of link
spamming), implementing comments as a separate service where groups of
comments are keyed by origin URL or article ID is a no-brainer.

~~~
derefr
True. I was more imagining discussion sites like this one, where a post is
basically just a special parentless comment that's rendered differently, and
all normalized tables that connect to one also connect to the other (e.g. both
posts and comments are associated with a user profile, both posts and comments
have a point score, etc.).

On a plain blog, where "people who post" and "people who comment" are
basically disjoint sets, comments can indeed be separated out into their own
service, which may indeed be a gateway implemented by a third-party RPC
consumer object.

------
ilaksh
I think that eventually we will move towards defining the whole system in a
high level way that is independent of the languages, whether it is a service
object/RPC or microservice, etc. In order to do that you need define the
programming languages, databases, web servers, and web services using a common
meta-language or interchange format based on some type of knowledge
representation. To make things practical there will be the capability to work
with the systems in your preferred representation and then translate back into
the common metalanguage.

~~~
tdicola
Let's call it the common object request broker architecture or CORBA for
short. Someone check if anyone is using that name already.

~~~
ilaksh
That's the right context but I think we need to eventually go to a higher
level with some type of common bidrectional knowledge representation
([http://en.m.wikipedia.org/wiki/Knowledge_representation_and_...](http://en.m.wikipedia.org/wiki/Knowledge_representation_and_reasoning))
scheme that can underpin not only interfaces but all information system layers
and representations.

~~~
fleitz
Corba is an architecture astronauts wet Dream, to go any higher would result
in negative vaccum.

------
krschultz
Certainly there are solid points here, but he doesn't really address the ops
side of the equation. I wouldn't write a bunch of microservices on day 1 at a
startup with no traffic. I have no doubt it is more complex than a monolith
for development & operations. I have no doubt that it introduces a bunch of
extra network related overhead..

But what happens when you have serious traffic? One of the main benefits of
microservices is splitting the system up for deployment & provisioning. One
particular part of the system might be very memory heavy, you can deploy it on
a cluster of machines that are spec'ed appropriately. One part of the system
might have a relatively constant workload so you can put it on dedicated
hardware, while other parts might be cyclical and you can spin up and down
instances to match traffic. You can deploy particular components independently
which makes releases a much smaller affair.

These things are not impossible with monoliths, but they are easier with
microservices. So if the bigger pain point is deployment, scale, etc and not
writing new code, then microservices might be a good choice.

~~~
yummyfajitas
In many cases you can do everything you just described by sharding the
monolith. Instead of putting 100% of an EmailService on 1 box, put 10% of it
on 10 boxes which are also running a web service 10%, an auth service 10%,
etc. This will give you logical separation and reduce latency.

Obviously I'm not advocating making a postgres (lots of seeks) server share
disks with a hadoop server (lots of spinning). That's silly. I'm advocating
sticking with service objects until you have a good reason not to.

~~~
discreteevent
Exactly, that seems to be the point of the article. Starting with micro
services is plain old over-engineering (reminds me of the original J2EE which
I managed to avoid) but using a service object still leaves you free to
distribute if and when you need to.

------
SideburnsOfDoom
> "exposed via a json-over-http protocol"

Sigh. The use of json format is not necessary or sufficient make the service
"micro".

There's this thing called "content-negotiation". IMHO, Any http web service
framework worth using just does it. This means that the "xml or json" issues
are fixed before they start. Unless you really want to have that trouble
later.

~~~
rurounijones
He says that it is an ill-defined term then goes on with _So for the purposes
of this article_ he will use json-over-http.

The actual method (json-over-http-, thrift-over-infiniband, best practices
regarding conten-negotiation) is not the point of the article.

So to keep things simple _for the purposes of an article_ he uses probably the
most common method; is that really cause for a self-aggrandizing snarky
comment?

~~~
SideburnsOfDoom
> is that really cause for a self-aggrandizing snarky comment?

I think it is worth addressing this. In my day job we are dealing with the
ongoing effects of not doing http content negotiation a while back, and an
article that perpetuates bad practices (even by the omission of simply failing
to mention anything else because it's not the point of the article) is not
helpful.

------
johnrob
Regardless of how the code is written, the 'at scale' system will need to
physically resemble the microservice model. Once you have tens, hundreds, or
more servers you are forced to group things by service. The alternative would
cause massive data consistency delays from the sharding required to reduce
network traffic.

------
tel
It's worth noting that even if all you have is a bunch of SOs floating around
in the same "monolith" you still have a "distributed system" of a kind. You
(probably) will never have to worry about partitions, but your state space is
still going to be the multiple of all of your independent stateful threads.

Obviously the solution would be to ensure that most SOs don't actually
maintain much internal state to the greatest degree they can. This can be
partially solved by abstracting out certain stateful primitives into other
service objects—achieve this with dependency injection, perhaps.

------
lnanek2
Not to mention that services can participate in transactions and rollbacks a
lot easier. Doing that with web services involves getting a ton of wacky
protocols like WS-AtomicTransaction working, which many back ends simply don't
support or don't support well.

~~~
shanemhansen
The fact that something called WS-AtomicTransaction even exists is terrifying.
I thank $diety I don't have to deal with that sort of stack.

------
jiggy2011
Microservices as described here sound like a lot like Actors to me.

------
gone35
_Neckbeard._

I understand the semantic emphasis (and appeal) of 'neckbeard'/'graybeard' in
the IT subculture is patently on expertise/oldschoolness, not on gender at all
--hell, I've used that noun with gusto myself with barely any thought about
the person's gender.

Yet, given the (by no means conclusive, but increasingly socially accepted)
evidence that using implicitly-gendered words like that can be, at best,
tacitly exclusionary to some degree --like equating 'balls' with
courage/determination, or refering to 'man' as humankind--; perhaps one
should, at the very least, pause and reflect on whether the amusingness of
'neckbeard' is, in this particular context, worth its use.

~~~
Nursie
It's an insult, so it's sort-of exclusionary by default. It refers to those
nerdy guys who don't know how to dress themselves, compulsively collect arcane
knowledge and probably smell bad.

Maybe we ought to come up with a female stereotype to match, or a genderless
one. Or maybe this will do just fine - you don't want to be a 'neckbeard'
regardless of gender, it's not a good thing.

~~~
rancor
There is a term for the female equivalent, namely the elusive 'legbeard'.

