[HN Gopher] Microservices should form a polytree
       ___________________________________________________________________
        
       Microservices should form a polytree
        
       Author : mapehe
       Score  : 89 points
       Date   : 2025-12-08 07:24 UTC (4 days ago)
        
 (HTM) web link (bytesauna.com)
 (TXT) w3m dump (bytesauna.com)
        
       | mapehe wrote:
       | Hi, this is my company blog. Hope you like this week's post.
        
         | btbytes wrote:
         | have you read about Erlang supervision trees?
         | https://adoptingerlang.org/docs/development/supervision_tree...
        
       | vedhant wrote:
       | This actually makes a lot of sense. I have one question though.
       | Why is having 2 microservices depend on a single service a
       | problem?
        
         | Neywiny wrote:
         | The explanation given makes sense. If they're operating on the
         | same data, especially if the result goes to the same consumer,
         | are they really different services? On the other hand, if the
         | shared service provides different data to each, is it really
         | one microservice or has it started to become a tad monolithic
         | in that it's one service performing multiple functions?
         | 
         | I like that the author provides both solutions: join (my
         | preferred) or split the share.
        
           | nightpool wrote:
           | I don't understand this. Can you help explain it with a more
           | practical example? Say that N1 (the root service) is a
           | GraphQL API layer or something. And then N2 and N3 are
           | different services feeding different parts of that API--using
           | Linear as my example, say we have a different service for
           | ticket management and one for AI agent management (e.g.
           | Copilot integration). These are clearly different services
           | with different responsibilities / scaling needs / etc.
           | 
           | And then N4 is a shared utility service that's responsible
           | for e.g. performance tracing or logging or something similar.
           | To make the dependency "harder", we could consider that it's
           | a shared service responsible for authentication and
           | authorization. So it's clear why many root services are
           | dependent on it--they need to make individual authorization
           | decisions.
           | 
           | How would you refactor this to remove an undirected
           | dependency loop?
        
             | whstl wrote:
             | Yeah, a lot of cross-cutting concerns fall into this
             | pattern: logging, authorization, metrics, audit trails,
             | feature-flags, configuration distribution, etc
             | 
             | The only way I can see to avoid this is to have all those
             | cross-cutting concerns handled in the N1 root service
             | before they go into N2/N3, but it requires having N1 handle
             | some things by itself (eg: you can do authorization early),
             | or it requires _a lot_ of additional context to be passed
             | down (eg: passing flags /configuration downstream), or it
             | massively overcomplicates others (eg: having logging be
             | part of N1 forces N2/N3 to respond synchronously).
             | 
             | So yeah, I'm not a fan of the constraint from TFA. It being
             | a DAG is enough.
        
             | Neywiny wrote:
             | I tried and cannot. Just keep thinking of it as: if
             | something is doing 2 jobs, split it, if 2 things have the
             | same as they say goes-in-tos and -goes-out-ofs, combine
             | them. And same doesn't mean bit for bit match (though
             | obviously don't needlessly duplicate data), but just a bit
             | higher level.
             | 
             | The problem is that I don't sit in the microservice or
             | enterprise backend spaces, so I an struggling to formulate
             | explanations in those terms.
        
           | suspended_state wrote:
           | I think it does indeed make a lot of sense in the particular
           | example given.
           | 
           | But what if we add 2 extra nodes: n5 dependent on n2 alone,
           | and n6 dependent on n3 alone? Should we keep n2 and n3
           | separate and split n4, or should we merge n2 and n3 and keep
           | n4, or should we keep the topology as it is?
           | 
           | The same sort of problem arises in a class inheritance graph:
           | it would make sense to merge classes n2 and n3 if n4 is the
           | only class inheriting from it, but if you add more nodes,
           | then the simplification might not be possible anymore.
        
           | throwaway894345 wrote:
           | Most components need to depend on an auth service, right? I
           | don't think that means it's all necessarily one service (does
           | all of Google Cloud Platform or AWS need to be a single
           | service)?
        
             | Spivak wrote:
             | That's immediately what I thought of. You'll never be able
             | to satisfy this rule when every service has lines pointing
             | to auth.
             | 
             | You'll probably also have lines pointing to your storage
             | service or database even if the data is isolated between
             | them. You could have them all be separate but that's a
             | waste when you can leverage say a big ceph cluster.
        
               | spyspy wrote:
               | The trick I've used is the N1 (gateway) service handles
               | all AuthN and proxies that information to the upstream
               | services to allow them to handle AuthZ. N+ services only
               | accept requests signed by N1 - the original
               | authentication info is removed.
        
       | jamesbelchamber wrote:
       | Good practical explanation of something I felt but couldn't put a
       | name to.
        
       | rco8786 wrote:
       | Is there any way to actually enforce this in reality?
       | _Eventually_ some leaf service is going to need to hit an API on
       | an upstream node or even just 2 leaf nodes that need to talk to
       | each other.
        
         | jayd16 wrote:
         | IAM roles.
         | 
         | Said less snarky, it should be trivial to define and restrict
         | the dependencies of services (Although there are many ways to
         | do that). If its not trivial, that's a different problem.
        
           | rco8786 wrote:
           | I don't mean that. I mean that eventually the business is
           | going to need some feature that requires breaking the acyclic
           | rule.
        
             | jayd16 wrote:
             | Ah, you don't mean enforce a novice making a mistake, you
             | mean ensure from a design purity perspective?
             | 
             | I don't think its true that you need requests to flow both
             | ways. For example, if a downstream API needs more context
             | from an upstream one, one solution is to pass that data
             | down as a parameter. You don't need to allow the downstream
             | services to independently loop back to gather more info.
        
           | otterley wrote:
           | Since you called the problem "trivial," we can now all depend
           | on you to resolve these problems for us at little cost,
           | correct?
        
             | nineteen999 wrote:
             | The solution requires AWS since the gp thinks that's the
             | only access control mechanism that matters. So I doubt
             | there is going to be little cost about it.
        
             | jayd16 wrote:
             | Restricting arbitrary east-west traffic should be table
             | stakes... It should be the default and you opt into
             | services being able to reach each other. So in that sense
             | its already done.
        
       | jayd16 wrote:
       | It's about the same for most code all the way down to single
       | threaded function flow.
        
         | sethammons wrote:
         | Yes! This is not unique to microservices.
         | 
         | If you look at this proposal and reject it, i question your
         | experience. My experience is not doing this leads to codebases
         | so intertwined that organizations grind to a halt.
         | 
         | My experience is in the SaaS world, working with orgs from a
         | few dozen to several thousand contributors. When there are a
         | couple dozen teams, a system not designed to separate out
         | concerns will require too much coordinated efforts to develop
         | against.
        
         | ericmcer wrote:
         | Yeah good call out, if your code is functional it will end up
         | like this naturally.
        
       | buster wrote:
       | Isn't it the same wisdom as to avoid cyclic dependencies?
        
         | rhelz wrote:
         | It is not only that. An acyclic graph can be non-planar, which
         | means that as you add more nodes, the number of edges can grow
         | as O(n^2).
         | 
         | A polytree is a planar graph, and the number of edges must grow
         | linearly with the number of edges.
        
       | webstrand wrote:
       | Oh that's weird, in the hacker news search index, this link was
       | posted 4 days ago.
        
       | didibus wrote:
       | I might have a different take. I think microservices should each
       | be independent such that it really doesn't matter how they end up
       | being connected.
       | 
       | Think more actors/processes in a distributed actor/csp concurrent
       | setup.
       | 
       | Their interface should therefore be hardened and not break
       | constantly, and they shouldn't each need deep knowledge of the
       | intricate details of each other.
       | 
       | Also for many system designs, you would explicitly want a
       | different topology, so you really shouldn't restrict yourself
       | mentally with this advice.
        
         | throwaway894345 wrote:
         | I agree with this, and also I'm confused by the article's
         | argument--wouldn't this apply equally to components within a
         | monolith? Or is the idea that--within a monolith--all failures
         | in any component can bring down the entire system anyway?
        
           | marcosdumay wrote:
           | > wouldn't this apply equally to components within a
           | monolith?
           | 
           | It's a nearly universal rule you'll want on every kind of
           | infrastructure and data organization.
           | 
           | You can get away for some time with making things linked by
           | offline or pre-stored resources, but it's a recipe for an
           | eventual disaster.
        
         | rcxdude wrote:
         | Well, in practice you're likely to have hard dependencies
         | between services in some respect, in that the service won't be
         | able to do useful work without some other service. But I agree
         | that in general it's a good idea to have a graceful degradation
         | of functionality as other services become unavailable.
        
           | didibus wrote:
           | Right, I don't mean that no service depends on each other,
           | but that they can treat each other like a black box.
        
           | nyrikki wrote:
           | As we are talking about micro services, K8s has two patterns
           | that are useful.
           | 
           | A global namespace root with sub namespaces will just desired
           | config and current config will the complexity hidden in the
           | controller.
           | 
           | The second is closer to your issue above, but it is just
           | dependency inversion, how the kubelet has zero info on how to
           | launch a container or make a network or provision storage,
           | but hands that off to CRI, CNI or CSI
           | 
           | Those are hard dependencies that can follow a simple
           | wants/provides model, and depending on context often is
           | simpler when failures happen and allows for replacement.
           | 
           | E.G you probably wouldn't notice if crun or runc are being
           | used, nor would you notice that it is often systemd that is
           | actually launching the container.
           | 
           | But finding those separation of concerns can be challenging.
           | And K8s only moved to that model after suffering from the
           | pain of having them in tree.
           | 
           | I think a DAG is a better aspirational default though.
        
         | jayd16 wrote:
         | > it really doesn't matter how they end up being connected.
         | 
         | I think you just mean that it should be robust to the many ways
         | things end up being connected but it always does _matter._
         | There will always be a cost to being inefficient even if its ok
         | to be.
        
       | adamwong246 wrote:
       | the problem with "microservices" is the "micro". Why we thought
       | we need so many tiny services is beyond me. How about just a few
       | regular sized services?
        
         | dragonwriter wrote:
         | At the time "microservices" was coined, "service oriented
         | architecture" had drifted from being an architectural style to
         | being associated with inplementation of the WS-* technical
         | standards, and was frequently used to describe what were
         | essentially monoliths with web services interfaces.
         | 
         | "Microservices" was, IIRC, more about rejecting that and
         | returning to the foundations of SOA than anything else. The
         | original description was each would support a single business
         | domain (sometimes described "business function", and this may
         | be part of the problem, because in some later descriptions,
         | perhaps through a version of the telephone game, this got
         | shortened to "function" and without understanding the original
         | context...)
        
         | edude03 wrote:
         | Kind of - AFAIK "micro" was never actually throughly defined.
         | In my mind I think of it as mapping to one table (IE, users =
         | user service, balances = balances service) but that might still
         | be a "full service" worth of code if you need anything more
         | than basic CRUD
        
           | dragonwriter wrote:
           | The original sense was _one business domain or business
           | function_ (which often would include more than one table in a
           | normalized relational db); the broader context was that,
           | given the observation that software architecture tends to
           | reflect software development organization team structure,
           | software development organizations should parallel businesses
           | organizations and that software serving different business
           | functions should be loosely coupled, so that business needs
           | in any area could be addressed with software change with only
           | the unavoidable level of friction from software serving
           | different business functions, which would be directly tied to
           | the business impacts of the change on those connected
           | functions, rather than having unrelated constraints from
           | coupling between unrelated (in business function) software
           | components inhibiting change driven by business needs in a
           | particular area.
        
         | andix wrote:
         | They were never meant to be tiny, in the sense of just a few
         | hundred lines of code.
         | 
         | The name was properly chosen poorly and led to many confusions.
        
         | 9rx wrote:
         | "Micro" refers to the economy, not the technology. A service in
         | the macro economy is provided by another company. Think of a
         | SaaS you use. Microservices takes the same model and moves it
         | under the umbrella of a micro economy (i.e. a single company).
         | Like traditional SaaS, each team is responsible for their own
         | product, with communication between teams limited to sharing of
         | documentation. You don't get to call up a developer when you
         | need help.
         | 
         | It's a (human) scaling technique for large organizations. When
         | you have thousands of developers they can't possibly keep in
         | communication with each other. You have to draw a line between
         | them. So, we draw the line the same way we do at the global
         | scale.
         | 
         | Conway's Law, as usual.
        
         | jayd16 wrote:
         | I always took it to be a minimum and that "micro" meant "we
         | don't need to wait for a service to have enough features to
         | exist. They can be small." Instead, people see it as a maximum
         | and services should be as small as possible, which ends up
         | being a mess.
        
         | pan69 wrote:
         | I have always understood "micro" to be referring to "scope",
         | not to "size".
        
         | nhumrich wrote:
         | Micro is a relative term. And was coined by these massive
         | conglomerates, where micro to them is "normal sized" to us.
         | They work better if you ignore what "micro" normally means. But
         | "not too too large services" doesn't quite roll off the tongue.
        
         | SrslyJosh wrote:
         | Because it's simpler, duh. </sarcasm>
        
       | Perz1val wrote:
       | Rule #2 sounds dumb. If there can't be a single source of truth,
       | for let's say permission checking, that multiple other services
       | relay on, how would you solve that? Replicate it everywhere? Or
       | do you allow for a new business requirement to cause massive
       | refactors to just create a new root in your fancy graph?
        
         | kaashif wrote:
         | This is exactly the example I thought of and came here to post.
         | 
         | The rule is obviously wrong.
         | 
         | I think just having no cycles is good enough as a rule.
        
         | jayd16 wrote:
         | Services handle the permissions of their own features.
         | Authentication is handled at the gateway.
         | 
         | Not sure if I agree its really the best way to do things but it
         | can be done.
        
           | solid_fuel wrote:
           | That implies that every service has a `user -> permissions`
           | table, no? That seems to contradict the idea brought up
           | elsewhere in the thread that microservices should all be the
           | size of one table.
        
       | cientifico wrote:
       | Services (or a set of Microservices) should mimic teams at the
       | company. If we have polytree, that should represent departments.
        
         | mkarrmann wrote:
         | Microservices should have clear owners reflected in the org
         | chart, but the topology of dependencies should _definitely not_
         | be isomorphic to your org chart.
        
       | Lucasoato wrote:
       | > Even without a directed cycle this kind of structure can still
       | cause trouble. Although the architecture may appear clean when
       | examined only through the direction of service calls the deeper
       | dependency network reveals a loop that reduces fault tolerance
       | increases brittleness and makes both debugging and scaling
       | significantly more difficult.
       | 
       | While I understand the first counterexample, this one seems a bit
       | blurry. Can anybody clarify why a directed acyclic graph whose
       | underlying undirected graph is cyclic is bad in the context of
       | microservice design?
        
         | isotropy wrote:
         | Without necessarily endorsing the article's ideas....I took
         | this to be like the diamond-inheritance problem.
         | 
         | If service A feeds both B and C, and they both feed service D,
         | then D can receive an incoherent view of what A did, because
         | nothing forces B and C to keep their stories straight. But B
         | and C can still both be following their own spec perfectly, so
         | there's no bug in any single service. Now it's not clear whose
         | job it is to fix things.
        
       | nicodjimenez wrote:
       | This seems completely wrong. In an RPC call you have a trivial
       | loop, for example.
       | 
       | It would make more sense to say that the event tree should not
       | have any cycles, but anyway this seems like a silly point to
       | make.
        
         | nicodjimenez wrote:
         | My main take on microservices at this point is that you only
         | want microservices to isolate failure modes and for independent
         | scaling. Most IO bound logic can live in a single monolith.
        
           | 9rx wrote:
           | It is simpler than that. You only want microservices in the
           | same cases you want services (i.e. SaaS). Meaning, when your
           | team benefits from an independent third-party building and
           | maintaining it. The addition of "micro" to "service"
           | indicates that you are reaching out to a third-party that is
           | paid by the same company instead of paying a separate
           | company.
        
       | muvlon wrote:
       | Avoiding cyclic dependencies is good, sure. And they do name
       | specific problems that can happen in counterexample #1.
       | 
       | However, the reasoning as to why it can't be a general DAG and
       | has to be restricted to a polytree is really tenuous. They
       | basically just say counterexample #2 has the same issues with no
       | real explanation. I don't think it does, it seems fine to me.
        
         | henryfjordan wrote:
         | An AuthN/Z system would probably end looking like
         | counterexample #2, which immediately raised a red flag for me
         | about the article.
        
           | waterproof wrote:
           | Yeah if services can't be used by multiple other services,
           | then what's the point?
        
             | spyspy wrote:
             | Treating N4 as a service is fair. I think the article was
             | leaning more toward that idea of N4 being a database, which
             | is a legit bad idea with microservices (if fact defeating
             | the point entirely). My takeaway is that if you're going to
             | have a service that many other services depend on, you can
             | do it but you need to be highly away of that brittleness.
             | Your N4 service needs to be bulletproof. Netflix ran into
             | this exact issue with their distributed cache.
        
             | mon_ wrote:
             | The article doesn't make that claim. For example, the
             | service n7 is used by multiple other nodes, namely n3 and
             | n4. There is no cycle there, so it's okay.
        
               | PunchyHamster wrote:
               | but why is having multiple paths to a service wrong ? The
               | article just claims "it does bad things", without
               | explaining _how_ it does bad things and why it would be
               | bad in that context.
        
         | munchler wrote:
         | Came here to say the same thing. A general-purpose microservice
         | that handles authentication or sends user notifications would
         | be prohibited by this restriction.
        
           | efaref wrote:
           | Or DNS.
           | 
           | I think the article is just nonsense.
        
       | andix wrote:
       | In reality their structure is much more like the Box with
       | Christmas lights I just got from the basement. It would take a
       | knot theory expert half a day to analyze what's happening inside
       | the box.
        
       | scuff3d wrote:
       | This is a fair enough point, but you should also try to keep that
       | tree as small as possible. You should have a damn good reason to
       | make a new service, or break an existing one in two.
       | 
       | People treat the edges on the graph like they're free. Like
       | managing all those external interfaces between services is
       | trivial. It absolutely is not. Each one of those connections
       | represents a contract between services that has be maintained,
       | and that's orders of magnitude more effort then passing data
       | internally.
       | 
       | You have to pull in some kind of new dependency to pass messages
       | between them. Each service's interface had to be documented
       | somewhere. If the interface starts to get complicated you'll
       | probably want a way to generate code to handle
       | serialization/deserialization (which also adds overhead).
       | 
       | In addition to share code, instead of just having a local module
       | (or whatever your language uses) you now have to manage a new
       | package. It either had to be built and published to some repo
       | somewhere, it has to be a git submodule, or you just end up
       | copying and pasting the code everywhere.
       | 
       | Even if it's well architected, each new services adds a
       | significant amount of development overhead.
        
       | itsthecourier wrote:
       | just imagine how many clients services like auth, notifications
       | and so on has.
       | 
       | Polytrees look good, they don't work on orthogonal services
        
       | anomaloustho wrote:
       | Why do we use polytree in this context instead of DAG? Because
       | nodes can't ever come back together?
        
         | duped wrote:
         | The author is not saying you should use a polytree but rather
         | that the ideal graph of microservices should also be a
         | polytree.
         | 
         | A polytree has the property that there is exactly one path that
         | each node can be reached. If you think of this as a dependency
         | graph, for each node in the graph you know that none of its
         | dependencies have shared transitive dependencies.
         | 
         | I'll give it one though: if there are no shared transitive
         | dependencies then there cannot be version conflicts between
         | services, where two otherwise functioning services need
         | disparate versions of the same transitive dependency.
        
       | advisedwang wrote:
       | Requiring that no service is depended on by two services is
       | nonsense.
       | 
       | You absolutely want the same identity service behind all of your
       | services that rely on an identity concept (and no, you can't just
       | say a gateway should be the only thing talking to an identity
       | service - there are real downstream uses cases such as when
       | identity gets managed).
       | 
       | Similarly there's no reason to have multiple image hosting
       | services. It's fine for two different frontends to use the same
       | one. (And don't just say image hosting should be done in the
       | cloud --- that's just a microservice running elsewhere)
       | 
       | Same for audit logging, outbound email or webhooks, acl systems
       | (can you imagine if google docs, sheets, etc all had distinct
       | permissions systems)
        
         | liampulles wrote:
         | I agree with you. Its interesting when I look at the examples
         | you provide, that they are all non-domain services, so perhaps
         | that is what codifies a potential rule.
        
         | jayd16 wrote:
         | Yeah even further, does that mean that SAAS like S3 shouldn't
         | exist because it has multiple users?
         | 
         | I guess one possible solve would be to separate shared services
         | into separate private deployments. Every upstream service gets
         | its own imagine hosting service. Updates can roll out
         | independently. I guess that would solve the blast radius/single
         | source of failure problems but that seems really extreme.
        
         | spyspy wrote:
         | The trick is to have your gateway handle authn, and then proxy
         | authz data upstream so those services can decide how to handle
         | it without needing to make a second call to the identity
         | service.
        
       | pavlov wrote:
       | If a service n4 can't be called by separate services n2 and n3 in
       | different parts of the tree (as shown in counterexample #2), then
       | n4 isn't really a service but just a module of either n2 or n3
       | that happens to be behind a network interface.
        
       | closeparen wrote:
       | Here's a really simple way to get a cycle.
       | 
       | Service A: publish a notification indicating that some new data
       | is available.
       | 
       | Service B: consume these notifications and call back to service A
       | with queries for the changed data and perhaps surrounding
       | context.
       | 
       | What would you recommend when something like this is desired?
        
         | 9rx wrote:
         | There is no cycle here.
         | 
         | Service B initiates the connection to Service A in order to
         | receive notifications, and Service B initiates the connection
         | to Service A to query for changed data.
         | 
         | Service A never initiates a connection with Service B. If
         | Service B went offline, Service A would never notice.
        
         | 10000truths wrote:
         | That's not a cycle - service B isn't writing any new data to A.
        
       | amarant wrote:
       | The article is not wrong, but I feel like the polytree restraint
       | is a bit forced, and perhaps not the most important concern.
       | 
       | You really need to consider why you want to use micro services
       | rather than a monolith, and how to achieve those goals.
       | 
       | Here's where I'll get opinionated: the main advantage micro
       | services have over a monolith is the unique failure modes they
       | enable. This might sound weird at first, but bear with me. First
       | of all, there's an uncomfortable fact we need to accept: your web
       | service will fail and fall over and crash. Doesn't matter if
       | you're Google or Microsoft or whatever, you will have failures,
       | eventually. So we have to consider what those failures will look
       | like, and in my book, microservices biggest strength is that, if
       | built correctly, they fail more gracefully than monoliths.
       | 
       | Say you're targeted by a DDOS attack. You can't really keep a
       | sufficiently large DDOS from crashing your API, but you can do
       | damage control. To use an example I've experienced myself, where
       | we foresaw an attack happening (it came fairly regularly, so it
       | was easy to predict) and managed to limit the damage it did to
       | us.
       | 
       | The DDOS targeted our login API. This made sense because most
       | endpoints required a valid token, and without a token the request
       | would be ignored with very little compute wasted on our end. But
       | requests against /login had to hit a database pretty much every
       | time.
       | 
       | We switched to signed JWT for Auth, and every service that
       | exposed an external API had direct access to the public key
       | needed to validate the signatures. This meant that if the Auth
       | service went down, we could still validate tokens. Logged in
       | users were unaffected.
       | 
       | Well, just add predicted, the Auth service got ddosed, and
       | crashed. Even with auto scaling pods, and a service startup time
       | of less than half a second, there was just no way to keep up with
       | the sudden spike. The database ran out of connections, and that
       | was pretty much it for our login service.
       | 
       | So, nobody could login for the duration of the attack, but
       | everyone who was already logged in could keep using our API's as
       | if nothing had happened. Definitely not great, but an acceptable
       | cost, given the circumstances.
       | 
       | Had we used a monolith instead, every single API would've gone
       | down, instead of just the Auth ones.
       | 
       | So, what's the lesson here? Services that expose external API's
       | should be siloed, such that a failure in one, or it's
       | dependencies, does not affect other API's. A polytree can achieve
       | this, but it's not the only way to do it. And for internal
       | services the considerations are different, I'd even go so far as
       | to say simpler. Just be careful to make sure that any internal
       | service than can be brought down by an attack on an external one,
       | doesn't bring other external services down with it.
       | 
       | So rather than a polytree, strive for siloes, or as close to them
       | as you can manage. When you can't make siloes, consider either
       | merging services, or create deliberate weak-points to contain
       | damage
        
       | OutOfHere wrote:
       | What's wrong with just imposing a DAG?
        
       | adrianco wrote:
       | All sounds like a good plan, but there's no easy way to enforce
       | the lack of cycles. I've seen helper functions that call a
       | service to look something up, called from a library that is
       | running on the service itself. So a service calls itself. There
       | was probably four or five different developers code abstractions
       | stacked in that loop.
        
       | lifeisstillgood wrote:
       | What are you trying to protect yourself against?
       | 
       | 1. Microservices imply distributed computing. So work with the
       | grain on that - which is basically message passing with shared
       | nothing resources. Most microservices try to do that so we are
       | pretty good from a technical pov
       | 
       | 2. Semantic loops - which is kind of what we are doing here with
       | poly trees. This is really trying to model the business in
       | software
       | 
       | Now here comes the hard part - this is not merely hard it's
       | sometimes bad politics to find out how a business really works.
       | Is think far more software projects fail because the business
       | they are in is unwilling to admit it is not the shape they are
       | telling the software developers it is. Politics, fraud or
       | anything in steer.
        
       | JoeAltmaier wrote:
       | Back in the day an OS called CTOS hosted what were essentially
       | microservices. This acyclic problem was solved there, by not
       | letting the essential OS services ever wait on a service
       | response. It simply registered the outstanding service request
       | and went back to servicing its own request queue. I thought at
       | the time, this was an elegant solution to the deadlock problem.
        
       | NortySpock wrote:
       | So a data flow path that is a dag. Yeah, sounds right.
       | 
       | Also seems close to Erlang / Elixir supervision trees, which
       | makes sense as Erlang / Elixir basically gives you microservices
       | anyway...
        
       | TheCycoONE wrote:
       | I have a question. Does the directed / no cycles aspect mean that
       | webhooks / callbacks are forbidden.
       | 
       | I work a lot in the messaging space (SMS,Email); typically the
       | client wants to send a message and wants to know when it reached
       | its destination (milliseconds to days later). Unless the client
       | is forbidden from also being the report server which feels like
       | an arbitrary restriction I'm not sure how to apply this.
        
       | ericmcer wrote:
       | This seems cool if all you need is: call service -> Get response
       | from service -> do something with response.
       | 
       | How do you structure this for long running tasks when you need to
       | alert multiple services upon their completion?
       | 
       | Like what does your polytree look like if you add a messaging
       | pub/sub type system into it. Does that just obliterate all
       | semblance of the graph now that any service can subscribe to
       | events? I am not sure how you can keep it clean and also have
       | multiple long running services that need to be able to queue
       | tasks and alert every concerned service when work is completed.
        
         | rcxdude wrote:
         | A general pub/sub bus between all the nodes does generally
         | encourage everything to become tangled together, for sure.
        
         | mikepurvis wrote:
         | I think for a lot of teams, part of the microservices pitch is
         | also that at least some of the services are off the shelf
         | things managed by your cloud provider or a third party.
        
       | heyitsdaad wrote:
       | Take Counterexample #2. Add n5 as another arrow from n3. That
       | looks like a legitimate use case to me.
        
       | willahmad wrote:
       | it's only in theory, in practice not going to happen.
       | 
       | In most of the cases, authorization servers are called from each
       | microservice.
       | 
       | evented systems loopback and it's difficult to avoid it, e.g.:
       | order created -> charge -> charge failed -> order cancelled
        
       | kgeist wrote:
       | I think what the article is doing wrong is treating all
       | microservices the same.
       | 
       | Microservices can be split into at least 3 different groups:
       | - infrastructure (auth, messaging, storage etc.)       - domain-
       | specific business logic (user, orders)       - orchestration
       | (when a scenario requires coordination between different domains)
       | 
       | If we split it like this, it's evident that:                  -
       | orchestration microservices should only call business logic
       | microservices        - business logic microservices can only call
       | infrastructure microservices       - infra microservices are the
       | smallest building blocks and should not call anything else
       | 
       | This avoids circular dependencies, decreases the height of the
       | tree to 3 in most cases, and also allows to "break" the rule #2
       | in the article, because common, no one is going to write several
       | versions of auth just to make it a polytree.
       | 
       | It also becomes clearer what a microservice should focus on when
       | it comes to resilience/fault tolerance in a distributed
       | environment:                 - infra microservices must be most
       | resilient to failure, because everyone depends on them       -
       | orchestration microservices should focus on compensating logic
       | (compensating transactions/sagas)       - business logic
       | microservices focus on business logic and its correctness
        
       ___________________________________________________________________
       (page generated 2025-12-12 23:00 UTC)