Then I point out that, if they just refactor to a single method that's 20 lines, they can read it from beginning to end and it makes sense.
Then I point out that, if they just refactor to a single method that's 20 lines, they can read it from beginning to end and it makes sense.
Developers do deep work with a framework which ties them to a specific language and the accompanying ecosystem. So, what you see is the "not invented here" syndrome, and how already solved problems are tackled again in that specific ecosystem.
Many solstices ago, I was a PHP developer. If you'd ask me to split a 2.55 Gb CSV file in several CSV files as a one-off request, I would have fiddled with a PHP script, because that was my bread and butter. Probably would have taken something like https://csv.thephpleague.com/ off the shelf to get the job done.
Well, no, you can do exactly that in a single line with tail, head, split and cat.
Since I moved away from PHP, I have come to find a new, deep respect for the already existing general purpose commands which are part of the Unix spec. And reflecting on my earlier work, I realize that I could have solved some challenges a lot quicker.
Now, this is not a stab at clean code or PHP. Both are valuable tools.
Rather, a big lesson for young developers is that the cleanest code out there... is the code you didn't write at all, as you leverage what's already there.
You can't, because csv records may span multiple lines. So dicing them with standard tools may subtly break them. Unless you know your particular CSV data only has single line records.
(I take your broader point though. It's just that CSV is a bad example, because you usually wind up needing specialized tools to deal with them. It's likely that your PHP script would actually be more correct!)
To GP: also - CSV headers. Still possible in one line of shell, but it is starting to get unwieldy.
I should have mentioned another lesson for junior developers: learn to understand the structure of your data and avoid making assumptions about formatting.
In any case, I think the core issue is really how much faith you have in the proficiency of your teammates. If you can't trust the developers in your team to actually only write functions that do what they say in the name (without nasty side-effects), then I can see why not having all the logic in front of you in one giant function can be annoying - you have to jump into all the definitions and manually double check to be sure what's happening.
I've been thinking about this a lot lately actually. At some level, when you create a hierarchy of classes and/or a collection of objects, you're deciding that some logic is best implemented with that set of objects and the way they talk to each other as the fundamental building block. It's very much like designing a language; you're designing the lego bricks and then putting them together to make something. The hope is of course that you're going to be able to use those lego bricks in other situations by composing them in different ways.
Where I think we can go wrong is in getting stuck on the one abstraction type; particularly in this case it's falling into a mindset where the only way to compose software is by comnposing objects. Yet at some level, you're going to be composing your logic out of function calls (or what essentially look like them). You need to know at what level you're building and viewing the system. Sure, you can build a set of objects that you can then use to build some other logic that's implemented by their composition and collaboration, but sometimes maybe all you need is a method that implements this logic more directly, using function calls and their results. From far away, it's OOP with objects collaborating via messages; from up close, it's just procedural (or even functional) code with restrictions on the state it has access to.
This mistake I think is embodied in a sentiment I used to pick up on a lot at the tail end of my CS education (around the time Java was really starting to come into fashion). It was a sentiment I'd describe as something like "OOP has superceded procedural programming". To which I'd always want to ask the question "but what about inside your objects?"
For this reason, it's better to prefer as little structure as you can reasonabley get away with, not more. Now, this is a nuanced view, a senior person can absolutely insist on more structure up front and avoid issues, but they'll have a good reason for doing so that doesn't involve "it's clean code".
But in general, you want as little structure as you can get away with. It's a lot easier to change something that hasn't been abstracted to death with guesses about what the future is going to hold.
I think part of the issue is a perspective thing. If I spend a day throwing something together and it sits for 6 months, great. I got ROI from that code. If 6 months in new requirements come in and I decide I need to rewrite it, who cares. It worked day in and day out for 6 months off a days worth of effort.
Too many people view code as needing to be long lived and unchanging.
There's a lot of social pressure that pushes people to view code as a thing that's either done and permanent, or not done, unfinished and therefore unacceptable.
It's called imperative programming. Funny how rarely you see the word.
I don't think code reuse is itself a bad thing, but it can easily be overused and cause far more confusion than benefits.
I disagree. First 20 lines in a single block means that any single line can have interact with any other. The 19th line's behavior can be subtly influenced by what's on the first line. That means it's not just an issue of reading line-by-line. You have to keep every line in the entire code block in working memory simultaneously.
The limits of human working memory is about seven or eight chunks. When functions get longer than this, they take exponentially longer to understand. 100 lines of code broken up into 25 line functions can take ten times longer to understand than 1000 lines of code broken up into well-abstracted four line functions.