Skip to content

Instantly share code, notes, and snippets.

@cyyeh
Last active March 20, 2024 17:46
Show Gist options
  • Save cyyeh/ea14108c6821c1ce33ac3f58541259d4 to your computer and use it in GitHub Desktop.
Save cyyeh/ea14108c6821c1ce33ac3f58541259d4 to your computer and use it in GitHub Desktop.
97 things every programmer should know

Table of Contents

Bugs and Fixes

  • Check your code first before looking to blame others
  • Don't touch that code!
  • How to use a bug tracker
  • Two wrongs can make a right (and are difficult to fix)

Build and Deployment

  • Deploy early and often
  • Don't touch that code!
  • Install me
  • Keep the build clean
  • Let your project speak for itself
  • One binary
  • Own (and refactor) the build

Coding Guidelines and Code Layout

  • Automate your coding standard
  • Code layout matters
  • Code reviews
  • A comment on comments
  • Comment only what the code cannot say
  • Take advantage of code analysis tools

Design Principles and Coding Techniques

  • Apply functional programming principles
  • Ask, "what would the user do?"(you are not the user)
  • Beauty is in simplicity
  • Choose your tools with care
  • Code in the language of the domain
  • Code is design
  • Coding with reason
  • Convenience is not an -ility
  • Distinguish business exceptions from technical
  • Don't repeat yourself
  • Don't repeat yourself
  • Encapsulate behavior, not just state
  • The golden rule of api design
  • Interprocess communication affects application response time
  • Make interfaces easy to use correctly and hard to use incorrectly
  • Message passing leads to better scalability in parallel systems
  • Missing opportunities for polymorphism
  • Only the code tells the truth
  • Prefer domain-specific types to primitive types
  • Prevent errors
  • Resist the temptation of the singleton pattern
  • The single responsibility principle
  • Thinking in states
  • WET dilutes performance bottlenecks

Domain Thinking

  • Code in the language of the domain
  • Domain-specific languages
  • Learn foreign languages
  • Prefer domain-specific types to primitive types
  • Read the humanities
  • Thinking in states
  • Write small functions using examples

Errors, Error Handling, and Exceptions

  • Distinguish business exceptions from technical
  • Don't ignore that error!
  • Don't nail your program into the upright position
  • Prevent errors
  • Verbose logging will disturb your sleep

Learning, skills, and expertise

  • Continuous learning
  • Do lots of deliberate practice
  • Don't just learn the language, understand its culture
  • Fulfill your ambitions with open source
  • The guru myth
  • Hard work does not pay off
  • Read code
  • Read the humanities
  • Reinvent the wheel often

Nocturnal or Magical

  • Don't rely on "magic happens here"
  • Don't touch that code!
  • The guru myth
  • Know how to use command-line tools
  • The linker is not a magical program
  • Test while you sleep (and over weekends)
  • Verbose logging will disturb your sleep
  • Write code as if you had to support it for the rest of your life

Performance, Optimization, and Representation

  • Apply functional programming principles
  • Floating-point numbers aren't real
  • Improve code by removing it
  • Interprocess communication affects application response time
  • Know your limits
  • Large, interconnected data belongs to a database
  • Message passing leads to better scalability in parallel systems
  • The road to performance is littered with dirty code bombs
  • Use the right algorithm and data structure
  • WET dilutes performance bottlenecks

Professionalism, Mindset, and Attitude

  • Continuous learning
  • Do lots of deliberate practice
  • Hard work does not pay off
  • The longevity of interim solutions
  • The professional programmer
  • Put the mouse down and step away from the keyboard
  • Testing is the engineering rigor of software development
  • Write code as if you had to support it for the rest of your life
  • You gotta care about the code

Programming Languages and Paradigms

  • Apply functional programming principles
  • Domain-specific languages
  • Don't just learn the language, understand its culture
  • Know well more than two programming languages
  • Learn foreign languages

Refactoring and Code Care

  • Act with prudence
  • Before you refactor
  • The boy scout rule
  • Comment only what the code cannot say
  • Don't be afraid to break things
  • Improve code by removing it
  • Keep the build clean
  • Know your next commit
  • The longevity of interim solutions
  • A message to the future
  • Only the code tells the truth
  • Own (and refactor) the build
  • The professional programmer
  • The road to performance is littered with dirty code bombs
  • Simplicity comes from reduction
  • Ubuntu coding for your friends
  • You gotta care about the code

Reuse Versus Repetition

  • Beware the share
  • Convenience is not an -ility
  • Do lots of deliberate practice
  • Don't repeat yourself
  • Reinvent the wheel often
  • Use the right algorithm and data structure
  • WET dilutes performance bottlenecks

Schedules, Deadlines, and Estimates

  • Act with prudence
  • Code is design
  • Know your next commit
  • Learn to estimate
  • Make the invisible more visible

Simplicity

  • Beauty is in simplicity
  • Learn to say, "hello, world"
  • A message to the future
  • Simplicity comes from reduction

Teamwork and Collaboration

  • Code reviews
  • Learn foreign languages
  • Pair program and feel the flow
  • Start from Yes
  • Two heads are often better than one
  • Ubuntu coding for your friends
  • When programmers and testers collaborate

Tests, Testing, and Testers

  • Apply functional programming principles
  • Code is design
  • Don't be cute with your test data
  • The golden rule of api design
  • Make interfaces easy to use correctly and hard to use incorrectly
  • Make the invisible more visible
  • News of the weird: testers are your friends
  • Test for required behavior, not indicental behavior
  • Test precisely and concretely
  • Test while you sleep(and over weekends)
  • Testing is the engineering rigor of software development
  • When programmers and testers collaborate
  • Write small functions using examples
  • Write tests for people

Tools, Automation, and Development Environments

  • Automate your coding standard
  • Check your code first before looking to blame others
  • Choose your tools with care
  • Don't repeat yourself
  • How to use a bug tracker
  • Know how to use command-line tools
  • Know your IDE
  • Large, interconnected data belongs to a database
  • Learn to say, "hello, world"
  • Let your project speak for itself
  • The linker is not a magical program
  • Put everything under version control
  • Step back and automate, automate, automate
  • Take advantage of code analysis tools
  • Test while you sleep (and over weekends)
  • The Unix tools are your friends

Users and Customers

  • Ask, "what would the user do?" (you are not the user)
  • Domain-specific languages
  • Make interfaces easy to use correctly and hard to use incorrectly
  • News of the weird: testers are yur friends
  • Prevent errors
  • Read the humanities
  • Your customers do not mean what they say

Bugs and Fixes

Check Your Code First Before Looking to Blame Others, Allan Kelly

  • Assuming that the tools are widely used, mature, and employed in various technology stacks, there is little reason to doubt the quality. Of course, if the tool is an early release, or used by only a few people worldwide, or a piece of seldom downloaded, version 0.1, open source software, there may be good reason to suspect the software. (Equally, an alpha version of commercial software might be suspect.)
  • All the usual debugging advice applies, so isolate the problem, stub out calls, and surround it with tests; check calling conventions, shared libraries, and version numbers; explain it to someone else; look out for stack corrup- tion and variable type mismatches; and try the code on different machines and different build configurations, such as debug and release.
  • Question your own assumptions and the assumptions of others.
  • Multithreaded problems are another source of bugs that turn hair gray and induce screaming at the machine. All the recommendations to favor simple code are multiplied when a system is multithreaded. Debugging and unit tests cannot be relied on to find such bugs with any consistency, so simplicity of design is paramount.
  • Once you eliminate the impossible, whatever remains, no matter how improbable, must be the truth.

Don’t Touch That Code!, Cal Evans

  • A developer— even a senior developer—should never have access beyond the development server. Most development is done on a developer’s local machine using his favorite blend of IDEs, virtual machines, and an appropriate sprinkling of black magic for good luck.
  • Under no circumstances—ever, at all—should a developer have access to a production server. If there is a problem, your support staff should either fix it or request that you fix it.

How to Use a Bug Tracker, Matt Doar

  • A good bug report needs to convey three things
    • How to reproduce the bug, as precisely as possible, and how often this will make the bug appear
    • What should have happened, at least in your opinion
    • What actually happened, or at least as much information as you have recorded
  • Bugs are like a conversation, with all the history right there in front of everyone. Don’t blame others or deny the bug’s very existence. Instead, ask for more information or consider what you could have missed.
  • Changing the status of a bug—e.g., Open to Closed—is a public statement of what you think of the bug. Taking the time to explain why you think the bug should be closed will save tedious hours spent later on justifying it to frustrated managers and customers.
  • Changing the priority of a bug is a similar public statement, and just because it’s trivial to you doesn’t mean it isn’t stopping someone else from using the product.
  • Finally, remember that a bug is not a standard unit of work any more than a line of code is a precise measurement of effort.

Two Wrongs Can Make a Right (and Are Difficult to Fix), Allan Kelly

  • When two defects in the code create one visible fault, the methodical approach to fixing faults can itself break down. The developer gets a bug report, finds the defect, fixes it, and retests. The reported fault still occurs, however, because a second defect is at work. So the first fix is removed, the code inspected until the second underlying defect is found, and a fix applied for that. But the first defect has returned, the reported fault is still seen, and so the second fix is rolled back. The process repeats, but now the developer has dismissed two possible fixes and is looking to make a third that will never work.
  • Single wrongs can be easy to spot and easy to fix. It is the problems with multiple causes, needing multiple changes, that are harder to resolve. In part, this is because easy problems are so easily fixed that people tend to fix them relatively quickly and store up the more difficult problems for a later date.
  • There is no simple advice for how to address faults arising from sympathetic defects. Awareness of the possibility, a clear head, and a willingness to consider all possibilities are needed.

Design Principles and Coding Techniques

Apply Functional Programming Principles, Edward Garson

  • Mastery of the functional programming paradigm can greatly improve the quality of the code you write in other contexts. If you deeply understand and apply the functional paradigm, your designs will exhibit a much higher degree of referential transparency.

Ask, “What Would the User Do?” (You Are Not the User), Giles Colborne

  • WE ALL TEND TO ASSUME THAT OTHER PEOPLE THiNK LiKE US. But they don’t. Psychologists call this the false consensus bias.
  • The best way to find out how a user thinks is to watch one. Ask a user to complete a task using a similar piece of software to what you’re developing.
  • Avoid tasks that are too specific.
  • Get the user to talk through his or her progress. Don’t interrupt. Don’t try to help. Keep asking yourself, “Why is he doing that?” and “Why is she not doing that?”
  • The first thing you’ll notice is that users do a core of things similarly. They try to complete tasks in the same order and they make the same mistakes in the same places. You should design around that core behavior.
  • You’ll see users getting stuck. When you get stuck, you look around. When users get stuck, they narrow their focus. It becomes harder for them to see solutions elsewhere on the screen. A user’s narrow focus of attention is why tool tips are more useful than help menus.
  • You’ll also find that there’s a gap between what users say they want and what they actually do. That’s worrying, as the normal way of gathering user requirements is to ask them. It’s why the best way to capture requirements is to watch users.

Beauty Is in Simplicity, Jørn Ølmheim

  • Beauty of style and harmony and grace and good rhythm depends on simplicity.
  • There are a number of things we strive for in our code: Readability, Maintainability, Speed of development and The elusive quality of beauty. Plato is telling us that the enabling factor for all of these qualities is simplicity.
  • The bottom line is that beautiful code is simple code. Each individual part is kept simple with simple responsibilities and simple relationships with the other parts of the system. This is the way we can keep our systems maintain- able over time, with clean, simple, testable code, ensuring a high speed of development throughout the lifetime of the system.

Choose Your Tools with Care, Giovanni Asproni

  • In fact, when making a choice, you should keep in mind a few things:
    • Different tools may rely on different assumptions about their context—e.g., surrounding infrastructure, control model, data model, communication protocols, etc.—which can lead to an architectural mismatch between the application and the tools. Such a mismatch leads to hacks and workarounds that will make the code more complex than necessary.
    • Different tools have different lifecycles, and upgrading one of them may become an extremely difficult and time-consuming task since the new func- tionality, design changes, or even bug fixes may cause incompatibilities with the other tools. The greater the number of tools, the worse the problem can become.
    • Some tools require quite a bit of configuration, often by means of one or more XML files, which can grow out of control very quickly. The applica- tion may end up looking as if it was all written in XML plus a few odd lines of code in some programming language. The configurational complexity will make the application difficult to maintain and to extend.
    • Vendor lock-in occurs when code that depends heavily on specific ven- dor products ends up being constrained by them on several counts: maintainability, performances, ability to evolve, price, etc.
    • If you plan to use free software, you may discover that it’s not so free after all. You may need to buy commercial support, which is not necessarily going to be cheap.
    • Licensing terms matter, even for free software. For example, in some companies, it is not acceptable to use software licensed under the GNU license terms because of its viral nature—i.e., software developed with it must be distributed along with its source code.
  • My personal strategy to mitigate these problems is to start small by using only the tools that are absolutely necessary. Usually the initial focus is on removing the need to engage in low-level infrastructure programming (and problems), e.g., by using some middleware instead of using raw sockets for distributed applications. And then add more if needed. I also tend to isolate the external tools from my business domain objects by means of interfaces and layering, so that I can change the tool if I have to with a minimal amount of pain.

Code in the Language of the Domain, Dan North

  • Making domain concepts explicit in your code means other programmers can gather the intent of the code much more easily than by trying to retrofit an algo- rithm into what they understand about a domain.
  • It also means that when the domain model evolves—which it will, as your understanding of the domain grows—you are in a good position to evolve the code. Coupled with good encap- sulation, the chances are good that the rule will exist in only one place, and that you can change it without any of the dependent code being any the wiser.

Users and Customers

Ask, "what would the user do?" (you are not the user), Giles Colborne

  • WE ALL TEND TO ASSUME THAT OTHER PEOPLE THiNK LiKE US. But they don’t. Psychologists call this the false consensus bias.
  • The best way to find out how a user thinks is to watch one. Ask a user to complete a task using a similar piece of software to what you’re developing.
  • Avoid tasks that are too specific.
  • Get the user to talk through his or her progress. Don’t interrupt. Don’t try to help. Keep asking yourself, “Why is he doing that?” and “Why is she not doing that?”
  • The first thing you’ll notice is that users do a core of things similarly. They try to complete tasks in the same order and they make the same mistakes in the same places. You should design around that core behavior.
  • You’ll see users getting stuck. When you get stuck, you look around. When users get stuck, they narrow their focus. It becomes harder for them to see solutions elsewhere on the screen. A user’s narrow focus of attention is why tool tips are more useful than help menus.
  • You’ll also find that there’s a gap between what users say they want and what they actually do. That’s worrying, as the normal way of gathering user requirements is to ask them. It’s why the best way to capture requirements is to watch users.

Domain-Specific Languages, Michael Hunger

  • A specific domain has a specialized vocabulary to describe the things that are particular to that domain.
  • Internal DSLs
    • Are written in a general-purpose programming language whose syntax has been bent to look much more like natural language.
    • Depending on the implementation and the domain, they are used to build data structures, define dependencies, run processes or tasks, communicate with other systems, or validate user input.
  • External DSLs
    • Are textual or graphical expressions of the language; although textual DSLs tend to be more common than graphical ones.
  • You must always take the target audience of your DSL into account. Are they developers, managers, business customers, or end users? You have to adapt the technical level of the language, the available tools, syntax help (e.g., IntelliSense), early validation, visualization, and representation to the intended audience.

Make Interfaces Easy to Use Correctly and Hard to Use Incorrectly, Scott Meyers

  • ONE OF THE MOST COMMON TASKS in software development is interface specification. Interfaces occur at the highest level of abstraction (user interfaces), at the lowest (function interfaces), and at levels in between (class interfaces, library interfaces, etc.).
  • Good interfaces are
    • Easy to use correctly: People using a well-designed interface almost always use the interface correctly, because that’s the path of least resistance.
    • Hard to use incorrectly: Good interfaces anticipate mistakes people might make, and make them difficult—ideally, impossible—to commit.
  • A good way to design interfaces that are easy to use correctly is to exercise them before they exist. You’re more likely to come up with such interfaces if you develop them from a user’s point of view. (This perspective is one of the strengths of test-first programming.)
  • Making interfaces hard to use incorrectly requires two things. First, you must anticipate errors users might make and find ways to prevent them. Second, you must observe how an interface is misused during early release and modify the interface—yes, modify the interface!—to prevent such errors.
  • Above all, remember that interfaces exist for the convenience of their users, not their implementers.

News of the Weird: Testers Are Your Friends, Burk Hufnagel

  • In my experience, programmers often have an adversarial relationship with the people who test their software. “They’re too picky” and “They want everything perfect” are common complaints. Sound familiar?
  • You may think the testers make you look bad by reporting trivial issues. But when customers are thrilled because they weren’t bothered by all those “little things” that QC made you fix, then you look great. See what I mean?

Prevent Errors, Giles Colborne

  • It is easy to think of an error as being caused by a wrong input from the user. But people make mistakes in predictable, systematic ways. So it is possible to “debug” the communication between the user and the rest of the system just as you would between other system components.
  • Formatting errors are another common problem. Instead, respect users’ preference to enter information, not data. Another way of avoiding formatting errors is to offer cues—for instance, with a label within the field showing the desired format (“DD/MM/YYYY”). Another cue might be to divide the field into three text boxes of two, two, and four characters.
  • Cues are different from instructions: cues tend to be hints; instructions are verbose. Cues occur at the point of interaction; instructions appear before the point of interaction. Cues provide context; instructions dictate use.
  • In general, instructions are ineffective at preventing error. Users tend to assume that interfaces will work in line with their past experience (“Surely everyone knows what ‘July 29, 2012’ means?”). So instructions go unread. Cues nudge users away from errors.
  • Another way of avoiding errors is to offer defaults.
  • Whatever the cause, systems should be tolerant of errors. You can facilitate this by providing multiple levels of undo to all actions—and, in particular, actions that have the potential to destroy or amend users’ data.
  • Logging and analyzing undo actions can also highlight where the interface is drawing users into unconscious errors, such as persistently clicking on the “wrong” button. These errors are often caused by misleading cues or interac- tion sequences that you can redesign to prevent further error.
  • Whichever approach you take, most errors are systematic—the result of misunderstandings between the user and the software. Understanding how users think, interpret information, make decisions, and input data will help you debug the interactions between your software and your users.

Read the Humanities, Keith Braithwaite

  • People write software with people for people. It’s a people business. Unfortunately, what is taught to programmers too often equips them very poorly to deal with people they work for and with.
  • Ludwig Wittgenstein makes a very good case in Philosophical Investigations (Wiley-Blackwell), and elsewhere, that any language we use to speak to one another is not—cannot be—a serialization format for getting a thought or idea or picture out of one person’s head and into another’s.
  • Wittgenstein also shows that our ability to understand one another at all does not arise from shared definitions, it arises from a shared experience, from a form of life.
  • Lakoff and Johnson present us with a catalog of Metaphors We Live By (University of Chicago Press), suggesting that language is largely metaphorical, and that these metaphors offer an insight into how we understand the world.
  • Martin Heidegger studied closely the ways that people experience tools. Programmers build and use tools, we think about and create and modify and recreate tools. Tools are objects of interest to us. But for its users, as Heiddeger shows in Being and Time (Harper Perennial), a tool becomes an invisible thing understood only in use. For users, tools only become objects of interest when they don’t work. This difference in emphasis is worth bearing in mind whenever usability is under discussion.
  • Eleanor Rosch overturned the Aristotelean model of the categories by which we organize our understanding of the world. When programmers ask users about their desires for a system, we tend to ask for definitions built out of predicates. This is very convenient for us. The terms in the predicates can very easily become attributes on a class or columns in a table. These sorts of catego- ries are crisp, disjoint, and tidy. Unfortunately, as Rosch showed in “Natural Categories” and later works, that just isn’t how people in general understand the world. They understand it in ways that are based on examples. Some exam- ples, so-called prototypes, are better than others and so the resulting categories are fuzzy, they overlap, they can have rich internal structure. Insofar as we insist on Aristotelean answers, we can’t ask users the right questions about the user’s world, and will struggle to come to the common understanding we need.

Your Customers Do Not Mean What They Say, Nate Jackson

  • The problem is that customers don’t always tell you the whole truth. They generally don’t lie, but they speak in customer speak, not developer speak. They use their terms and their contexts. They leave out significant details. They make assumptions that you’ve been at their company for 20 years, just like they have. This is compounded by the fact that many customers don’t actually know what they want in the first place!
  • Just interact with them more. Challenge your customers early, and challenge them often. Don’t simply restate what they told you they wanted in their words. Remember: they didn’t mean what they told you. I often implement this advice by swapping out the customer’s words in conversation with them and judging their reaction.
  • You’d be amazed how many times the term customer has a completely different meaning from the term client. Yet the guy telling you what he wants in his software project will use the terms interchangeably and expect you to keep track as to which one he’s talking about. You’ll get confused, and the software you write will suffer.
  • If at all possible, have multiple people tell you about the same topic in separate conversations. They will almost always tell you different stories, which will uncover separate yet related facts.
  • Two people telling you about the same topic will often contradict each other. Your best chance for success is to hash out the differences before you start your ultra-complex software crafting.
  • Use visual aids in your conversations.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment