Go to the source.

The code tells the true story.

Since only the source tells us what the code is truly doing, you want to make it as readable as possible. There many things one can do to improve the quality of the source code for the reader. Future programmers will be thanking you.

Comments and design documents will go out of date. Sometimes they’re outdated before the primary development is even finished. Thus it is best if the comments not describe what the source is doing. Instead, comments should explain why the objects and methods exist. The reader would love to understand why some decisions were made.

Another thing to do is to use meaningful names. Avoid technical jargon. Instead, use words from the business domain. If the code itself can tell the story, then there is less need for documentation that is rapidly going out of date. It also helps if you refactor to smaller methods. When a method has only one job, its name tends to be more accurately descriptive.

One more thing that will help future readers immensely is to have excellent test coverage. A well-written test explains the intended behavior. Some tests also contain examples that can describe how the application should handle edge cases, situations that might not be covered by other documentation. Great tests are the best!

Follow your passions.

You’ll always put a lot more effort into tasks you love doing.

“Find a job you enjoy doing, and you will never have to work a day in your life.” — Mark Twain

When you deeply care about your work, you will enjoy your work more. The whole situation switches from toil to a profession. It’s not your “day job”. It’s what you do. It’s what you are all about. Some people punch a clock; better people are committed to becoming even better because they want to be the best.

Following your passions will also help you overcome any fears. Your focus moves from trying to please others to learning more and gaining mastery in your craft.

You will also be more motivated to succeed. People who don’t love what they do just aim for satisfactory results. People who really care about their craft want to maximize the experience.

Try pairing.

This is an excellent programming technique with many benefits.

There are many great reasons to try pairing.

First of all, two heads are better than one. It’s a lot easier to get over problematic hurdles and mental challenges when two people attack a problem. When you work alone, you can only rely on your own skills and experiences. With pairing, this power is doubled.

Pairing also gives you a free code review in real time, which is much more efficient than having someone pick up your code later and review it. Code reviews are great, but the reviewer will not understand the code as deeply as someone who developed the code with you.

Your work will also go a lot faster when pairing. A lot less time will be spent in rework or going down ill-advised paths, as you will catch more errors earlier. Your pairing partner can also keep you focused on work, away from the distractions of cat videos and social media updates.

Pairing is a great way to learn new techniques. There’s nothing quite like learning a technique in real time, in action. It’s much more efficient than merely reading about it in a book. On the other side, this is also a great way to teach a method to someone else. Part of developing mastery is improving your ability to teach others, and pairing helps a lot with that.

So give it a try.

Accept criticism.

It’s not always easy to get feedback.

You should definitely take it when you can get it. Some people shy away from criticism, fearing it reveals their weaknesses and emphasizes their failures. That’s simply not the case; by giving you valuable feedback, your coworkers are trying to make you better.

The best and most immediate criticism a developer can get is during the code reviews. Your fellow programmers can help you follow best practices and adhere to the styles and conventions that lead to high-quality code. They should take their job as a reviewer very seriously because they will have to support this code in the future.

You can also receive valuable feedback from the testers. The QA team doesn’t have to report only bugs. They can also inform you about things that work but may not be optimal. User interfaces that aren’t clear. Response times that appear to be slow. Applications that are hard to test. Work with the QA team to get as much information as you can.

Another good source of feedback is from the product owners and managers. When you receive changes to the specifications after a demonstration of work in progress, it’s a sign that your team could have designed the application better. Finding faults during the design phase is crucial, as changes get more expensive in later stages.

You’re not perfect, but you can be better. Who doesn’t want to be better?

Control your library versions.

Unexpected side effects occur when multiple versions are in use.

When including libraries and external packages in your application, you need to be careful to specify a version. Package manager software makes it very easy and sometimes even encourages the use of the most recent version of a package. This is done with good intentions, thinking you will want the most current version to take advantage of the latest fixes.

The problem is that this can lead to having different versions used in your various environments. If the development environment uses one version, the testing environment using another, and the production environment using a third, you may experience unexpected behavior. This also leads to bugs that are very hard to track down, as they often cannot be reproduced in other environments.

Thus it is better to nail down the version. You should know exactly what version you deployed in your production environment. This also leads to extra work, as you will need to examine your libraries periodically to see if you should update them to a newer version. The difference is that these updates will be deliberate, voluntary choices made on your own schedule.

Developers and testers, unite.

These two parties should collaborate heavily in the development process.

In some organizations, developers and the QA department are separate entities that don’t collaborate very well. In some cases, the QA team is in a different building, or even in a foreign country. Developers do their best to write code, and then they “throw it over the wall” to the QA team for review. Bug reports stream back to the development as they find defects.

This suboptimal approach leads to an “us against them” attitude, which is counterproductive. A proper collaborative environment has these two teams working with each other, not against each other.

Testers can help developers anticipate unexpected use cases. Their experience of trying random things and looking at the application from different perspectives can be hugely beneficial.

Developers can help improve automated tests. Automation is often tricky for the QA team to develop into their tests, and if they gain the assistance of the development team, it can be beneficial. Also, if the QA team gets insight into upcoming features before they arrive as finished code, they will be better able to prepare their new test cases.

When the two groups work hand-in-hand as a team, the overall result is much more efficient.

Use polymorphism.

This is a technique that can replace your if/else and case statements.

You don’t need to replace all of your if statements with polymorphism, but you should definitely learn this technique. In many cases, a simple if statement is sufficient. But this is a convenient tool to have in the draw that can lead to code that better expresses intent.

Here’s how it works. Say you have a Shipment class that calculates a shipping fee in a method. In the method, you have an if statement, where if the shipment is over 80 pounds, it uses a freight calculation. Otherwise, it uses a standard USPS parcel post calculation. And then later, in the code, when determining what kind of label to print, it does this if/else thing again. Then, a third time, when deciding where to drop off the shipment, the if/else appears once more. Now you’re feeling like you’re repeating yourself.

Instead, you could have Shipment be an abstract class, and let it be extended by FreightShipment and PostalShipment classes. The abstract class could define abstract methods for calculating shipping fees, printing labels, and locating drop-off points. In the concrete implementation classes, you will the respective and proper implementations for each method.

Now, these methods are not concerned with determining what kind of shipment it is. It already knows that based on the class. This allows the class to focus on its particular implementation.

Also, if a third kind of shipment is added later, you don’t need to change the other two classes. That’s a huge win.

Keep it DRY.

As in, don’t repeat yourself.

That is, don’t have copies of the same business logic in the codebase. There is a horrible technique weak developers use known as “copypasta” code, where lines of code are copied from one section and pasted to another. This practice creates a lot of code quickly, but it also creates problems just as quickly.

When a particular piece of logic appears in more than one place, it invites bugs. In the future, another developer with less knowledge of the system will need to make a change that involves this logic. Not realizing it appears in multiple places, the developer makes a change in only one place. Now the code base has two different implementations for what should conceptually be the same bit of logic. As a result, the behavior of the system becomes random and unpredictable.

Keeping code DRY means ensuring that each bit of logic only appears once. This is best done by refactoring down to separate methods and classes. Thankfully, today, there are many tools to detect code duplication, making it easier to avoid this problem.

Pay it forward.

Someone else has to maintain your code in the future. Do them a favor.

When you’re supporting your team’s codebase, you become a little blind to some of the problems that exist. Because you have been a large part of the application’s history, you know all the system’s ins and outs. You know where to look to find any given piece of logic. Most importantly, you understand why the team made their decisions and what needs to change if new requirements come in.

Unfortunately, the person in the future who has to maintain the code doesn’t have any of these advantages. They get this crazy application dumped on them with no warning, and now they have to support it and add new features to it. For a complex codebase, this can be very difficult.

There are some things you can do today to help this future person out. Avoid writing spaghetti code. Keep things simple. Each method should have one purpose; break more complicated methods up.

Follow standard conventions as much as possible. Everything should have a standard place and programmed in a standard way. Follow coding standards and style guides. Use the most popular libraries and frameworks. Avoid tools built in-house when there are widely-used open-source alternatives available.

Document the reasons why functions exist. Write up why the team used one approach over other alternatives. These are the most valuable kinds of comments you can have in an application.

Don’t assume user behavior.

Users will always surprise you in how they employ your application.

It’s always surprising to see which features in your software will get the most use. Even more surprising is how users sometimes will work with your software in ways you did not expect. When you designed and wrote the application, you had certain use cases in mind. But once you release the system to the real world, a lot more randomness comes into play. People will do unexpected things.

Talk to your users to learn how your code is actually being used. Often about 20% of the features will get 80% of the use. Some features may never be used. If there are bugs or difficulties with the system, the users may find workarounds that you are not aware of. You need to learn about these so you can develop a more user-friendly solution.

Sometimes it is helpful to analyze the usage logs to gain statistics about the usage of various parts of the application. It is generally more useful, however, to talk to the users directly and get them to relate their experiences first hand.

On the trading floors of wall street financial firms, the traders often retain some of the developers in the same room as them, to keep the feedback loop as short as possible. They do this because millions of dollars in transactions are on the line. If learning from users is that important to them, it should be important to you as well.