Hacker News new | ask | show | jobs
by cryptica 1913 days ago
I also hate monorepos. I consider the monorepo to be an anti-pattern.

It's an architectural advantage to separate each module into a different repo as it encourages careful separation of concerns.

If you find that you often need to update many modules together every time you want to add a new feature to your project, this is often an indication that your modules do not have proper separation of concerns and your abstractions are leaking. It means your project exhibits low cohesion and/or tight coupling between modules.

The difficulty in maintaining separate module dependencies is actually a very useful signal to you as a developer that your code is too tightly coupled and needs to be refactored into modules which are more independent.

Monorepos are a bandaid patch solution which covers up the root problem. The real problem is incorrect separation of concerns, AKA low cohesion which leads to tight coupling between your components.

It's not possible to design simple interfaces between components when these components have overlapping responsibilities.

1 comments

Updating a backend API consumed by a frontend:

  - in 2 repos -> 2 PRs -> 2 test suites -> 2 code reviews
  - in a monorepo -> 1 PR -> 1 test suite -> 1 code review
When your project grows in complexity, there are some concerns that cross the boundaries of your repositories (CI/CD pipelines, testing and QA being a few examples).

Having a monorepo helps.

Consider having all your docker images and helm charts alongside the source code of the many parts of your big project. Is that really an anti-pattern?

EDIT: also a new dev arriving in the team, having to clone only one repository is easier for them. I also try to have a simple docker-compose stack so they have only one command to spin up the whole dev environment.

>> When your project grows in complexity, there are some concerns that cross the boundaries of your repositories

The notion of 'cross-cutting concerns' is also an anti-pattern. It's a violation of the 'separation of concerns' principle. A violation of the 'cross-cutting' kind, to be exact.

There are almost always better alternative solution which don't involve cross-cutting concerns but which require a slightly more carefully thought out architecture.

When it comes to testing, I agree that (for example) integration tests are extremely valuable but I disagree that having the source code of your dependencies in the same repo yields any benefits for integration testing.

Ideally each module dependency should have its own set of tests which test its features based on the appropriate level of abstraction. Dependencies should be more 'general purpose' (suit more different use cases) while higher level logic should be more fitted to the specific business domain. Integration tests should not test the implementation of module dependencies; dependencies should have their own tests.

Higher level tests can sometimes help to uncover issues in dependencies and thus help you to design the tests of those dependencies but keeping them separate is essential because the dependencies should represent a completely different level of abstraction.

You don't want to end up tightly coupling the tests of the main project with the implementation details of its dependencies. Separating the tests correctly helps you to ensure that the scope of your tests is limited to the correct level of abstraction.

My point is that while it's desirable to integration-test a project with its dependencies plugged into it, those tests should not reference any specific implementation details of those dependencies... Because, otherwise, unrelated changes in the implementation of the dependencies are likely to break your higher level tests (which should not be the case); code changes within dependencies should only break your higher level tests if those changes affect higher level behavior.

For example, changing method names and arguments of a dependency should not break your top level integration tests (assuming you've made the matching code changes in your main project source, you shouldn't need to change the top level integration tests at all, they should still pass), the top level tests shouldn't care what the method names of dependencies are and they especially shouldn't care about how those methods are implemented.