Get up to 80 % extra points for free! More info:

Basic Best Practices for Software Design

In today's software design lesson, we're gonna focus on best practices. These are generally well-known practices that have proven themselves right over the years, and if we know them, they will save us a lot of problems. You all have definitely ever seen poorly written software resembling a house of cards. In such an application, it's hard and dangerous to make any changes as it can cause further errors and jeopardize the future of the project. In order to avoid such design mistakes, we don't need to reinvent the wheel, but just learn from the known mistakes of others and avoid them. There are quite a lot of best practices for software design, we'll present the most basic ones today.

KISS

KISS rule in software development - Best Software Design Practices

Let's start it easy and move on to more complex definitions step by step. The KISS rule is an acronym for "Keep It Simple, stupid!". KISS suggests that there is often a solution that is simple, relatively easy to implement and produces a satisfying result. In particular, customers who don't understand the internal structure of the application tend to require whatever they think of and over-complicate it. It's a good habit to discuss the necessity or the details of at least some of the requirements. You often find out that the customer actually needs something else that you can solve more elegantly.

Example

Let's take private messages here on ICT.social as an example. When we were programming them, Facebook had a JavaScript mechanism for its private messages. New messages popped up above the new message form which was located below the conversation. We asked ourselves whether we really needed to program it this way, and we soon came up with the idea to reverse the message order. The new message form was located at the top, and we used an existing AJAX script to load new messages downwards. We suddenly got the same functionality for negligible development time just because the direction of the messages has changed. These are the situations where it pays off to talk with the customer, in case you don't program the software for yourself, or reconsider the assignment.

Facebook private messages solution - Best Software Design Practices

The private messages solution from Facebook

ITnetwork private messages solution - Best Software Design Practices

The private messages solution from ICT.social

From my own experience, I can confirm that software is getting more and more complex, and eventually you'll find out that you need more and more features in your application. Keeping it simple will give you a competitive edge over companies that fiddle their software exactly according to the idea of ​​someone who doesn't understand IT, and then they are unable to read their won code.

SRP

The Single Responsibility Principle, abbreviated to SRP, says that every piece of code, e.g. a class, should be responsible for one particular thing. When our application consists of components and each component focuses on one feature and does it well, we have a fairly high chance of success.

The SRP is closely related to the assignment of responsibility. We've focused on it in the GRASP design pattern group.

Example

Practicing SRP is, for example, creating managers for various entities in the application, separating our code into the CustomerManager, InvoiceManager, StockManager classes and so on. Each class is responsible for its entities. We don't have just one Manager.

We can use SRP on methods too, even though this isn't the core principle of this practice. Each method should do one thing and we should be able to describe what it does without using the "and" conjunction. If our answer would be something like "this method loads, filters, and displays results," the method should be broken into multiple methods.

SoC

Separation Of Concerns, is a principle similar to SRP. Here, however, we usually focus at a higher level. While SRP separates, for example, working with invoices from working with customers, SOC typically separates the application logic from the presentation. This means that logical operations should be concentrated in a different part of the application than, for example, printing data to the user. You surely know that we are talking about dividing the application into layers. You can read more about it in the Software Architecture and Dependency Injection course. Well-known architectures such as MVC, MVP, MVVM, and so on, are all SOC implementations.

DRY

Don't Repeat Yourself, is one of the most important programming principles. Beginners, in particular, tend to copy code from one part of the program to another. Once you have 2 identical blocks of code anywhere in your application, or even 2 similar pieces of code, it's automatically wrong.

Example

This mistake is so common that we'll use a part of a game that was sent to us by our member. Specifically, it's a code switching images (sprites) according to the direction and size of the character:

// right direction
if (direction == 0) {
    if (picture == 1)
        div.className += "spriteLiveRightL";
    if (picture == 2)
        div.className += "spriteLiveRightM";
    if (picture == 3)
        div.className += "spriteLiveRightS";

    div.style.left = -200 + "px";
}

// left direction
if (direction == 1) {
    if (picture == 1)
        div.className += "spriteLiveLeftL";
    if (picture == 2)
        div.className += "spriteLiveLeftM";
    if (picture == 3)
        div.className += "spriteLiveLeftS";

    div.style.left = screenWidth + 100 + "px";
}

At first glance, we can see that there are minimal differences in these 2 blocks of code. The code can be at least shortened to:

if (direction == 0) {
    let directionName = "Right";
    div.style.left = -200 + "px";
}
else {
    let directionName = "Left";
    div.style.left = screenWidth + 100 + "px";
}

if (picture == 1)
    div.className += "spriteLive" + directionName + "L";
if (picture == 2)
    div.className += "spriteLive" + directionName + "M";
if (picture == 3)
    div.className += "spriteLive" + directionName + "S";

The code above works the same way, but it has much less duplication. Imagine that we changed the image names from "...Right..." and "...Left ..." to "R" and "L". Look how much code would have to be overwritten in the example violating DRY and how much in the corrected example. However, the code is still not ideal.

DRY isn't just about duplicate code but about repeating in general. Brainless long branching can be almost always replaced by smarter constructs, usually loops or arrays. Let's make another change:

if (direction == 0) {
    let directionName = "Right";
    div.style.left = -200 + "px";
}
else {
    let directionName = "Left";
    div.style.left = screenWidth + 100 + "px";
}

let pictures = [1: "L", 2: "M", 3: "S"];
div.className += "spriteLive" + directionName + pictures[picture];

In our case, we stored the character size names "L", "M" and "S" in a dictionary under the number by which the size (image) is determined. Then there's nothing easier than getting the size letter according to the dictionary key.

Now we'll apply the KISS rule to the code as well. We can simply name the images using numbers so that the direction and size in their names correspond to the representation of these values ​​in the code. Why make it complicated? Images aren't intended for users anyway. The result:

div.style.left = direction ? (screenWidth + 100 + "px") : (-200 + "px");
div.className += "spriteLive" + direction + "_" + picture;

We've managed to write a code accomplishing the same thing on 2 lines instead of the original 18(!). All of this just by using KISS and DRY. Imagine what happens when you apply the best practices to the entire application. Suddenly, you don't have to write dozens of thousands of code lines and you are about to crush your competition in a few months. Don't underestimate good practices for sure :)

An example of DRY could be carousels on ICT.social, which can be configured in different ways:

Carousel on ICT.social - Best Software Design Practices

Carousel with photos

Carousel on ICT.social with different settings - Best Software Design Practices

Carousel with HTML contents

This certainly isn't anything big yet. Internally, however, these carousels inherit from a component that switches tabs:

Tabcontrol as the parent of the carousel - Best Software Design Practices

A tabcontrol with algorithm source codes for different languages​​

Many programmers would implement the carousel and bookmarks separately, but when you think about it, they do basically the same thing, yet they look different. You can create one component only by a small variation of the other.

Other DRY examples would be e.g. creating quality general CSS styles that aren't limited to specific elements on the page and can be parameterized, as is the case with the Bootstrap CSS framework:

<table class = "table table-striped">

The code above sets a basic style and striping to a table.

Shy

Maybe you know the sentence:

Keep it DRY, shy, and tell the other guy.

We've already explain DRY and repetition, but how about shy code? The shy code behaves just like shy people. It communicates with another code only when it's necessary and doesn't have more information about others than it necessarily needs. SHY is actually another denomination for the Law of Demeter, see below.

LoD

The Law of Demeter, the Greek Goddess of the Harvest, is basically about the low/loose coupling, i.e. maintaining the smallest possible number of references between components. It's defined by three rules where it introduces the term unit for an encapsulated part of code, a class:

  • Each unit should have limited knowledge about other units, which are only the units closely related to the current unit.
  • Each unit should only "talk" to its "friends"; don't talk to strangers.
  • Only talk to your direct friends.

We can see from the rules that each object should be universal and absolutely shielded from the rest of the application. To know minimum information about the whole and share minimum information about itself to the whole.

Example

You can certainly imagine a practical example. These are classes with well-encapsulated internal logic, providing general functionality so they don't need to know the details of a particular system and can be reused anywhere. E.g. you'll create an order generator so that it can be 100% customized and won't depend on the needs of one information system. You may be wondering if it isn't a waste of development time and money to create features that you don't need in your current project. That would be a waste for sure, so you can just count with these features and design the components so that the features could be easily added into the code in the future.

LoD is also about passing of dependencies, there should be as few as possible of them, and a class should depend on abstractions, not concrete classes. This is what the Dependency Inversion Principle from the SOLID principles refers to.

IoC

You should know the Inversion of Control principle well. It's a group of design patterns, including popular Dependency Injection, which is the only good way to pass dependencies in object-oriented applications. IoC says that objects in the application should be controlled by a higher mechanism that creates class instances and passes the necessary dependencies to them. This is the opposite approach to the older way of working with dependencies, when classes pulled their dependencies from the system by themselves, e.g. via Singletons or other antipatterns. As this is an extremely important issue, we prepared a separate DI course of Software Architecture and Dependency Injection for you where it's explained in detail on real examples.

SOLID and STUPID, acronyms for other practices, also belong among the popular good practices and therefore, a separate article is devoted to them.

Do you have any practices you like to use? Do you have an interesting experience with best practices? Share it with others in the comments below the article :)


 

All articles in this section
Best Software Design Practices
Article has been written for you by David Capka Hartinger
Avatar
User rating:
No one has rated this quite yet, be the first one!
The author is a programmer, who likes web technologies and being the lead/chief article writer at ICT.social. He shares his knowledge with the community and is always looking to improve. He believes that anyone can do what they set their mind to.
Unicorn university David learned IT at the Unicorn University - a prestigious college providing education on IT and economics.
Activities