fbpx
Mobile App Development Web Development

Software Engineering: Good Principles for Developing Software

Whenever we talk about principles or ethics in any field, it helps us to make a judgment precisely manner, to overcome the difficulties, and to stop being exhausted. In the same manner, software engineering also has its own principles for developing a better product and stops being less productive.  

The software engineering process is one that is complicated, but with discipline, education, and guidance it can become predictable. You will likely have the same steps with each product, though the time you spend on each level will vary depending on your goals and team. A software engineering process is a model chosen for managing the creation of software from initial customer inception to the release of the finished product.

The steps of the software engineering process include:

  1. Analysis
  2. Design
  3. Coding
  4. Testing
  5. Maintenance

DRY (Don’t Repeat Yourself)

This principle originates from the book “The Pragmatic Programmer” by Andy Hunt and Dave Thomas, who defined it as:

Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.

This means that every piece of data should have a single reference point or single source of truth (SSOT), such that changing a single part of that data doesn’t require changing logically unrelated elements. That’s because all occurrences of that data refer back to a single location. This is in contrast to code that requires changing every instance of say a variable whenever you change a single instance of it in your source code. Code that doesn’t abide by the DRY principle is said to be WET, which stands for “write everything twice”, “we enjoy typing”, “write every time”, or “waste everyone’s time”! Applying DRY to code reduces redundancy and makes it easier to manage later on.

KISS (Keep It Simple Stupid)

According to The Routledge Dictionary of Modern American Slang and Unconventional English, this principle was devised by the U.S. NAVY in 1960. They observed that most systems work best when kept simple and plain, as opposed to complicated and complex. Experience has shown that complexity causes bugs because there are more (unnecessary) parts to keep track of and fewer engineers can understand how they connect. KISS makes your code cleaner and less likely to have bugs. Such code is also easier to debug and maintain.

YAGNI (You Aren’t Gonna Need It)

YAGNI comes from the software development methodology called Extreme Programming (XP). Who better to define it than XP co-founder, Ron Jeffries, who said:

Always implement things when you actually need them, never when you just foresee that you need them.

It’s not uncommon for developers to add features to their applications in anticipation of a potential need. The ability to delete a comment might be tempting for some, but it’s becoming quite standard now to leave out the ability to delete it altogether.

Platforms like Youtube and LinkedIn, for example, don’t allow you to delete your comments. Avoiding features that are unnecessary is a good practice in software engineering. However, there are cases where anticipating a future use or need for a feature might be useful.

SOLID

It consists of design principles that first appeared in Robert C. Martin’s 2000 paper entitled Design Principles and Design Patterns. They are:

  • Single-Responsibility Principle: Every class, method, or module should have a single responsibility, such that only one part of an application should be able to affect the class if that part is changed. It makes sense in real life. Your bedroom is not meant for showering, nor is your shower meant for sleeping. Classes and methods can be thought of as rooms with separate purposes and responsibilities. This makes your code more organized and easier to follow.
  • Open-Closed Principle: This means open for extension and closed for modification.

    Open for an extension means that existing code should be developed with the ability to build on top of it, without having to start from scratch. We shouldn’t need to change existing code in order to add functionality or features to it.

    Closed for modification means that once existing code is working we should try not to make unneeded changes to it. The reason for that is that it can open a can of worms by forcing us to also change all the code that is related to it, unbeknown to us. To avoid giving ourselves more work than needed, existing code should be left alone, ideally. Please keep in mind that there are often very valid reasons for refactoring code that may be clumsy or difficult to follow. When refactoring can provide clarity or improve performance, exceptions to this principle ought to be made.
  • Liskov substitution Principle: This means that your subclasses should behave the same as the class they inherit from. In other words, you should be able to substitute the child for the parent class and expect the same basic behavior. For instance, say you have a vehicle class with the property of wheels and method drive.
  • Interface Segregation Principle: This is best defined by Martin himself

Many client-specific interfaces are better than one general-purpose interface.

It’s more practical to have separate interfaces that handle separate tasks than one that handles many. For example, in an application, it’s better to have separate tabs that deal with separate matters, like ‘Settings’, than to have one that deals with unrelated issues.

Dependency Inversion Principle: High-level modules should not depend on low-level modules. The interaction between the two modules should be thought of as an abstract interaction between them, not a concrete one.

Separation of Concerns

This refers to the fact of assigning a separate responsibility to each function, class, or component. It’s often very tempting to have a single function handle more than one task, however, it is best to divide the labor among specialized functions, or components. Say you’re developing a weather app, instead of having a single function that generates the weather forecast for a given day, it would be wiser to have a function that calculates the temperature, one that returns the humidity, and yet another that determines the date. This makes for cleaner code that is easier to read and troubleshoot.

I want to note that although it may seem identical to the ‘single responsibility principle’, it’s not. Single responsibility says that every class or function should have its own responsibility. Separation of concerns says that you should break that single responsibility into smaller parts that have each their own responsibility. In our weather app example, you can have one function take the single responsibility of generating the weather. Ideally, you’d want to have a separate function for the date/time, one for the humidity, etc. That’s the separation of concerns. Therefore, it can be thought of as a subset of the single responsibility principle.

Code Reusability

One of the benefits of the separation of concerns is that it allows for code reusability. Because each method was written to handle a separate task, it can now be reused in the future for similar objectives. So, in our weather app, our date-calculating function can be reused in a different part of our code that may also require the date.

Law of Demeter

The basic idea of this principle is to divide the areas of responsibility between classes and encapsulate the logic within a class, method or structure. Several recommendations can be distinguished from this principle:

  1. The classes or entities should be independent
  2. You should try to reduce the number of connections between different classes.
  3. The associated classes must be in one module/package/directory (also known as cohesion.

Following those principles, the application becomes more flexible, understandable and easy to maintain.

These are just a few of the principles of software engineering that are highly recommended for developers to keep in mind when developing applications. They allow for code that is easier to read, debug, and maintain over long periods of time.

Fellow developers let’s be engineers! Let’s think about design and build robust and well-implemented systems, rather than growing organic monsters. Listed principles are highly correlated and connected in their essence. Of course, I didn’t create them, but a small reminder does not hurt, at least my memory is definitely not perfect.

Related Posts: