The Pragmatic Programmer: Your Journey to Mastery, 20th Anniversary Edition
Rate it:
Open Preview
58%
Flag icon
Why is writing concurrent and parallel code so difficult? One reason is that we learned to program using sequential systems, and our languages have features that are relatively safe when used sequentially but become a liability once two things can happen at the same time. One of the biggest culprits here is shared state. This doesn’t just mean global variables: any time two or more chunks of code hold references to the same piece of mutable data, you have shared state.
58%
Flag icon
Concurrent and parallel code used to be exotic. Now it is required.
58%
Flag icon
We need to allow for concurrency and to think about decoupling any time or order dependencies. In doing so, we can gain flexibility and reduce any time-based dependencies in many areas of development: workflow analysis, architecture, design, and deployment.
58%
Flag icon
An activity diagram consists of a set of actions drawn as rounded boxes. The arrow leaving an action leads to either another action (which can start once the first action completes) or to a thick line called a synchronization bar. Once all the actions leading into a synchronization bar are complete, you can then proceed along any arrows leaving the bar. An action with no arrows leading into it can be started at any time.
58%
Flag icon
use activity diagrams to maximize parallelism by identifying activities that could be performed in parallel, but aren’t.
59%
Flag icon
Activity diagrams show the potential areas of concurrency, but have nothing to say about whether these areas are worth exploiting.
62%
Flag icon
A lot of attention is given to shared memory as a source of concurrency problems, but in fact the problems can pop up anywhere where your application code shares mutable resources: files, databases, external services, and so on. Whenever two or more instances of your code can access some resource at the same time, you’re looking at a potential problem.
62%
Flag icon
concurrency in a shared resource environment is difficult, and managing it yourself is fraught with challenges.
62%
Flag icon
An actor is an independent virtual processor with its own local (and private) state.
62%
Flag icon
A process is typically a more general-purpose virtual processor, often implemented by the operating system to facilitate concurrency.
62%
Flag icon
The only state in the system is held in messages and in the local state of each actor. Messages cannot be examined except by being read by their recipient, and local state is inaccessible outside the actor.
62%
Flag icon
An actor processes each message to completion, and only processes one message at a time.
66%
Flag icon
Developers who don’t actively think about their code are programming by coincidence—the code might work, but there’s no particular reason why.
66%
Flag icon
Testing is not about finding bugs, it’s about getting feedback on your code: aspects of design, the API, coupling, and so on. That means that the major benefits of testing happen when you think about and write the tests, not just when you run them.
66%
Flag icon
As you gain experience as a programmer, your brain is laying down layers of tacit knowledge: things that work, things that don’t work, the probable causes of a type of error, all the things you notice throughout your days.
67%
Flag icon
We should avoid programming by coincidence—relying on luck and accidental successes—in favor of programming deliberately.
68%
Flag icon
Accidents of implementation are things that happen simply because that’s the way the code is currently written. You end up relying on undocumented error or boundary conditions.
68%
Flag icon
For routines you call, rely only on documented behavior. If you can’t, for whatever reason, then document your assumption well.
68%
Flag icon
Without a proper model of time handling, the entire large code base had devolved over time to an untenable mass of +1 and -1 statements. Ultimately, none of it was correct and the project was scrapped.
Mauricio Chirino
Beware of hacky “quick-temporary” resources.
68%
Flag icon
Are you relying on English-speaking users? Literate users? What else are you relying on that isn’t guaranteed?
68%
Flag icon
Finding an answer that happens to fit is not the same as the right answer.
68%
Flag icon
Assumptions that aren’t based on well-established facts are the bane of all projects.
68%
Flag icon
Can you explain the code, in detail, to a more junior programmer? If not, perhaps you are relying on coincidences.
68%
Flag icon
Don’t just test your code, but test your assumptions as well. Don’t guess; actually try it. Write an assertion to test your assumptions (see Topic 25, ​Assertive Programming​). If your assertion is right, you have improved the documentation in your code. If you discover your assumption is wrong, then count yourself lucky.
70%
Flag icon
If you have an algorithm that is , try to find a divide-and-conquer approach that will take you down to .
70%
Flag icon
be wary of premature optimization. It’s always a good idea to make sure an algorithm really is a bottleneck before investing your precious time trying to improve it.
71%
Flag icon
Rather than construction, software is more like gardening—it is more organic than concrete. You plant many things in a garden according to an initial plan and conditions. Some thrive, others are destined to end up as compost.
72%
Flag icon
Next time you see a piece of code that isn’t quite as it should be, fix it. Manage the pain: if it hurts now, but is going to hurt even more later, you might as well get it over with.
72%
Flag icon
the major benefits of testing happen when you think about and write the tests, not when you run them.
Mauricio Chirino
Thinking about the test itself makes us realise what we actually know about the implementation and if we truly understand the requirement behind the feature we’re writing
72%
Flag icon
Thinking about writing a test for our method made us look at it from the outside, as if we were a client of the code, and not its author.
73%
Flag icon
If you think about testing boundary conditions and how that will work before you start coding, you may well find the patterns in the logic that’ll simplify the function.
73%
Flag icon
By all means practice TDD. But, if you do, don’t forget to stop every now and then and look at the big picture. It is easy to become seduced by the green "tests passed" message, writing lots of code that doesn’t actually get you closer to a solution.
73%
Flag icon
Tests can definitely help drive development. But, as with every drive, unless you have a destination in mind, you can end up going in circles.
Mauricio Chirino
Don’t get caught on endlessly polishing tests and refactoring code
74%
Flag icon
Log messages should be in a regular, consistent format; you may want to parse them automatically to deduce processing time or logic paths that the program took. Poorly or inconsistently formatted diagnostics are just so much “spew”—they are difficult to read and impractical to parse.
74%
Flag icon
All software you write will be tested—if not by you and your team, then by the eventual users—so you might as well plan on testing it thoroughly.
74%
Flag icon
The worst choice is often called “Test Later,” but who are you kidding? “Test Later” really means “Test Never.”
78%
Flag icon
They make you think about your code in terms of invariants and contracts; you think about what must not change, and what must be true. This extra insight has a magical effect on your code, removing edge cases and highlighting functions that leave data in an inconsistent state.
Mauricio Chirino
The power of property based testing
79%
Flag icon
Good fences make good neighbors. Robert Frost, Mending Wall
79%
Flag icon
Never trust data from an external entity, always sanitize it before passing it on to a database, view rendering, or other processing.[63]
80%
Flag icon
don’t automatically grab the highest permission level, such as root or Administrator. If that high level is needed, take it, do the minimum amount of work, and relinquish your permission quickly to reduce the risk.
80%
Flag icon
Do not restrict special characters such as []();&%$# or /. See the note about Bobby Tables earlier in this section. If special characters in your password will compromise your system, you have bigger problems.
80%
Flag icon
Do not disable the paste function in the browser. Crippling the functionality of the browser and password managers does not make your system more secure, in fact it drives users to create simpler, shorter passwords that are much easier to compromise.
80%
Flag icon
You want to encourage long, random passwords with a high degree of entropy. Putting artificial constraints limits entropy and encourages bad password habits, leaving your user’s accounts vulnerable to takeover.
81%
Flag icon
The beginning of wisdom is to call things by their proper name. Confucius
81%
Flag icon
What’s in a name? When we’re programming, the answer is “everything!”
81%
Flag icon
Your brain treats written words as something to be respected. We need to make sure the names we use live up to this.
Mauricio Chirino
This is why we need to think hard about the names we give to our variables
81%
Flag icon
Honor the Culture
Mauricio Chirino
Adapt yourself (and your variables/method names) to that of the context -language/community- you’re writing code for
82%
Flag icon
If you aren’t vigilant about updating names as you go, you can quickly descend into a nightmare much worse than meaningless names: misleading names.
82%
Flag icon
Note from the battle-scarred: UTC is there for a reason. Use it.
83%
Flag icon
Perfection is achieved, not when there is nothing left to add but when there is nothing left to take away... Antoine de St. Exupery, Wind, Sand, and Stars, 1939