More on this book
Community
Kindle Notes & Highlights
by
Andy Hunt
Read between
October 2 - December 26, 2020
As a programmer, you are part listener, part advisor, part interpreter, and part dictator. You try to capture elusive requirements and find a way of expressing them so that a mere machine can do them justice.
You try to document your work so that others can understand it, and you try to engineer your work so that others can build on it. What’s more, you try to do all this against the relentless ticking of the project clock. You work small miracles every day. It’s a difficult job.
There is no best solution, be it a tool, a language, or an operating system. There can only be systems that are more appropriate in a particular set of circumstances.
What distinguishes Pragmatic Programmers? We feel it’s an attitude, a style, a philosophy of approaching problems and their solutions. They think beyond the immediate problem, placing it in its larger context and seeking out the bigger picture.
Martin Fowler says, “you can change your organization or change your organization.”[3]
We can be proud of our abilities, but we must own up to our shortcomings—our ignorance and our mistakes.
Instead of excuses, provide options. Don’t say it can’t be done; explain what can be done to salvage the situation. Does code have to be deleted? Tell them so, and explain the value of refactoring
When disorder increases in software, we call it “software rot.” Some folks might call it by the more optimistic term, “technical debt,” with the implied notion that they’ll pay it back someday. They probably won’t.
Don’t leave “broken windows’’ (bad designs, wrong decisions, or poor code) unrepaired. Fix each one as soon as it is discovered. If there is insufficient time to fix it properly, then board it up.
many users would rather use software with some rough edges today than wait a year for the shiny, bells-and-whistles version
Great software today is often preferable to the fantasy of perfect software tomorrow.
Always have something to read in an otherwise dead moment. Time spent waiting for doctors and dentists can be a great opportunity to catch up on your reading—but
Never underestimate the power of commercialism. Just because a web search engine lists a hit first doesn’t mean that it’s the best match;
Just because a bookstore features a book prominently doesn’t mean it’s a good book, or even popular; they may have been paid to place it there.
A good idea is an orphan without effective communication.
As developers, we have to communicate on many levels. We spend hours in meetings, listening and talking. We work with end users, trying to understand their needs. We write code, which communicates our intentions to a machine and documents our thinking for future generations of developers. We write proposals and memos requesting and justifying resources, reporting our status, and suggesting new approaches. And we work daily within our teams to advocate our ideas, modify existing practices, and suggest new ones. A large part of our day is spent communicating, so we need to do it well.
Treat English (or whatever your native tongue may be) as just another programming language. Write natural language as you would write code: honor the DRY principle, ETC, automation, and so on. (We discuss ...
This highlight has been truncated due to consecutive passage length restrictions.
You’re communicating only if you’re conveying what you mean to convey—just talking isn’t enough. To do that, you need to understand the needs, interests, and capabilities of your audience.
As with all forms of communication, the trick here is to gather feedback. Don’t just wait for questions: ask for them. Look at body language, and facial expressions. One of the Neuro Linguistic Programming presuppositions is “The meaning of your communication is the response you get.” Continuously improve your knowledge of your audience as you communicate.
Plan what you want to say. Write an outline. Then ask yourself, “Does this communicate what I want to express to my audience in a way that works for them?” Refine it until it does.
Make what you’re saying relevant in time, as well as in content. Sometimes all it takes is the simple question, “Is this a good time to talk about…?’’
Your ideas are important. They deserve a good-looking vehicle to convey them to your audience. Too many developers (and their managers) concentrate solely on content when producing written documents. We think this is a mistake. Any chef (or watcher of the Food Network) will tell you that you can slave in the kitchen for hours only to ruin your efforts with poor presentation.
There is no excuse today for producing poor-looking printed documents.
If possible, involve your readers with early drafts of your document. Get their feedback, and pick their brains. You’ll build a good working relationship, and you’ll probably produce a better document in the process.
There’s one technique that you must use if you want people to listen to you: listen to them.
Writing documentation can be made easier by not duplicating effort or wasting time, and by keeping documentation close at hand—in the code itself.
So restrict your non-API commenting to discussing why something is done, its purpose and its goal. The code already shows how it is done, so commenting on this is redundant—and is a violation of the DRY principle.
If you wouldn’t say it to someone’s face, don’t say it online.
try to make what you write replaceable. That way, whatever happens in the future, this chunk of code won’t be a roadblock.
Note the situation in your engineering day book: the choices you have, and some guesses about change. Leave a tag in the source. Then, later, when this code has to change, you’ll be able to look back and give yourself feedback. It might help the next time you reach a similar fork in the road.
Programmers are constantly in maintenance mode. Our understanding changes day by day. New requirements arrive and existing requirements evolve as we’re heads-down on the project. Perhaps the environment changes. Whatever the reason, maintenance is not a discrete activity, but a routine part of the entire development process.
The code is the same, but the knowledge they represent is different. The two functions validate two separate things that just happen to have the same rules. That’s a coincidence, not a duplication.
DRY isn't about avoiding duplication at all cost, that just leads to tightly couple code that's rigid to change because an update in a single place affects multiple locations.
Somehow the myth was born that you should comment all your functions.
whenever a module exposes a data structure, you’re coupling all the code that uses that structure to the implementation of that module. Where possible, always use accessor functions to read and write the attributes of objects. It will make it easier to add functionality in the future.
All services offered by a module should be available through a uniform notation, which does not betray whether they are implemented through storage or through computation.
Rather than writing code that represents external data in a fixed structure (an instance of a struct or class, for example), just stick it into a key/value data structure (your language might call it a map, hash, dictionary, or even object). On its own this is risky: you lose a lot of the security of knowing just what data you’re working with. So we recommend adding a second layer to this solution: a simple table-driven validation suite that verifies that the map you’ve created contains at least the data you need, in the format you need it.
Two or more things are orthogonal if changes in one do not affect any of the others. In a well-designed system, the database code will be orthogonal to the user interface:
If components have specific, well-defined responsibilities, they can be combined with new components in ways that were not envisioned by their original implementors.
Systems should be composed of a set of cooperating modules, each of which implements functionality independent of the others.
Because each layer uses only the abstractions provided by the layers below it, you have great flexibility in changing underlying implementations without affecting code. Layering also reduces the risk of runaway dependencies between modules.
There is an easy test for orthogonal design. Once you have your components mapped out, ask yourself: If I dramatically change the requirements behind a particular function, how many modules are affected? In an orthogonal system, the answer should be “one.’’[16]
Don’t rely on the properties of things you can’t control.
Write shy code—modules that don’t reveal anything unnecessary to other modules and that don’t rely on other modules’ implementations.
Every time your code references global data, it ties itself into the other components that share that data. Even globals that you intend only to read can lead to trouble (for example, if you suddenly need to change your code to be multithreaded).
Writing unit tests is itself an interesting test of orthogonality. What does it take to get a unit test to build and run? Do you have to import a large percentage of the rest of the system’s code? If so, you’ve found a module that is not well decoupled from the rest of the system.
If you’re brought into a project where people are desperately struggling to make changes, and where every change seems to cause four other things to go wrong, remember the nightmare with the helicopter. The project probably is not orthogonally designed and coded. It’s time to refactor.
Nothing is forever—and if you rely heavily on some fact, you can almost guarantee that it will change.
There is always more than one way to implement something, and there is usually more than one vendor available to provide a third-party product. If you go into a project hampered by the myopic notion that there is only one way to do it, you may be in for an unpleasant surprise.
The mistake lies in assuming that any decision is cast in stone—and in not preparing for the contingencies that might arise. Instead of carving decisions in stone, think of them more as being written in the sand at the beach. A big wave can come along and wipe them out at any time.