This is your brain. This is your brain on computers.

5 Essential Things Every Programmer Should Know in 2022

Programming and software development in general can be expansive topics. As a result, it’s easy to get overwhelmed by endless advice, tips, and tricks in reference materials.

How do you keep sane in an industry that’s always changing? It seems like every day there’s something new you need to know. While it’s important to keep up, some tips are more practical than others.

That’s why we’ve created this focused guide with five essential things every programmer should know. Sure, there’s a lot more beyond this list, but you need to start somewhere.

Choose a Syntax Color Scheme That Benefits You

By default, many operating systems, consoles, text editors, and development environments come with a bland syntax highlighting setup. Light mode versus dark mode. Low contrast versus high contrast. Why not put some of your own style in the mix?

Maintaining a personalized workspace can bring out your hidden efficiency and creativity. Not only is customizing your workspace fun, but doing so establishes that it’s yours. By putting a personal touch on your tools, you’re effectively bringing them into your domain.

As a woodworker carves his initials into his chisels, so too will you leave your mark on your development software. Sure, there’s less permanence in such a brand, but the feeling is the same nonetheless.

In essence, you’re saying, “This is mine. I care about this. I care enough to individualize this.”

With that, you’ve placed a personal investment into something that you care about. It’s time to wield it to your benefit on a trajectory to greatness.

Less philosophically, some coloring schemes are just more pleasant on the eyes under certain lighting conditions.

Log Early and Log Often

If there’s one thing that developers regret after shipping a product, it’s that they didn’t log enough useful information. There are few diagnostic tools more useful than a properly implemented logging strategy.

From even the simplest and shortest of log files, you can obtain a wealth of information about how the system is being used or misused.

Consider the following: user-identifier frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326 user-identifier frank [10/Oct/2000:13:55:37 -0700] "GET /styles.css HTTP/1.0" 200 521 user-identifier frank [10/Oct/2000:13:55:38 -0700] "GET /scripts.js HTTP/1.0" 200 2421 user-identifier frank [10/Oct/2000:13:55:39 -0700] "GET /myface.jpg HTTP/1.0" 404 0

From this log, we can deduce that the user:

  • Tried to retrieve four files via HTTP (presumably via a website)
  • Three files succeeded, and one file failed with a 404 not found error
  • A total of ~5.5kb was transferred
  • The user is authenticated as “frank”
  • All of this occurred in the middle of the day (UTC-7 time zone) on Oct 10, 2000

And that’s just one log. Now imagine cross-referencing this data against other logs in your applications and systems. You can essentially follow along with and replay activities that users are performing.

This allows developers and customer help agents alike with more support options. Users calling in asking about errors they’re receiving? No problem you’ve got logs!

Don’t be surprised if you’re continuously tweaking log levels and contents. They’re just one of those things that are never perfect and require incremental improvements as your applications, products, and systems mature.

In previous applications, we’ve used logging frameworks and SDKs like NLog, Log4j, elmah, ELK, NewRelic, and just plain old Microsoft Logging.

Branch, Commit, and Merge Often

In a team based environment, the importance of good source control practices can’t be stressed enough.

Atlassian describes the importance of version control succinctly:

Developing software without using version control is risky, like not having backups. Version control can also enable developers to move faster and it allows software teams to preserve efficiency and agility as the team scales to include more developers.

What is Version Control — Atlassian

Version control doesn’t apply exclusively to source code. In fact, tools like Git track changes to any files on disk like text, documents, images, and videos.

However, change tracking to files that aren’t plain text become more difficult to maintain and review because humans can’t easily decipher the text representation of an image or video file. Additionally, every time a tracked image changes, the previous and new version are kept in history forever. This can quickly increase the size of your repository on disk. Fortunately, tools like git-lfs can mitigate these issues.

Create Branches to Mitigate Conflict

Imagine a scenario in which you are part of a three person team working on the same file. You make some changes and commit. One of your teammates pulls down your changes and quickly realizes that your changes broke a few things. Now that developer is blocked until you or he can resolve whatever bug you introduced.

None of this would be an issue if you created a branch and committed your changes to the branch while code review and testing was ongoing. Branching and waiting to merge after review is an essential element of good agile and DevOps culture. By isolating your changes to a branch and exposing that branch to other developers, you’re encouraging segregated collaboration and reducing the amount of churn caused by team conflicts.

Did You Know?
GitHub offers a variety plans (even free!) that help you and your organization rally around standards, visualize your branches, and maintain a clean repository?

It’s important to choose and align your organization around a specific branching strategy such as release branching, feature branching, user story branching, or trunk-based development. In the end, it’s whatever works best for your team and product.

Commit Your Changes Often

In addition to branching, the cadence at which you merge and commit to your branch is critical.

First, committing changes to your local branches as often as possible encourages you to track granular changes. Frequent commits allow you and others to follow along with the story of how you came to a solution. Additionally, it allows you to unwind changes in a more piecemeal fashion instead of undoing a day’s worth of efforts. In summary, don’t wait until the end of each day to commit whatever you’ve been working on.

Second, merging from some sort of master branch into your local branch on a regular basis will ensure that you don’t get too far behind changes that others have committed, tested, and released. Merging regularly into your local branch reduces conflicts that arise if you do end up getting out of date.

Finally, merging from your local branch into a master, release, or development branch regularly ensures that you don’t have branches hanging out there for too long. Long-lived branches are the antithesis of agile development. By holding on to changes that haven’t been reconciled against other changes, you run the risk of requiring much more complicated review, testing, and sign-off processes.

Further Reading
Be sure to check out our huge guide to becoming a software developer and see where good source control practices fit into your journey.

Clever Code is Not Maintainable

Short-sighted people write clever code. And while it might seem clever to write clever code, it’s not.

Imagine you’re reviewing changes from your coworker. You come across a strange function that makes nearly zero sense. You just can’t understand what it’s doing. Sure, it’s briefly written and gets the job done, but can’t be understood by anyone but the author.

How are teams supposed to work on source code that only a single person can understand? Answer: they can’t!

What is Clever Code?

So what is clever code, you ask? Consider the following method in which someone felt the need to be overly complicated.

public static int GetNextSize(int i)
  return i > 0 ? i << 2 : ~(i << 2) + 1;

Now compare this to it’s simplified version.

public static int GetNextSize(int i)
  return Math.AbsoluteValue(i * 4);

Even if you have no idea how to interpret and understand the code blocks above, you can at least tell the difference. The first contains complicated operators that require careful deciphering while the second uses a human-readable function to calculate the absolute value.

This is of course a contrived example, but it drives the point home. Programmers don’t get extra credit for being clever. “Fun to write” doesn’t always end as “fun to read.”

Don’t Start Yelling at Us Yet

We admit that there is a time and a place for heavily optimized and difficult to understand code (simulations, physics modeling, graphics and audio algorithms). Unfortunately, a lot of the industry attempts to emulate this behavior for the sake of spicing things up.

It’s understandable. Programmers are thinking and problem solving all day. Sometimes we get stuck in a rut and want to work out a clever solution. On teams, however, we don’t live in a vacuum. Try to think about that poor soul cursed with reading (and fixing) what you’ve written.

Don’t Prematurely Optimize for Performance

Next up on the evils of programming, premature optimization. You know, that time you spent shaving milliseconds off methods that perform some calculations. Or that day you wasted trying to prevent an extra megabyte of memory from being consumed when querying a database.

Before we get too into this topic, let’s get something out of the way first. We aren’t advocating for no optimization whatsoever. While writing your code, it’s important to keep basic optimization in mind.

Yes, optimization is an important part of software development. And yes, there are times when optimization is critical to the success of a product. Applying blanket statements both ways isn’t going to be totally accurate.

Optimization versus Premature Optimization

It’s important to make a distinction between regular optimization and premature optimization. The former being an evidence-based approach to making your application function more efficiently where the latter is a potential waste of time based on guesses and inaccurate foresight.

Consider the following function in which we search a collection for a specific number.

public bool DoesNumberExist(int numberToFind, IEnumerable<int> numbers)
  foreach(var number in numbers)
    if(number == numberToFind)
      return true;

  return false;

You might first notice that it’s a very basic linear search with no optimizations or special search algorithms. The worst case scenario is that we have to search every element of the collection and never find it. The best case scenario is that we get lucky and find it on the first element.

Given enough time and research, we can improve this by implementing a smart search algorithm. But, should we?

The answer is “maybe” if you’re including this method in a library that could be used for various cases. Users of your library won’t be too pleased if they’re stuck with a hastily implemented search algorithm.

But imagine you’re building an application with a use case in which that collection contains a maximum of one hundred numbers. Finding a number within a collection that small makes nearly zero difference between a “dumb” algorithm and a “smart” one. The runtimes will be nearly the same.

That’s when it’s important to draw a line somewhere in order to declare that it’s “good enough” for whatever the use case is.

Further Reading
In the event that you do need to improve your code’s performance, make sure to read our guide to free tools to make your job that much easier.
Justin Skiles

Justin Skiles

Justin has been developing enterprise application software for over 10 years primarily using Microsoft stacks, Azure, and various open source tools. He has most recently been trying his best as a Manager and Director of Software Engineering in the health care industry.

Share the Knowledge

Share on facebook
Share on twitter
Share on linkedin
Share on pinterest
Share on facebook
Share on twitter
Share on linkedin
Share on pinterest

Follow our updates



Keep Exploring. Choose Your Path.