News for hackers. Stuff that matters.
Re:“It's The Future” by nicolas_t on Wednesday August 17, 2016 @06:36AM (#12303587)
I think that splitting into micro services is valuable if and only if you reach a scale where it makes sense to split into micro services. By scale, I mean the number of people on the team (if you have a lot of people, it can make sense to split into micro-services to limit communication bottlenecks between developers) or in term of traffic, in which case microservices can be very useful to better optimize the system piece by piece.

A small team starting a new project should not waste a single second considering microservices unless there's something that is so completely obviously decoupled in a way that not splitting it into a microservice will lead to extra work. It's also way easier to split into microservices after the fact than when you're developing a new app and you don't have a clue how it will look like or what the overall structure of the app will be in a year (most common case for startups).

Re:“It's The Future” by jules on Wednesday August 17, 2016 @08:18AM (#12304084)
In practice micro services mean that you turn a function or method call into a network request. This doesn't really limit communication bottlenecks. It is often more difficult to argee on a network interface than on a simple function or object interface. It's also more difficult to change. You introduce a whole new set of failure modes due to going over the network. Debugging is more difficult since you now can no longer step through your program in a debugger but rather have an opaque network request that you can't step into. You can no longer use editor/IDE features like go to definition. It becomes harder to do integration tests. Version control becomes harder if the different services are in different repositories. A network request is much slower than a function call. You no longer have the advantage of a garbage collector for logical values that now cross network boundaries, and rather need to manually free them. Deployment is more difficult. The list is much longer than this, but I'd be interested in the counter-list: what are the advantages of micro-services?
Re:“It's The Future” by wtbob on Wednesday August 17, 2016 @09:32AM (#12304513)
> You introduce a whole new set of failure modes due to going over the network.

A thousand times yes. Distributed systems are hard.

> Debugging is more difficult since you now can no longer step through your program in a debugger but rather have an opaque network request that you can't step into.

Yes. Folks underestimate how difficult this can be.

In theory it should be possible to have tooling to fix this, but I've not seen it in practice.

> You can no longer use editor/IDE features like go to definition.

Not a problem with a good editor.

> Version control becomes harder if the different services are in different repositories.

No organisation should have more than one regular-use repo (special-use repos, of course, are special). Multiple repos are a smell.

Re:“It's The Future” by dietrichepp on Wednesday August 17, 2016 @09:52AM (#12304662)
> No organisation should have more than one regular-use repo (special-use repos, of course, are special). Multiple repos are a smell.

I would modify this slightly. Larger organizations with independent teams may want to run on per-team repos. Conway's law is an observation about code structure but it sometimes also makes good practice for code organization. And of course, sometimes the smell is "this company is organized pathologically".

Another problem is that large monolithic repositories can be difficult to manage with currently available software. Git is no panacea and Perforce isn't either.

Re:“It's The Future” by pc86 on Wednesday August 17, 2016 @09:53AM (#12304672)
> No organisation should have more than one regular-use repo

Flat out wrong for any organization with multiple products. Which, let's be honest, is most of them.

Re:“It's The Future” by dietrichepp on Wednesday August 17, 2016 @10:12AM (#12304805)
I guess Facebook, Twitter, and Google are doing things "flat out wrong", then. Yes, that's a weak argument (argument from authority) but it is true that monolithic repositories have major advantages even for organizations with multiple products. Common libraries and infrastructure are much easier to work with in monolithic repositories.

My personal take on it, at this point, is that much of our knowledge of how to manage projects (things like individual project repos, semantic versioning, et cetera) is centered on the open-source world of a million mostly-independent programmers. Things change when you work in larger organizations with multiple projects. You even start to revisit basic ideas like semantic versioning in favor of other techniques like using CI across your entire codebase.

Re:“It's The Future” by lobster_johnson on Wednesday August 17, 2016 @12:47PM (#12306056)
Those are huge organizations with commensurately large developer resources, and they simply work at a different scale than most people on HN. "It works for Google" is not an argument for anything.

Monorepos come with their own challenges. For example, if any of your code is open source (which means it must be hosted separately, e.g. on Github), you have to sync the open-source version with your private monorepo version.

Monorepo are large. Having to pull and rebase against unrelated changes on every sync puts an onerous burden on devs. When you're remote and on the road, bandwidth can block your ability to even pull.

And if you're going to do it like Google, you'll vendor everything -- absolutely everything (Go packages, Java libraries, NPM modules, C++ libraries) -- which requires a whole tool chain to be built to handle syncing with upstream, as well as a rigid workflow to prevent your private, vendored fork from drifting away from upstream.

There are benefits to both approaches. There is no "one right way".

Re:“It's The Future” by dietrichepp on Wednesday August 17, 2016 @04:34PM (#12308236)
It seems we agree, we are both claiming that "there is no one right way".

I love Git, and I used submodules for years in personal projects. It started with a few support libraries shared between projects, or common scripts for deployment, but it quickly ballooned into a mess. I'm in the process of moving related personal projects to a monolithic repository, and in the process I'm giving up the ability to tag versions of individual projects or provide simple GitHub links to share my code.

Based on these experiences, I honestly think that the only major problem with monolithic repositories is that the software isn't good at handling it, and this problem could be solved with better software. If the problem is solved at some point in the future, I don't think the answer will look much like any of the existing VCSs.

Based on experiences in industry, my observation is that the choice of monolithic repository versus separate repository is highly specific to the organization.

Re:“It's The Future” by jshmrsn on Wednesday August 17, 2016 @09:49AM (#12304635)
> No organisation should have more than one regular-use repo (special-use repos, of course, are special). Multiple repos are a smell.

Mind elaborating on this?

Re:“It's The Future” by brianpgordon on Wednesday August 17, 2016 @08:24PM (#12309595)
> > You can no longer use editor/IDE features like go to definition. > Not a problem with a good editor.

What editor are you thinking of that can jump from HTTP client API calls to the corresponding handler on the server?

Re:“It's The Future” by ISV_Damocles on Wednesday August 17, 2016 @12:56PM (#12306167)
> No organisation should have more than one regular-use repo (special-use repos, of course, are special). Multiple repos are a smell.

Totally agree with everything else, but gotta completely disagree on this last point. Monorepos are a huge smell. If there's multiple parts of a repo that are deployed independently, they should be isolated from each other.

Why? Because you're fighting human nature, otherwise. It's totally reasonable to think that once you excise some code from a repo that it's no longer there, but when you have multiple projects all in one repo, different services will be on different versions of that repo, and your change may have changed semantics enough that interaction bugs across systems may occur.

You may think that you caught all of the services using the code you refactored in that shared library, but perhaps an intermediate dependency switched from using that shared library to not using it, and the service using that intermediate library hasn't been upgraded, yet?

When separately-deployable components are in separate repositories, and libraries are actual versioned libraries in separate repositories these relationships are explicit instead of implicit. Explicit can be `grep`ed, implicit cannot, so with the multi-repo approach you can write tools to verify that all services currently in production are no longer using an older, insecure shared library, or find out exactly which services are talking to which services by the IDLs they list as dependencies.

While with the monorepo approach you can get "fun" things like service A inspecting the source code of service B to determine if cache should be rebuilt (because who would forget to deploy service A and service B at the same time, anyways...), as an example I have personally experienced.

My personal belief is that the monorepo approach was a solution back when DVCSs were all terrible and most people were still on centralized VCSs like Subversion that couldn't deal with branches and cross-repo dependencies well, and that's just what you had to do, while Git and Mercurial, along with the nice language-level package managers, make this a non-issue.

Finally, there's an institutional bias to not rock the boat (which I totally agree with) and change things that are already working fine, along with a "nobody got fired buying IBM" kind of thing with Google and Facebook being two prominent companies using monorepos (which they can get away with by having over a thousand engineers each to manage the infrastructure and build/rebuild their own VCSs to deal with the problems inherent to monorepos that most companies don't have the resources and/or skills to replicate).

EDIT: Oh, I forgot, I'm not advocating a service-oriented architecture as the only way to do things, I'm just advocating that whatever your architecture, you should isolate the deployables from each other and make all dependencies between them explicit, so you can more easily write tooling to automatically catch bad deploy states, and more easily train new hires on what talks to/uses what, since it's explicitly (and required to be) documented.

If that still means a monorepo for your company's single service and a couple of tiny repos for small libraries you open source, that's fine. If it means 1000 repos for each microservice you deploy multiple times a day, that's also fine (good luck!).

Most likely it means something like 3-10 repos for most companies, which seems like the right range for Miller's Law) ( https://en.wikipedia.org/wiki/The_Magical_Number_Seven,_Plus... ) and therefore good for organizing code for human consumption.

Re:“It's The Future” by wtbob on Thursday August 18, 2016 @08:42AM (#12312013)
> It's totally reasonable to think that once you excise some code from a repo that it's no longer there, but when you have multiple projects all in one repo, different services will be on different versions of that repo, and your change may have changed semantics enough that interaction bugs across systems may occur.

But having multiple repos doesn't prevent the equivalent situation from happening (and, I think, actually makes it much likelier): no matter what, you have to have the right processes in place to catch that sort of issue.

> You may think that you caught all of the services using the code you refactored in that shared library, but perhaps an intermediate dependency switched from using that shared library to not using it, and the service using that intermediate library hasn't been upgraded, yet?

That's the sort of problem which happens with multiple repos, but not (as often) with a single repo.

> Explicit can be `grep`ed, implicit cannot, so with the multi-repo approach you can write tools to verify that all services currently in production are no longer using an older, insecure shared library, or find out exactly which services are talking to which services by the IDLs they list as dependencies.

A monorepo is explicit, too, even more explicit than multiple repos: WYSIWYG. And you can always see if your services are using the same API by compiling them (with a statically-typed language, anyway).

The beautiful thing about a monorepo is it forces one to confront incompatibilities when they happen, not at some unknown point down the road, when no-one know what changed and why.

Re:“It's The Future” by mseebach on Wednesday August 17, 2016 @09:25AM (#12304461)
I think that your comment is actually a pretty good test for when not to spin out a micro service.

If you expect to need to step into a function call when debugging, then it's too tightly coupled to spin out. You should be able to look at the arguments to the call and the response and determine if it's correct (and if not, now you have isolated a test case to take to the other service and continue debugging there).

If the interface will change so often that you expect it will be a problem that it's in a separate repository, if you expect that you will always need to deploy in tandem, then it's too tightly coupled to spin out.

The advantage of micro services is the separation in fact of things that are separate in logic. The complexity of systems grows super-linearly, so it's easier to reason about and test several smaller systems with clear (narrow) interfaces between them than one big. It's easier to isolate faults. It's harder to accidentally introduce bugs in a different part of the system when the system doesn't have a different part. If done right, scaling can be made easier. But these are hard architectural questions, there's no clear-cut rule for when you should spin off a new service and when you should keep things together.

Someone else mentioned separating the shopping app from the payment system for an ecommerce business, which even has security benefits. I think that's an excellent example.

Edit: Another clear benefit is that you can choose different languages, libraries, frameworks and paradigms for different parts of the code. You can write your boring CRUD backend admin app in Ruby on Rails, your high-performance calculation engine in Rust and your user-facing app in Node.js (so the front- and backend an share Javascript validation code).

Re:“It's The Future” by cookiecaper on Wednesday August 17, 2016 @09:23AM (#12304440)
I just want to add one disadvantage before I give some advantages. There's a lot of operational complexity involved in routing, monitoring, and keeping every instance of every microservice running. That complexity also makes debugging in production much more difficult, as one must track a relay of network requests through many separate layers to find the point where it actually got stuck.

As for advantages, microservices tend to keep code relatively simple and free from complex inheritance schemes. There's rarely a massive tangled-up engine full of special cases in the mix, as there often is in monolithic apps. This substantially decreases technical debt and learning curve, and can make it simple to understand the function an isolated microservice performs.

There is the obvious advantage that if you have disparate applications executing nearly-identical logic to read or write data to the same location, and the application platforms can't execute the same library code, you can centralize that logic into an HTTP API, which reduces maintenance burden and prevents potentially major bugs.

My opinion is that adopting microservices as a paradigm leads to a slow, difficult-to-debug application, primarily because people take the "micro" in microservices too seriously. One shouldn't be afraid to split functionality out into an ordinary service after it's been shown to be reasonable to do so.

Re:“It's The Future” by totally on Wednesday August 17, 2016 @08:58AM (#12304276)
Yes, but there's another dimension here. If another team breaks your build in a monolithic repo, you may or may not be able to resolve this quickly. You're in a contract with them about the state of the repo and thus your service.

With microservices, the production version of their service would conceivably be stable. It moves the contract from the repo to the state of production services.

Re:“It's The Future” by wtbob on Wednesday August 17, 2016 @09:35AM (#12304537)
> If another team breaks your build in a monolithic repo, you may or may not be able to resolve this quickly.

With a monolithic repo done right, the other teams broke their build of their branch, and it's up to them to resolve it. You, meanwhile, are perfectly happy working on your branch. When their changes are mergeable into trunk, then they may merge them, not before — and likewise for you.

With multiple repos, they break your build, but don't know it. You don't know it either, until you update your copies of their repos — and now you have to figure out what they did, and why, and how to update your logic to handle their new control flow, and then you update again and get to do it again, until finally you ragequit and go live in a log cabin with neither electricity nor running water.

Re:“It's The Future” by vonmoltke on Wednesday August 17, 2016 @10:00AM (#12304715)
> With multiple repos, they break your build, but don't know it. You don't know it either, until you update your copies of their repos — and now you have to figure out what they did, and why, and how to update your logic to handle their new control flow, and then you update again and get to do it again, until finally you ragequit and go live in a log cabin with neither electricity nor running water.

I don't see how this is a problem if you are pushing frequently and have a CI system. You know within minutes if the build is broken. If it broke, don't pull the project with the breaking changes.

My point is, I don't think one approach is inherently better than the other. Both require effort on the part of the teams to manage changes (or a CM team), and both require defined processes.

Re:“It's The Future” by sanderjd on Wednesday August 17, 2016 @10:16AM (#12304841)
> If it broke, don't pull the project with the breaking changes.

I agree with the overall sentiment of your comment, but the quoted part is where I've seen trouble brew. The tendency is to be conservative about pulling updates to dependencies, which can easily get you into a very awkward state when a critical update eventually sits on top of a bunch of updates you didn't take because they broke you. It is usually better to be forced to handle the breakage immediately, one way or another.

Re:“It's The Future” by totally on Thursday August 18, 2016 @09:01AM (#12312142)
> With a monolithic repo done right.

Yes, that's the contract that you need to have with other teams. And it's the contract that is automatically enforced with microservices.

Re:“It's The Future” by marcosdumay on Wednesday August 17, 2016 @10:15AM (#12304831)
That's true, but...

You don't debug distributed systems by tracing into remote calls and jumping into remote code. You debug it by comparing requests and responses (you use discrete operations, right) with the specified requests and responses, and then opening the code that has a problem¹.

It calls for completely different tooling, not for a "better debugger".

1 - Or the specs, because yes, now that your system is distributed you also have to debug the specs. Why somebody would decide on doing that for no reason at all? Yet lots of people do.

Re:“It's The Future” by vmateixeira on Wednesday August 17, 2016 @07:02AM (#12303728)
I think it's more to do with a need rather than going straight just because you have enough people on a team. For instance, if you find that some of your processing/specific request handling can outperform better by using a different framework, programming language than the ones it's currently developed on, then you should definitely consider a microservice approach by decoupling that specific service/functionality from your current stack.
Re:“It's The Future” by RyanZAG on Wednesday August 17, 2016 @07:37AM (#12303881)
Careful with this one too. Usually adding new features to adapt to a changing marketplace can have new requirements across many of your services that need to be finished quickly. If those services are each in a different language, it can slow everything down by weeks or months.

Multiple platforms is not a problem and generally a good thing as long as it's not excessive. You don't want to be in a case where you have the same number of different platforms as developers or anything like that. I'm guessing there is a rule of thumb here, but I'm not sure what it would be. Max 1 different platform per 5 developers? Something like that.

Re:“It's The Future” by crdoconnor on Wednesday August 17, 2016 @07:39AM (#12303885)
>decoupling that specific service/functionality from your current stack.

I do wish people would stop conflating "running in a different service" and "loose coupling". They are completely orthogonal.

I've worked on some horrendously tightly coupled microservices.

Re:“It's The Future” by jcadam on Wednesday August 17, 2016 @08:23AM (#12304103)
OSGi makes it easy to end up with a cornucopia of tightly coupled nanoservices all running in the same JVM.

Unless you can coax dOSGi into working (which is tons of fun), then you can have services tightly coupled to other services running on entirely different machines causing frequent (and hilarious) cascades of bundle failures whenever the network hiccups.

OSGi is a trigger word for me now. I've worked on two large OSGi projects (previous job and current job) and it's always the same. Sh*t is always broken (and my lead still insists that OSGi is the one true way to modular bliss). And the OSGi fanboys always say "Your team is using it wrong!" Which very well might be true, but I no longer care. Apparently it's just too damn hard to get a team of code monkeys to respect service boundaries when OSGi makes it so damn easy to ignore them.

If I'm ever in a position of getting to design a new software architecture (hasn't happened in 10 years, but hey I can dream), I'll punch anyone who suggests "OSGi" to me right in the face.

Re:“It's The Future” by neeleshs on Wednesday August 17, 2016 @10:25AM (#12304921)
Wholeheartedly agree on OSGi. Disastrous implementations. I worked with servicemix and still have nightmares around class path issues and crazy bundle scoping rules. A plain old maven built jar with shading works much better in practice, but shading itself is shady :)
Re:“It's The Future” by nicolas_t on Wednesday August 17, 2016 @09:56AM (#12304689)
Well, I consider that by definition tightly coupled microservices should never be done. If it's not possible to decouple that function then it should not be in a micro service.
Re:“It's The Future” by yamaneko on Wednesday August 17, 2016 @11:52AM (#12305591)
> A small team starting a new project should not waste a single second considering microservices unless there's something that is so completely obviously decoupled in a way that not splitting it into a microservice will lead to extra work.

That's a good point. I think this thought extrapolates to other parts of software engineering as well. Sometimes writing very modular and decoupled software from the beginning is very hard for a small team, and we can't see well if this is the best approach since it's also hard to grasp the big picture.

I'm currently facing this issue. I'm trying to write very modular and reusable applications, but now I'm paralyzed trying to picture the best patterns to use, where should I use a facade, a decorator, etc. I think I'll adopt this strategy for myself--only focus on modularizing from the beginning if it'd lead to extra work otherwise.

Re:“It's The Future” by miend on Wednesday August 17, 2016 @08:57AM (#12304272)
I'd also add that microservices have increased value if you begin with such an architecture in the first place. It's much more difficult to "gracefully" rip an existing monolith into modular pieces than to build modularly from the start.
Re:“It's The Future” by mk89 on Wednesday August 17, 2016 @09:07AM (#12304348)
I don't like correcting with "well, actually", however, I have to say that the author of the book "Building Microservices" in his first few chapters (in particular: Chapter 3: Premature Decomposition) warns against using microservices with new apps, especially if you are new to the domain. He claims that they are actually easier to use when you have to refactor a large monolith, and that normally you shouldn't start with microservices unless you know what you are doing - therefore my criticism towards the article which starts with a pre optimization (split one service in 12), which seems to be a common, yet arguable practice.
Re:“It's The Future” by nicolas_t on Wednesday August 17, 2016 @10:02AM (#12304729)
This has not been my experience. I've seen a few projects where microservices had been added from the start because it's the thing to do and, in all cases, it didn't work well. It's extremely difficult to split in microservices if you do not have a clear big picture of your projects functions and coupling. And, in most cases, in new projects, you don't have that big picture.

Microservices also make it much harder to refactor the code which you often need to do in the early stage of a project.