I get what the author is saying, but static analysis aside I would do all that I can to avoid a 178 file update. I get that sorbet is allowing them to do this with higher confidence but even in a language that's compiled (thus performing a similar role to Sorbet) that much change is asking for trouble.
If making a single update touches that many source files, then they may want to take a look at their code organization and architecture as that is a whole heck of a lot!
the most productive i have ever been working as a software engineer was in a smaller company where roughly all of the company's product and library code was in a monorepo, and we had a reasonable culture of writing automated tests (although not at 100% branch coverage). sometimes you realise the abstraction in a core library used by all the product code is wrong or limiting, and if your test suite gives you confidence that you're going to catch any potential regressions, you can rework the library with a breaking change & fix everything that transitively depends on that library in a single atomic commit.
The rub for me here is that making one change in a core library ideally wouldn't touch 100+ other source files. This feels like a separation of concerns issue in which a module is being over used.
Perhaps I'm just in the wrong headspace, as I have never had to work in a monorepo fashion. That being said just because your code is in a monorepo, does that directly mean that you aren't versioning your libraries?
To my understanding most package management tooling in most echo systems allow for versioning. With that said, wouldn't you slowly roll out the version to the downstream projects Monorepo or not?
> just because your code is in a monorepo, does that directly mean that you aren't versioning your libraries?
If you are living the monorepo trunk-based development dream, you version all of your product and library code with the commit of the enclosing monorepo. The product code contained in monorepo commit X depends on the versions of the libraries also contained in that same monorepo commit X. Maybe another way to say it is that library dependencies are resolved to whatever is checked out in version control, without going through an abstraction layer of versioned package releases pushed to some package repository.
> To my understanding most package management tooling in most echo systems allow for versioning
correct. but that doesn't mean adopting a decentralised package-based versioning strategy is the most productive way for a team to operate!
> With that said, wouldn't you slowly roll out the version to the downstream projects Monorepo or not?
Perhaps! I can think of some arguments why you might prefer a gradual rollout: to reduce effort and split the work into smaller pieces that can be delivered independently, to reduce risk of the change breaking one of N products it touches, forcing the entire change to be rolled back.
But on the other hand, you don't have to -- you can choose to do the refactor atomically, which is not a choice you have if the product and library code is scattered across N different source control systems that depend on each other through versioned package releases.
If you are working in a monorepo & all your internal library dependencies are fulfilled by the coupled library version in the monorepo commit checkout, not decoupled through versioned package releases, then you would need to use different techniques to allow flexibility of some products to depend on version V1 of a library at the same time as other products depend on version V2. The most obvious one is creating a copy of the entire V1 library, giving it a new name, making the V2 change, checking it in to the monorepo as a sibling library, then rewriting some of the products to depend on V2. See also https://trunkbaseddevelopment.com/branch-by-abstraction/
Refactoring doesn’t just mean optimizing the inside of an implementation.
With a monorepo and good test coverage, I can improve the signature of a function on some library, and use a full-featured IDE to confidently update the usage myself without making it a 10-ticket task that spans 12 teams and 18 meetings.
> This feels like a separation of concerns issue in which a module is being over used.
It's not always modules. Libraries and patterns and frameworks and so on, they will come and they will go. Sometimes you want to just change something across the whole codebase, and having complete type and test coverage over a codebase ensure that you can do so fearlessly.
> wouldn't you slowly roll out the version to the downstream projects
No need. The upside of doing so is that you generally prevent breakage, but at the cost of having to support multiple older versions of everything. In a monorepo, you can change your codebase from one language to another in a single commit, and everything should work just fine. (Speaking from experience.)
> having complete type and test coverage over a codebase ensure that you can do so fearlessly.
here's a bit of hard-won wisdom. if you have a company codebase in a monorepo where the different components (products, libraries) in the monorepo have a fairly uniform level of quality standards, and there is a uniformly high level of test automation & tooling to detect regressions and enable confidence when making sweeping changes, it is incredibly productive.
however, if you have a company codebase in a monorepo where some regions of the code have wildly different quality standards, and test automation may be patchy or missing from some components, the lack of flexibility and coupling caused by how a monorepo resolves internal dependencies can produce a miserable experience. low-quality code without a good automated test suite or other tools to detect regressions needs to be able to pin versions of libraries, or some other mechanism to decouple from the rate of change of the high-quality components.
E.g. a single developer may be the sole person allocated to a project to attempt to build a prototype to try to win a new customer, so they may be bashing out a lot of lower quality code -- often for a good business reason -- without much peer review or test automation. If that lower quality codebase is in the monorepo and depends on core libraries in the same monorepo, then you get a situation where core library developers expect to be able to make breaking changes to core libraries, and if the test suite is green, merge -- but the low-quality prototype codebase doesnt have any tests and just gets increasingly broken (the consultingware prototype code test suite is always vacuously green). Or conversely, the developer trying to get their consulting project over the line might end up telling the core library developers that they're not allowed to make breaking changes as it keeps pulling the rug out from underneath business-critical prototype project delivery, and then you're in a situation where it is no longer possible to refactor the core libraries.
I've completed multi-hundred file refactorings without major issues both manually (long live grep) as well as automated (yay golang and / or jetbrains). Do not fear, just be careful and break it into digestible byte-sized pieces.
Lines of code and number of files is equally meaningless as nearly any other metric of complexity. I'm inclined to say that changing 178 files probably means they're too small.
If making a single update touches that many source files, then they may want to take a look at their code organization and architecture as that is a whole heck of a lot!