3 ms·
Yeah, the biggest problem that people get into with microservices is that they allow the communication structure to dictate the app structure. A monolith gives
by crdrost 5y ago
Yeah, the biggest problem that people get into with microservices is that they allow the communication structure to dictate the app structure. A monolith gives you some refactorability because you can run what would have been "integration" tests locally, as you massage your module boundaries to match the problem that you're solving. So a monolith can become a clean monolith, and then a clean monolith can maybe become microservices if you need the scale attributes.
The basic problem is that before you know where the module boundary is, you cannot have a clear module boundary. So three popular approaches emerge:
(a) DDD "milliservices". Basically define the different sorts of users, come up with a clustering of the different sorts of people that you think will be using your app. People are considered to be in the same cluster if they use the same jargon to refer to things, or different clusters if they both use some word but they both mean subtly different things by it.
(b) Gut-feeling microservices that become feature microservices. I should probably have an "auth service," I don't know what it does but I'm going to be doing auth so that's probably a service. I need to import a git library to contact GitHub, probably there should be a "git service" that handles all communication to GitHub or other git repos. Each of these things exposes some swagger/openAPI docs, maybe we should have a docs service? -- that sort of thing. The danger is that the things that are easy to break off are usually not the core competency of the product, and so there emerges some sort of "core services," one or two big honkers that basically are monoliths. People are aware that they aren't supposed to keep adding to the core services and so new services emerge named after feature requests, hello "sharing service," hello "wallet service." Except the core usually is tightly coupled to these new feature services and they all kind of connect to each other. The idea of splitting the core services into other services to fit the newfound module boundaries becomes complicated by all these ties to nearby features, you are not actually loosely coupled because you do RPCs and you probably code in the expectation of success into these RPCs like method calls.
(c) Every noun becomes a "nanoservice". This is a service that watches just one or two tables (or NoSQL document types or what have you) and exposes a CRUD API for that noun, plus a couple auxiliary verbs to do actual business needs with those nouns. So if you were implementing Git there would be a file service, a tree service, a branch service, a commit service, probably a working tree service... But you just have to "know" that logs and rebases and cherrypicks live in CommitService while diffing for some reason lives in TreeService and adding a file to your working tree requires first creating it in FileService and then handing that link off to the WorkingTreeService which will make needed calls to TreeService, creating your own tree is exposed via TreeService's CRUD but the developers tell you that down that road There Be Dragons and you should not have been messing with that.
Any of these three can be successful but only insofar as you can create new module boundaries and move module boundaries and test to make sure that your users will not notice any performance regressions. Of them I would only recommend option (a), because it gives a really nice place for these tests to live and an intuition that each test should document a user journey for the system.
- jamesfinlayson 5y agoA company I worked at went all in on option c - there was a random number service (that just wrapped a random number generation library), and sending an email was split across multiple services - one to pull the email request from the database, one to generate the email from the template, one to actually send the email and one to save the templated email to the database.
- dm3 5y agoHow did it work out? Very curious, as such granularity of deployable units seems absurd unless it's deployed into a single runtime...
- jamesfinlayson 5y agoIn reality it worked - each service only talked to the next so in that sense it was okay. But each service was its own binary running in its own container (someone went to a conference and heard that S3 was made up of 500 microservices, to they decided we needed as many microservices as possible). The bit where it didn't work so well was making changes and testing those changes - the original developers hacked it together then didn't want to touch it after that, so there was no dev environment (just staging environments to hijack) and no functional/e2e tests.
- yakshaving_jgt 5y agoI’m imagining that whomever is running that company prefers to heat his home by throwing cash directly into his fireplace instead of burning wood.
- tacone 5y ago"Gut-feeling microservices" is a fantastic definition, thanks for that.
- twic 5y ago> Gut-feeling microservices I'm in this comment and i don't like it. My current team has this pattern. I think we've ended up with two core services, with a fairly thin channel between them, but a constellation of tightly-coupled peripheral services around each core. To be honest, it works pretty well. It wasn't intentional, and it grew in exactly the haphazard way you describe. But it's not a disaster, or at least doesn't feel like one. Maybe we should rebrand this as "natural microservices"?