When joining a new team, figuring out whether a project is maintained properly often isn't easy - but there are some aspects healthy projects have in common.
Posted on July 20, 2021
Every software developer probably has their own idea of what a healthy software project is. For me personally, a project feels healthy if the team enjoys developing and maintaining it, ideally without any fear of unmanagable legacy code no-one is allowed or likes to touch.
However, I also found some more concrete aspects that were present in almost all healthy projects and missing in all not-so-healthy projects that I've contributed to, professionally and privately. The following list represents the most significant ones on both software-level and project-level.
Effort estimations in software development are inaccurate by nature. If the actual effort has less than, say, 15% variance compared to the estimated effort, your estimation was pretty good. And yet, some software projects allow for surprisingly accurate estimations while other software projects tend to produce incredible outliers. I've faced such outliers more than one time, with deviations up to 750%.
While the average estimation accuracy isn't a direct indicator for software quality, it is an indicator whether or not your processes are working - and working processes in turn are part of a healthy project. If your product and processes allow for reliable estimations, chances are that you've been doing at least some things right so far.
There are just a few things that can slow down the development pace as much as missing orthogonality can. An orthogonal architecture ensures that components can be changed independently without affecting each other. "If I change X, will Y break?" - If you cannot answer this question with a confident "no", your system obviously lacks orthogonality. This is a huge productivity- and reliability killer especially in large monolithic systems.
Deficient orthogonality often is caused by poor cohesion. In an ideal architecture, knowledge about business concepts or at least architectural layers should be allocated in isolated, loosely coupled components, a state which is referred to as high cohesion.
Image: Forward by via Wikimedia Commons
A system with high cohesion allows for great maintainability and extensibility since you'll have to touch fewer components when implementing a change. In contrast, low cohesion comes along with a tighter coupling between components and thus leads to worse orthogonality.
Orthogonality and cohesion turn out to be key indicators for software quality.
Another technical aspect is reproducibility of builds and infrastructure. In fact, this is not just a nice-to-have feature but a hard requirement for me. If a build configuration isn't capable of producing a deterministic and entirely reproducible output, I wouldn't consider the product to be production-ready. Same goes for the infrastructure the application is running on: Any environment configurations and runtime dependencies that are not version-controlled as Infrastructure as Code drastically lower the infrastructure's reproducibility and widen the undocumented gaps between development and production environments.
As a result, deployments to those production environments are less predictable. This leads us to the next aspect.
Software deployments and their degree of automization are yet another critical aspect. This is closely related to reproducibility, but confident deployments are a cultural question as well. If deployments still are a special and dangerous thing that nobody wants to be responsible for, there's probably something going utterly wrong. A Continious Deployment model doesn't fit for every team or product, but deployments at least have to be as automated as possible, as reproducible as possible and as trivial as possible.
In my experience, products that struggle to get these things right often show a lack of automation and proper integration or contract testing.
The structure of a system is a copy of the organization's communication structure according to Conway's law. Therefore, inappropriate team structures will inevitably lead to inappropriate software design.
Teams have to be organized in a fashion that mirrors the product architecture, and the communication and relationships between teams must be equivalent to the communication and relationships between the product modules or features those teams are in charge of. If they don't, you'll end up in trouble - but if they do, working in a team and being part of a larger product will be fun.