Could someone share their experience from a large ...
# community-support
v
Could someone share their experience from a large monorepo? Monorepo has this association to google having all of their code there, and in my head implies lots of unrelated stuff So, is it wise or common to have unrelated stuff together in a monorepo? say ios and android, or mobile and backend (where there is not dependencies between the two)
e
My experience has been that when I'm working in a monorepo, I hate it, and when I'm not working in a monorepo, I miss it.
😅 1
p
Cons: • A lot of code living together makes everything slower. Git, Android Studio, CICD. First compilation is crazy slow, second and up faster but still not as fast as independent repos. Pros: • Only 1 PR per branch. That's it. In multirepo one needs a PR per repo(library) per branch. Aligning branches for the whole project can take several PRs plus CICD time.
It is a trade-off, there is no clear winner here
m
we put everything into a single repo, including infrastructure code like terraform or helm a perhaps unexpected Pro: if you're using LLM tools they suddenly get a lot better. Code review agents start to cross reference your changes, coding agents can look up the specifics of the backend impl when writing frontend etc
v
First compilation is crazy slow, second and up faster but still not as fast as independent repos.
That had nothing to do with one repo vs. multiple repos. Just because you keep code together in one repo does not mean it has to be one big build that contains everything. You can also have one big repo with 10 individual builds in it that are exactly as performant as if they were in separate repos.
a perhaps unexpected Pro: if you're using LLM tools they suddenly get a lot better.
That's also not really relevant to having one repo or multiple. Even if you have multiple repos you can apply the other repos to the LLMs for context. My simple rule is: If it should be versioned / branched / tagged / released / ... together, it belongs into the same repository, if not, then not. This rule served me very well and so far always applied.
👍 4
p
How do you handle microservices? Currently, I put them into 1 big backend repo, but I release them individually due to the internal bureaucracy of the deployment process…
v
I did not do microservices so far. But I'd say my rule just applies the same? If you version / tag / release / branch together, it belongs into the same repository, if not then not. If with "release" you just mean the pure process of deploying and so on, that still counts. With release I mean finish the coding and creating a tag mainly. If things have different versions, tags are not really correct as you tag code that has nothing to do with the tag. If you split things that are versioned / branched / released together, you have process overhead of synchronizing all parts.
v
Usually microservices have rest/grpc between them. Would you consider the openapi xml or grpc protos as dependencies worth modeling in the build system?
v
Not sure what you mean by "model as dependencies"
v
"service A needs to call service B"
v
Well, whether you model it in the build system probably depends on whether you need the information at build time?
v
with gprc, there a plugin which codegens java interface+records which the service A then uses to call service B
v
Given that service B somehow provides some information from which the build of service A generates these classes, you have the connection modeled already. If for example service B produces some proto specification file, then service A will consume that file to do the code generation and thus you have the connection modeled.
v
right, agreed, but there is this also this (imo incorrect) narrative of "no dependencies between services" and they pretend the api descriptions are not dependencies
v
Yeah, well, depends on what you call dependency. If you call the API of a service that is for me a kind of dependency. But maybe not what is meant by that stanza? 🤷‍♂️
v
I think its just uninformed opinion - most likely getting a link to the openapi via chat and pretending its not a dependency
j
I see it as this: a grpc SERVER owns its contract. that proto contract should live in a separate module of the server repo. they release together, but the service deploys a service and the proto definition publish the generated stubs (in java, ts, python, whatever languages you plugin). then clients can pull in those stubs as a library to talk with the server. there is a dependency between those services. the idea of "no dependencies between services" should not be a goal. these services are related somehow: they are part of the same system and will be talking to each other's APIs. so if service A is a grpc server, and service B has a client to talk to A, then B depends on A. therefore, B depending on a library generated by A is appropriate. Now, architecturally, if you want to flip that dependency, because it is more appropriate for A to depend on B, then that is where messaging or event-driven architecture comes in. if B owns and consumes from a queue/topic, and publishes the model for messages to put on that queue, then A can depend on that library, publish those messages, and in that situation A depends on B, because it knows about B, but B has no idea who is publishing to its queue. use this to make sure your service dependency graph is what you want.
now of course, if it is all in one repo, it is simpler because you can just make breaking changes to contracts at any time and the releases will be synchronized. but eventually the high coupling there will cause more friction as the org scales to many teams. I like @Vampire’s heuristic for what belongs together in a repo and what doesnt.
❤️ 2
v
say a service A is released by the team A that owns it, but it needs to call service B (which gets handled completely by team B) by that heuristic you choose a multirepo approach? seems countrary to what I see (but I'm new)
v
Just that you see bad practice, does not make it right 😄 Also, I just told you how I see it, others see it differently.
But yes, if team A does service A and versions, releases, tags, etc. it independently of B, then in my opinion it has nothing to do in the same repository
👍 1
v
but then one needs to get the definitions via maven repos, which means versioning them, and we're back to square one, arent we?
🤔 1
v
What is "square one"? If B depends on A, it is just find that B depends on something of A. For example A can publish the "proto definition" or whatever it is called with protobuf, or the OpenAPI desciprition file as separate artifact. B can then depend on that API description to generate the code it needs.
t
No different than when you consume third-party APIs, right?
☝️ 1
v
Or A can generate right away some ready-made "client library" that B can right away consume if it is written in the same language
Or if you really want to avoid any technical build-time dependency, then after A was released copy their API description file into B's repository and generate code from that.
But that does not make it any less a dependency, B still depends on the API of A, just less technically, but that is quite meaningless imho.
If A and B would be in the same repository it would not be any different either.
v
I was under the impression that monorepo tries to solve the versioning + pushing artifact issue by making git be the versioning
v
B woudl still depend on A and consume something from it, be it a ready-made client library or just an API description file.
I was under the impression that monorepo tries to solve the versioning + pushing artifact issue by making git being the versioning
But you said that A is released independently, so no
v
I'm not disagreeing,I'm only making up my mind on the topic - but say slack, I see a monorepo of many microservices, with different ownerships, and build team goes to great lengths to keep the monorepo
v
Again, I'm just stating my opinion. And in my opinion a big monorepo of unrelated things is just bad-practice bullshit. 🤷‍♂️
I did not see any advantage of doing something like that yet, only drawbacks.
t
Monorepos are good (IMO, but no real experience) to share code (libraries) between your apps without having to release those libs and manage release lifecycles; but it comes with the drawback that all apps need to be updated whenever there's a breaking change in such lib, so the lib needs to be owned by some team that is entitled to make changes to all apps at once.
☝️ 2
v
so you're saying versioning is less painful than monorepo of unrelated stuff, I see
breaking changes .. you can emulate versioning in code if you really want to
v
But why should you? Just put stuff in separate repos and release them to a repository if you want proper versioning and not an "all in one" build.
💯 1
t
yes, and then someone has to make sure everyone has updated before the old/deprecated API can be removed; that's just another way of saying/applying it, that's still a breaking change
v
I guess it depends on the frequency on development, cutting versions every day is pointless
But I figure breaking stuff and changing globally is the point, with versions you never move to the new version across the org, you always end up supporting all of the versions
v
Again, imho if you tag / branch / version / release stuff together, put it in one repo, if you do it independently, put it in separate repos.
And no, there is no need to "support old versions", just tell the consumer to update if they need something fixed. If that is the company rule to avoid maintenance overhead for old versions, that's fine too.
If you have a frequent changing library that needs releases every day, so be it. But that imho is quite uncommon.
At least from my experience.
And to develop changes in a lib and test it in the consumer together, you can always use a local composite build, that is the main original use-case of them, as long as the Gradle versions are compatible or optimally identical.
v
Gotcha, then I have to ask the people for reasoning, because they go to great lengths to keep the monorepo, if they'd just multirepo maybe they'd save some headaches
but instead they make these massive efforts to join stuff, and I don't believe they have atomic deploys (?) maybe that's where I'm wrong
v
Well, every solution has its pros and cons like always. There are also people still using Maven nowadays instead of Gradle. And many of them you will not be able to convince to switch, not because of facts, just because of personal preference or fear of using something new. 🤷‍♂️
v
Sure, I'm just looking for the motivation, because obviously there needs to be one
p
Vampire, I think you are assuming a nicely structured module where features have api and impl modules and they are all using composite builds and everything is a bliss. But when you deal with a monster of 20+ modules mangled together and basically depending on each other. Touching one module most likely will cause the whole thing to recompile. And in this cases is worth starting new work in a separate repo than continue building on top of the same monster
v
> Sure, I'm just looking for the motivation, because obviously there needs to be one Yes, just saying that the motivation could also simply be personal preference, so watch out, you can quite fast get into clinch when trying to counter that with facts. 😄
v
sure but it's somebody else paying them so, I don't think its all just a cult; but yea bias could be there
v
@pablozki that does not counter what I said. If you want to develop something freshly nicely structured, it is fine to put it to a different repository. But then don't try to keep versions in sync or something like that. Develop that library in a separate repository, release it when it's ready, and depend on that library from the other project. If that new library is also tightly coupled to the "monster" an that it needs to always be released together and so on, keep them in the same repository. Having them in the same repository does not mean you have to build on top of the monster. You can also have in the same repository a completely separate build for that new thing that is independent and nice and then maybe include that build to the monster's build to consume it. Again, if it is tagged / released / branches / versioned together, put it in the same repository, if not put it in different repositories. Having things in the same repository does not mean you have to have one build that builds them. It can and often does, but that's a separate topic. You can have an Android build and a n iOS build completely independent in the same repository, but release and version them together.
🆗 1