I experienced a crystal clear example of this about 15 years ago. I developed a prototype of perl script that read data from one folder, filtered and enhanced it, and wrote it out to another folder, where it was picked up by another process. The script was configured by another perl file that contained the paths to read and write from. The initial (pre-production) deployment had the two folders adjacent, so the config script looked something like
At some point the script was handed off to some other dev who looked at those paths and apparently thought "that's not DRY!", and changed the code so that the config file just had
and actually append the "input" and "output" in code when needed (fairly elegantly leveraging some existing keys that already defined those two strings).
The problem was that when I developed the script the actual consumer hadn't been finalized, so that output folder path was just a placeholder. When it comes time to deploy we get the actual path which is now some NFS thing like
/mnt/other-services-host/other-service/input/
At this point I naively go to the config to update my $output_folder variable and discover the code changes made by the other dev, which have made it impossible to separate the two folders, and because of the "elegant reuse of existing keys" made it a huge pain to even change the code back, since the assumption that the last segment of the path had to match the intended use was deeply baked in. At this point I think I just started swearing for a week.
Now you've just obfuscated that string for no apparent reason. Nobody can grep for that literal string anymore and you gained an extra line of code.
Those paths are not the same data repeated twice just because they share common substrings. They are two paths that serve distinct purposes. The developer likely chose that syntax because it looks like a setting that can be changed. It could just as well have been read from a settings file.
In the spirit of the original article I think point is not whether it was too much or not enough abstraction--it was the wrong abstraction. His abstraction eases one potential change (changing the project folder, which would imply changing two path strings in the original code but one in his), but at the same time makes a whole bunch of other potential changes much harder (or even impossible) to handle. We all would have been better off if he'd just left the duplication in place.
Those are not really abstractions, just extracted variables. An abstraction would change the concept language.
$suffix = "put";
This is also not an abstraction, as the language of the term "suffix" comes from its role in string concatenation, which is the same as the role of the original string literal. It doesn't change the "level of abstraction".
This isn't an over-abstraction, it's an over-extraction. Each abstraction should be non-trivial.
$project_folder = "/whatever";
is a good abstraction. Looking at the string literal "/whatever", I cannot determine it's "role", but $project_folder is a good name and changes the concept language from being about string concatenation or arbitrary names into a concept language about projects and folders.
One might contemplate the question of why people use config files in some cases and command-line parameters in others. Having a section for constants at the beginning of a script resembles a config file to some extent.
Implicit assumption that other people's code is off-limits?
Most software on my machine has probably arrived from apt-get at some point or another. Even if it's all Perl scripts, I'm not going to overwrite them directly, only to have my changes either removed on update, or blowing up the package manager's consistency checksums, or [insert random reason I can't conceive, because I'm not familiar with internals of apt]. So it's either config files, command line, environmental variables, or I'm going to build a wrapper that bends installed software to my will.
The problem was that when I developed the script the actual consumer hadn't been finalized, so that output folder path was just a placeholder. When it comes time to deploy we get the actual path which is now some NFS thing like
At this point I naively go to the config to update my $output_folder variable and discover the code changes made by the other dev, which have made it impossible to separate the two folders, and because of the "elegant reuse of existing keys" made it a huge pain to even change the code back, since the assumption that the last segment of the path had to match the intended use was deeply baked in. At this point I think I just started swearing for a week.