Learn humility.

This virtue makes a great personal value.

No one likes an obnoxious boor, the guy who is so proud of himself that all he can do is talk about his own accomplishments. The one who doesn’t care to hear what anyone else has to say because he’s sure that he’s right and everyone else is wrong. The person who thinks they are smarter and wiser than everyone else, so the party should shut up and listen to him.

So here’s a hot tip: don’t be that guy.

Be open to other people’s opinions. You can learn so much by listening to others. It’s simply not possible to know everything. You can gain from the wisdom of others only if you open yourself to hearing about their experiences. Even the smartest person in the room makes mistakes. The difference is, usually, he’s able to admit it. After all, you don’t get to be super smart unless you’re continually learning.

Be supportive, not bossy — especially when pairing. No one likes working with difficult people. But if you’re there to help and assist, then your presence is welcomed. We all go further when we work together, so check your ego at the door and be humble.

You aren’t gonna need it.

YAGNI. Believe it.

One way to avoid introducing problems in your codebase is to avoid adding unnecessary extra bits. When you add these things to your code, you are wasting time that you could better spend supporting the actual requirements. There is only so much time in the day. In a rush to finish features in time to meet deadlines, the quality of the desired product will suffer if you spend time on items that aren’t required.

When a developer adds extra features that are not part of the requirements, this results in a lot of extraneous code. You may end up adding unneeded classes, methods, logic structures, and database elements. These, in turn, will need additional tests and examples. If a certain percentage of code has bugs, on average, then it follows that more code means more bugs.

All of this extra code and time spent on unasked-for requirements will likely delay the release of the critical features that your sponsor desires. These delays result in reduced revenues for the business, which everyone wants to avoid. You don’t want to be known as the person who regularly causes delays.

Stick to the requirements, and you’ll have fewer problems and waste less time. Write the tests to meet all of the business requirements. Write the code that satisfies the tests. Then stop.

Learn the state pattern.

Better programmers learn patterns from other programmers.

Learning patterns is something most good programmers do as they gain expertise in software engineering. Once you realize you will gain knowledge faster if you don’t limit yourself to your own experience, you begin to study the wisdom others have acquired over the years. With millions of developers writing code for several decades now, people have learned several techniques that appear time and again. These are known as patterns.

One such technique is the State pattern. This pattern is helpful when an object’s behavior depends on its internal status. In this scenario, an object can be in only one state at any given time. In each given state, the behavior of the object is different. For example, say a car object has states REVERSE, PARKED, and INGEAR. A call to accelerate() will have different behavior depending on its state.

In this pattern, accelerate() is not an actual method in the car object, but rather an interface. Instead, concrete implementations define the method in classes that implement the interface. Another class controls the context, which determines which state the car object is in, and assigns the implementation class.

Each state limits the object’s behavior. So it is possible to have multiple methods in the implementation class if they are associated with that state. For example, maybe displayParkingLights() returns true (or performs other actions) for the PARKED implementation, but not for the other two.

The use of this pattern avoids large monolithic conditional statements. Plus, new states can be added (or an existing state altered) without changing the other states. Separating this behavior based on state also makes the code easier to test.

Write tests with realistic data.

Use detailed examples with precise answers.

When writing automated tests, it’s simply not enough to have unit tests covering the various positive and negative outcomes of each method. It would be best if you also had high-level tests that simulate business input. For these, you should have examples taken from real-world scenarios.

Try to have complete scenarios with all of the various anticipated inputs. These scenarios, in turn, should result in a detailed expected output. If you’re simulating a shopping cart in an e-commerce application, include several items of different types in your tests and ensure that all of the totals, tax, and shipping compute as expected.

One reason we do this comes from QA teams. Running through realistic scenarios is the kind of thing they would do by hand, as a smoke test. There’s no reason for something this simple to be a manual test, though. Ultimately it would be most helpful to replace all of the manual tests people like to do in your application with automated tests that use the realistic data that humans might enter.

And of course, you should also include negative tests as part of this. Include common mistakes that a human might enter to ensure that all of the validation is working and delivering error messages as expected.

Go read some code.

Authors read a lot of books to get better at their art.

One thing you can do to become a better developer is to examine other people’s code deeply. Thankfully because of the large amount of great open-source software available, this is easy to do. Like an author reading lots of books to master the art of storytelling, you can examine the source code of many great programs to improve your programming techniques.

As you examine other people’s programs, ask yourself, is it easy to understand? Did the author write code in such a way as to make it easy for other people to expand and improve on it? If you find code that is not easy to understand, ask yourself why. Is it because they were intentionally trying to be cryptic, or is it because there are patter and techniques at play that you are not familiar with?

Read the code you wrote from a year ago. Is it as easy to read now as it was then? The chances are good that you will be disappointed in how little the historical you thought of future you. This is an excellent exercise to help encourage you to write better code that future developers can use.

Look for good and bad patterns in other people’s code. Often, in packages with few reviews, you can see developers making mistakes, using antipatterns, and otherwise doing regrettable things. You can learn from bad code as well as good code.

Step away if you get stuck.

Sometimes you need to sleep on it.

Everyone has had those days where you are stuck on a problem and can’t figure out a solution. The more you analyze it, the more you keep finding flaws and concerns. No one ever said that writing software to solve real issues would be easy!

When this happens, sometimes it’s best to back away from the problem for a while. Take a break. Go outside and walk around the block. Help someone else with their issues; if you can’t solve your own problem, you can still be productive by helping others. Plus, the time away may help clear your head and bring you some ideas.

In some cases, you need to put the problem aside for the day. It often happens that after a night’s rest, the solution may come to you more easily. It may even hit you in your morning shower.

There are other strategies. Do something creative. Write some stories, draw some pictures, do something using your hands. Maybe work in the garden. By engaging your brain in more creative activities, your neural connections may consider new possibilities, and new ideas will pop into your head. Give it a try.

Know the acceptance criteria.

You can’t get there if you don’t know where you are going.

Often, people will ask developers to add or improve a feature and give minimal details. If the developers start coding based on this incomplete information, chances are pretty high that the delivered code will not meet the customer’s expectations. These changes could also introduce bugs in the application. The developer will need to do lots of rework as additional feedback comes in, describing a little bit more accurately what the customer desired. Several back and forth rounds may occur, in an “agile” iterative fashion, causing extensive delays in the delivery of the final product. These delays will cause missed expectations and leave everyone unsatisfied.

Extended cycle times and rework are very costly. There is a better way. At the very least, each request should have its acceptance criteria spelled out in clear language. If the development team commits to having concrete details in their user stories before starting implementation, there will be less rework later on. Forcing the product owner to specify acceptance criteria before the developers write the first line of code will not eliminate all rework, but it should significantly reduce it.

If you know your goal before you start, and you are more likely to achieve it.

(Thanks to David Kidd for contributing ideas for this one.)

Use less magic.

The code should communicate the intent of the developers.

Frameworks are very powerful and enable the software engineer to take a lot of shortcuts in development. Sometimes, these shortcuts appear to make things happen like magic. Unfortunately, sometimes too much magic results in confusion and a loss of clarity. So while the code may work properly and pass tests, it becomes a challenge for a future programmer to modify it correctly.

Do a favor to the next developer who has to look at your code and ensure that your intent is obvious. Developers typically spend much more time reading code than writing it, so it behooves us to write code that is easier to read and understand.

Earn it.

You’re a professional programmer.

When you pay a doctor to examine your health and provide treatment, you expect high-quality service. Your health is very important, and you are spending good money on the doctor’s services. An improper diagnosis due to lazy efforts by the doctor or the medical staff could have severe effects on you.

When you hire a lawyer for legal advice, you need her expert opinion and counsel. The law is vast and complicated. It is not often that you need a lawyer’s services, but when you do, you need that lawyer to render expert-level services.

When you hire mechanics to work on your car, you trust them to repair and reassemble your vehicle correctly. If your vehicle were to fall apart while you were cruising down the Interstate, the results could be quite unfavorable. So you don’t trust just anyone to fix your car.

The examples go on and on. The architect who designs your house. The dentist who removes a tooth. The teacher who instructs your children. We expect these professionals to do their jobs well.

People expect the same of you. Your employer pays you good money to write software. Countless people could use these programs in the future. Businesses may depend on the results of the systems you build. Thus you should take your job very seriously, commit to high-quality results, and create great products that others can rely on.

Write code in English.

You don’t speak in code, but you can make the code speak to others.

When you write software, you should view it as a form of communication. The message you are trying to send is a declaration of intent to the next programmer who has to read your code. The logical arrangement of methods and symbols will instruct the system on how to perform a routine. The naming of methods and objects is where you communicate to others what the intended result should be.

Write in English, not in code. As best as you can, you should use plain words to describe what is going on. Do not abbreviate when it is not necessary. Always make the intent clear and distinct. It should be obvious at a glance what method intends to do and which objects it is working on.

Avoid using technical language. Instead, use words from the business domain. Also, avoid vague terms like “status,” “type,” and “flag.” If a customer_account object has three attributes named status, type, and flag, then it is uncertain how a developer should use each of these attributes.

The easier it is to read and understand code, the better. It will be less likely that there will be misunderstandings that lead to defects. As we all care deeply about code quality, we should try to make this job easy on ourselves.