Previous: Coroutines in C with Arbitrary Arguments
Next: Finish your stuff
Truly reusable components are clearly separated from the code that uses them. That makes it easy to use the component in a different project. It also makes it easy to rip the component out and replace it by a different one.
Non-reusable components cannot be used in different projects. At the same time, they tend to be hairy and almost impossible to rip out of their native project. They are interconnected with the rest of the codebase in subtle ways. Replacing them can break the functionality in unexpected manners and even if it does not you can never be sure that there's no hidden problem waiting for the most inconvenient time to strike you.
In a long-lived project, components are being replaced. Nice reusable components are easy to replace and so they are. Ugly non-reusable components are pain to replace and each replacement means both a considerable risk and considerable cost. Thus, more often then not, they are not replaced. As the years go by, reusable components pass away and only the hairy ones remain. In the end the project turns into a monolithic cluster of ugly components melted one into another.
This mechanism seems to account for most of the complexity in legacy codebases.
Let's call it Sustrik's law:
"Well-designed components are easy to replace. Eventually, they will be replaced by ones that are not so easy to replace."
The law seems almost impossible to beat. Are there any policies users can adopt to avoid the trap? Is there anything developers of nice components can do to avoid being replaced? I would love to hear any suggestions.
Martin Sústrik, June 2nd, 2015
Previous: Coroutines in C with Arbitrary Arguments
Next: Finish your stuff
Well, just like sands won't pile on top of each other by themselves and will easily go downhill, w/o some kind of intervention what you said is more likely to happen. I think code generally go through slow, long phases of reusability/modularity degradation, and then is improved/restored over relatively short, intense phase of refactoring. Often the latter can only be driven by those who are willing to do more than the absolute minimum for what is immediately needed.
I was thinking about it more in the evolutionary terms: Consider components to be memes. Which are going to survive? Those that are so nice that people really do want to use them. Those that are too hairy to get rid of once you are contaminated. Et c.
What mechanisms can be used to control the evil components? Can we turn to the artificial breeding instead of natural selection? Are there any lessons to be learned from population genetics? Epidemology should provide some hints for controlling the spreading. Et c.
Well the problem seems to be that there are two different times at which we pay 2 different costs.
a)Writing the component.
b)Changing the component.
An opportunistic agent would prefer the short-sighted path of minimal cost and always take into account the cost a and not b.
The problem is non-existent when different components are required by different people. The apache lucene project is a very good such example(many different languages, needs).
In general, because of previous experience with different projects, we have acquired the knowledge that changing components is important. Thus, Rules are introduced to make reusable components.
The best solution in my opinion is to create a rule such that every component is replacable as soon as it is created. In other words, there should be at least 2 components and the programmer of the software has to pay both the cost a and b at the same time.
Using xml documents to describe software and then generating them based on the components that are chosen in the xml document ,would be a very good way to enforce such rule.
Similarly, the ecological destruction of the Env can be solved in a similar way.
He explains that you achieve simplicity by pulling components apart conceptually.
If you google "simple made easy", you could find his phenomenal seminar on simplicity at infoq.
It's worth your time if you want simplicity and thus reusability.
I believe you have a logical error. It's only easy to replace one nice component with another nice not with hairy one. So replacing components is not the way projects rot. In fact replacing components is a form of refactor and thus code maintenance.
Hairy components grow naturally, it's not like you manufacture one and then dig it into project.
Interesting view. This sometimes causes another parallel effect on the team, which accelerates the problem: as the codebase gets worse, the best developers tend to leave and be replaced with worse (and harder to replace!) developers.
Making a component easily separable from the rest of the application also makes the component easier to maintain, reason about, test, etc. In other words, increases it's quality in a number of significant areas. The more a software project is composed of such components, the more useful, robust, and scslable it will tend to be. So the selective pressure that favors usefulness will give such components an edge.
I was not arguing that the resulting application will be extremely nice of useful. It very likely won't be. However, the compoent doesn't care. Or doesn't care too much. It's like a parasite: Don't be evil to the extent to kill the host. But short of that, do suck it dry.
Parasites that help the host be more successful would out compete the ones that make their hosts less successful, wouldn't they?
We call those symbionts and yes, it's a viable survival strategy.
Then there are true parasites that make the host less fit. For example, the first thing lot of them do is to castrate the host thus bringing its fitness to zero. It's a strategy that works fine as well.
Hire good engineers, listen to their issues and structure your business goals in a way that allows for technical issues to be solved.
In me experience, bad code costs more money in terms of maintenance, attrition and general neagtivity, however, it does so over a longer period of time than business is capable of having an attention span for.
It's just that there's a lack of effective communications between technology and business that causes unrealistic deadlines to be set, which are then difficult to adjust due to commitments made around them and general misunderstanding and frustration between those that just want the Next Feature out and those that are tasked with actually making that Next Feature happen.
I am explicitly told quite often to NOT spend time designing my work and to NOT try and do it in a general way, but to just get XYZ done now because there are business dependencies that rely on this feature being available to test so that other higher-level things can be decided.
During that time, additional tasks are heaped on engineers and soon they have many tasks like this that must be done this way and, if they have the fortitude and company compensation enough to stay on at one place for a while, on top of that they'll now be responsible for finding a way to fix the cheap code that already went out as somehow it seems to almost always make its way into production.
Eventually, high level people get let go or move on and then new hires promise to fix these huge problems with a new code stack, throwing away the old one.
They spend a few weeks designing and then commit to an unreasonable goal, and the process then begins to repeat itself even before the new project is complete.
I don't think this is a technical problem, I think this is a human problem.
Post preview:
Close preview