Why is it a best practice to write functions that only do one thing? Because as soon as the function is doing multiple things, it can get very very confusing as to what exactly is going on, even for the best programmers.
Yes, and in that connection I want to mention narcissism, which I personally think is a big obstacle standing in the way of collaborative programming, in the way of seeing one's code as community property that must be understood by everyone involved.
Narcissists, more numerous than most people realize, think their code is much better than code created by ordinary people, to the degree that they see no point in making it comprehensible to mere mortals. Also, consistent with the true nature of narcissists, they're secretly insecure about themselves and their abilities, which is the real motive for making their code incomprehensible -- to do otherwise might reveal how perfectly ordinary their code really is, and they really are.
> Why is it a best practice to write functions that only do one thing? Because as soon as the function is doing multiple things, it can get very very confusing as to what exactly is going on, even for the best programmers.
That's a good argument in favor of OO programming, where one writes a class instead of a mere function, thus avoiding the trap of trying to create multi-purpose functions.
I disagree there (that "That's a good argument in favor of OO programming"). What if one creates a multi-purpose class? How is that any better than a multi-purpose function?
IMHO the point -- do one thing -- is applicable to many paradigms.
Easily answered -- look at a class meant to deal with String objects. It encapsulates a string object plus any number of functions that deal with strings. Compare this to a function that does to a string what a class does, but necessarily under the command of a passed flag that instructs it which action to take. The latter is much less satisfactory from a comprehensibility standpoint.
I say this because I was programming before there were classes, or anything resembling high-level structure (I wrote Apple Writer in assembly language, a language utterly lacking in structure: http://en.wikipedia.org/wiki/Apple_Writer), so I've watched a number of revolutions in programming over the decades. The idea of a class associating a data type and functions meant to deal with it seemed to me to solve any number of problems -- problems I had to deal with in various clunky ways before that development.
> I disagree there (that "That's a good argument in favor of OO programming").
But it is. The idea that all functions having any special meaning to (for example) strings would be enclosed within an object also containing the string to be operated on, greatly reduced the confusion that preceded it. One can make too much out of the OO paradigm, but the basic idea is sound and based on pragmatic thinking.
I'm sorry, but saying things like but it is and the basic idea is sound and based on pragmatic thinking without a supporting argument is unconvincing.
It's very hard to read code, because code isn't linear--it's more like de-serializing a graph in your head, and so it takes somewhere between O(n log n) and O(n^2) to fully grok a codebase of size N. So we should limit N as much as possible.
Now, as programmers, we theoretically know how to limit N just fine. We can still make programs as big as we like, but as long as there's low coupling between the components making up those programs, each component can be separated into its own codebase. Each component exports a documented API, each other component consumes those APIs, treating their dependent components as black boxes. This is well-known stuff.
But despite "decrease coupling!" being one of the first things pounded into most programmers in Introduction to Blub courses since the 70s, coupling is still way too high, and codebases far too large as a result. Low coupling, when dressed up in terms like "Service-oriented architecture" or "the Unix philosophy", is seen as mystifying and novel to most programming journeymen, like some sort of weird Eastern religion. This probably means that, despite learning what coupling is and being able to recite that definition in a sort of cargo-cult manner, they never really viscerally absorbed what coupling does, the pain it causes, or how to lower it[1].
You shouldn't have to dive into a codebase big enough to drown yourself in. Codebases shouldn't be that big. Each codebase should be more like a little puddle, maintained by a few people (or even just one narcissistic person!), which is small enough that, if someone gets hit by a bus (or gets annoyed with the narcissist), it's both able to be read in one sitting, or able to be re-written from scratch in one sprint.
Effectively, this creates a "bus factor" of infinity: if any component is small enough that it can be learned, or recreated, then the original programmer is unnecessary to that component's upkeep. Because, sort of like an EC2 instance, the component is just as likely to be created anew, as it is to be "closed" and then "opened" again.
---
[1] I imagine that you could imbue such knowledge with a single assignment to the effect of:
* We'll be working with three already-written programs, Foo, Bar, and Baz. They're each available in source-control on Github.
* Foo is componentized already, so it's split into five codebases. You can clone the main one, then run `git submodule update` to get the rest.
* Bar and Baz, meanwhile, are big monolithic codebases. Just clone the whole mess.
1. On each of the original projects, two open bugs is listed in the issues. Fix the first bug in your fork.
2. Now, refactor your fork of Bar into componentized form. Copy the submodule approach of Foo.
3. Now fix the second bug listed on each of the projects' issue-trackers.
Just a nitpick. You say one should first master reading, then master writing. But I think both go together; I would just reverse the logical order of the two concepts (small steps and reading-then-writing):
- read letters
- write letters
- read words
- write words
- read sentences
- write sentences
- read ideas
- write ideas
Of course, it is not a fixed frame either, but it gives the main idea.
I disagree, somewhat. I think one cannot become a skilled code-reader without knowing how to write code. One cannot be a skilled code-writer without knowing how to read code, and having read a lot of code, but without having written any code, I don't think reading code provides any enlightenment.
My small-steps progression would be writing Hello World, writing a smallish program, learning how to read code, writing code that you have to maintain, becoming skillful at reading code, becoming skillful at writing code.
I agree with you on natural language, that one must be a skilled reader before writing. I think the reason I see a difference between code and natural language is that the baby-steps of writing code can be mapped onto speaking natural language. I don't think one could become a skilled reader before being a proficient speaker in one's native tongue.
You make some good points, but as just one counterexample, the famed distorting effect of BASIC on a beginning programmer is certainly made worse by allowing the student to write BASIC as well as read it. As to, say, Python, I guess this is less of an issue, and writing a bit of Python just to see what happens probably has a beneficial effect on comprehension.
But, granted that point, I think reading and understanding the code of skilled programmers, before trying to write any significant code, is a very good idea. Otherwise one risks becoming trapped in classic beginner errors like laboriously processing individual data elements instead of looping through a list of them with one processing function (an error I saw any number of times while teaching programming).
I was actually tempted to comment about the language selection as well, but this post did mention that it was in the context of web development.
In programming, writing is first, reading second. Creating good code is something that is learned through work. Reading and judging other peoples code requires great insight and sympathy; criticising something is easy. Understanding that they could have done it differently but chose not to for some very good reason is harder by far.
> My poems are dreadful, my stories silly, but I've learned what makes others so talented.
I think one could learn skilled writing more quickly by reading than by writing, and without the esteem-crushing experience of seeing how badly one's own early experiments fall short. I emphasize that I'm talking about having an unrealistic expectation that one's own early writing serves as anything but an exercise to be quickly discarded -- referring to both programming and prose.
The author obviously didn't approach programming in the way people approach reading -- small steps first, letters, then words, then sentences, then ideas. And finally, after mastering reading, one can try writing one's own ideas.
It's not self-evident how to do this in the programming world, because unlike the world of books, programming is a relatively new discipline. But, just as with reading, there are small programming steps, and there's a distinction between reading and writing. One must be a skilled reader before presuming to write.
This will be easier in the future as programming matures, and when being able to program comes to be seen as print literacy is seen now -- a default ability in an educated person.