Skip to content

Programming Principles

Don’t repeat yourself

Also known as the DRY principle, “Don’t Repeat Yourself” strives to reduce code duplication. The idea here is that if you have code that’s doing the same thing twice, it should be made into a method. By abstracting code into method, you can reuse that code and make development more efficient. In addition, avoiding code duplication makes debugging easier, as you won’t have to fix a bug in every instance of repeated code throughout your program.

Single-Responsibility principle

The single-responsibility principle (SRP) states that each class, module, or function in your program should only do one job. In other words, each should have full responsibility for a single functionality of the program. The class should contain only variables and methods relevant to its functionality. Learn more about SRP

Open-Closed Principle

This statement, at first, seems like a contradiction since it asks you to program entities (class/function/module) to be both open and closed. The open-closed principle (OCP) calls for entities that can be widely adapted but also remain unchanged. This leads us to create duplicate entities with specialized behavior through polymorphism.

Through polymorphism, we can extend our parent entity to suit the needs of the child entity while leaving the parent intact. Learn more about OCP

Watch an example: S.O.L.I.D. Lesson #2 Open-Closed Principle | Software Architecture | Android/Java

Liskov substitution principle

“Objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program.”

The Liskov substitution principle (LSP) is a specific definition of a subtyping relation created by Barbara Liskov and Jeannette Wing. The principle says that any class must be directly replaceable by any of its subclasses without error.

In other words, each subclass must maintain all behavior from the base class along with any new behaviors unique to the subclass. The child class must be able to process all the same requests and complete all the same tasks as its parent class.

In practice, programmers tend to develop classes based on behavior and grow behavioral capabilities as the class becomes more specific. The advantage of LSP is that it speeds up the development of new subclasses as all subclasses of the same type share a consistent use.

Watch an example: S.O.L.I.D. Lesson #3 Liskov Substitution Principle | Software Architecture | Android/Java

Portability

Portability is a key aspect that ensures functionality of your program. If your code contains literal (hard-coded) values of environmental parameters, such as usernames, host names, IP addresses or URLs, it will not run on a host having a different configuration than yours.

In order to tackle this, you would have to ‘parametrize’ variables and configure them before running your software in different environments. This can be controlled with property files, databases, or application servers.

In addition, resources like XML files must also have variables instead of literal values. Otherwise you’ll have to change the references while coding every time you want to port your application to another environment.

Add Input Validation to Your Code

If your code allows user input, do you really want to allow users to enter any type of input without restrictions? Writing a code without including any form of input validation is like leaving the door open to attackers, and it provides a better user experience.

Avoid Hard-Coded Numerical Values (Magic Numbers) Check the code below. It’s a bit of a small truck dispatch program. Can you figure out what the 150 number means?

while(boxCount > 150) {
    // do something important
}

The number of boxes delivered? Nope. The number of boxes ready for shipment? No. What if I write it like this instead?

int containerCapacity = 150;
while(boxCount > containerCapacity) {
    // do something important
}

Now, can you guess what the 150 number refers to? In this case, it refers to the number of boxes that each truck can contain. That was much more straightforward, right?

Now, take the same examples and imagine that you have to have to change the number 150 to 250. In the second example, you’ll just have to update the value in one place, while in the first example, you’ll have to go through the whole code and update the magic number one by one.

Keep the Code Simple

The code that a programmer writes should be simple. Complicated logic for achieving a simple thing should be kept to a minimum since the code might be modified by another programmer in the future. The logic one programmer implemented may not make perfect sense to another. So, always keep the code as simple as possible.

Avoid Deep Nesting

Too many levels of nesting can make code harder to read and follow.

Remove Dead Code

Delete code that isn't being used. That's why we have source control systems!

Avoid Long Methods

All other things being equal, a shorter method is easier to read, easier to understand, and easier to troubleshoot. Refactor long methods into smaller methods if you can.

Avoid Large Classes

Large classes, like long methods, are difficult to read, understand, and troubleshoot. Does the class contain too many responsibilities? Can the large class be restructured or broken into smaller classes?

Committing to git

Commit early and Often

Smaller and more frequent changes enable others to integrate your changes more efficiently than large changes. Smaller changes make it easier to write clear commit messages. Larger changes introduce a greater chance of missing details in the writing or the reading of the commit message. More frequent commits provide you more waypoints to revert to if you break something. This reduces the amount of work and code you lose with each error.

Write Descriptive and Meaningful Commit Messages

Commits are communication tools. So, take your time to write a descriptive and meaningful commit message. Your future self and your team workers will thank you a lot.

Through the command git log, you can navigate through codebase’s history. They should tell you a story. Committing vague and abstract messages like “Bugfix”, or “Refactoring auth” may be a problem sooner than you think.

Learn more about writing great commit messages

We should apply the Single Responsibility Principle here too, not only to the code. You should commit the least amount of lines that make sense together. Each commit should be "atomic", meaning it only includes the changes related to the bug fix or the new feature, with a clear and focused description. Atomic commits help maintain a clean and comprehensible version history, enabling efficient tracking, debugging, and collaboration within a Git repository.

Create a Meaningful Git Ignore File

A .gitignore file is a must in each repository to ignore predefined files and directories. It will help you to prevent secret keys, dependencies and many other possible discrepancies in your code. You can choose a relevant template from Gitignore.io to get started quickly.

Resources

https://www.educative.io/blog/coding-best-practices https://codesigningstore.com/ultimate-programming-best-practices-guide https://code.tutsplus.com/tutorials/top-15-best-practices-for-writing-super-readable-code--net-8118 https://sourcelevel.io/blog/7-git-best-practices-to-start-using-in-your-next-commit https://www.perforce.com/blog/vcs/git-best-practices-git-commit https://www.freecodecamp.org/news/git-best-practices-commits-and-code-reviews/