Secure coding

Good Programming Techniques - S.O.L.I.D. and Three-layer Architecture

Adrian Stolarski
September 25, 2012 by
Adrian Stolarski

A lot of people wonder how to approach writing code. So I decided to write on this topic in a few articles. Here's the first one, I hope that it will be interesting for you.

We begin our adventure

Learn Secure Coding

Learn Secure Coding

Build your secure coding skills in C/C++, iOS, Java, .NET, Node.js, PHP and other languages.

Learn Secure Coding

Learn Secure Coding

Build your secure coding skills in C/C++, iOS, Java, .NET, Node.js, PHP and other languages.

Today I would like to introduce you to S.O.L.I.D. We will learn about the three-layer architecture. It is a set of principles and practices for creating good code. S.O.L.I.D helps us to create good software and write clearly and legibly for all the source code. S.O.L.I.D forces the programmer to use many of the practices that will be useful in his daily work, and that really support the process of software testing.

S.O.L.I.D is widely used in application development using TDD methodology, about which I wrote in the introduction of Agile /agile-methodology/ article. These are really very simple principles that help us much life. The following briefly note on all of these rules:

  • SRP - Single Responsibility Principle - one object or one class implements only one function
  • OCP - Open / Closed Principle - each class and method is open for extension but closed for modification
  • LSP - Liskov Substitution Principle - all the objects in the program are interchangeable with their subtypes without changes to the functionality and operation of the program
  • ISP - Interface Segregation Principle - the use of multiple interfaces is much better than the use of a single interface, one interface should be focused around one functionality
  • DIP - Dependency Inversion Principle - the idea is to avoid abstraction, and not to avoid specifics

"S" as the Single Responsibility Principal

This is the simplest of the S.O.L.I.D principles. Theoretically, most developers are already familiar with it. It is derived from the old Unix way of programming: "One way or one class gets one and only one thing and doing it well." The idea is to focus on a single class, the smallest part of any application logic, so one class can have only one reason to change. But it is not allowed to make a single class perform two independent pieces of logic. We'll come back to that more can the end of the article, but now deserve a tiny example. If a class performs operations on objects and displays the results, then it breaks the principle of SRP.

This is where a lot depends on the programmer. Every programmer should follow SRP, because there are no tools that guarantee 100% accuracy with the principle of the SRP. The pattern facade method does not meet the SRP, while the task is to focus as much functionality in one place. However, below is a screen showing the NDepend site that checks compliance with the SRP:

And yet at the end of such fractures SRP, written by me in Java. The example is very simple:

[plain]public class CrushSrp {

public void print () {

System.out.println ("The result of this:" + divide (5.4));

}

private int divide (int i, int j) {

return i / j;

}

}

"O" or Open / Closed Principle[/plain]


As already mentioned, this principle states that the software should be open to any extension of a completely closed for various types of modifications. This is done by you, that a satisfactory result we should be able to get longer by extending the class and its methods of overcharge, not by changing the code written once. This principle is excellent in the code where the options are very limited modifications. This allows us to write programs that consist of modules. No one denies that's basically already out of S.O.L.I.D, which I personally use very often, such as: "If something is not trivial, close to the package or method." OCP is a fracture example:

[plain]public class Shake {

int type;

}

public class extends Shake Milkshake {

public Milkshake () {

super ();

int type = 1;

}

}

public class extends WaterShake Shake {

public WaterShake () {

super ();

int type = 2;

}

}

public class CrushOCP {

public int getShake (int type) {

if (type == 1) {

return 1;

}

else if (type == 2) {

return 2;

}

else {

return 3;

}

}

}

"L" or Liskov Substitution Principle[/plain]


It is one of the most difficult rules to follow. Can you believe that in the real world, very few people know of LSP. In the case of LSP the idea is that if we have functions that use indicators or any references to base classes we must be able to use the facilities without the knowledge of the classes that inherit these types of objects. The idea is that the class inherits should only extend the capabilities of the base class, but under no circumstances should they change its functionality. Sometimes it is, so that, depending on whether the call the base class or the child class, we have different results of their actions. It is a violation of the principle of LSP, because the child class should never change the behavior of the base class. This principle is really very difficult to apply in practice.

"I" or Interface Segregation Principle

It consists of the fact that all the interfaces that we create are responsible for the minimum functionality. Definitely, we should not write them, these methods do not really need and will not need it. The easiest way is to consider the example of a man and robot. So get to work. Here's the code:

[plain]public interface I_Worker {

public void work ();

public void sleep ();

}

public class Human {implements I_Worker

@ Override

public void work () {

/ / TODO Auto-generated method stub

}

@ Override

public void sleep () {

/ / TODO Auto-generated method stub

}

}

public class Robot {implements I_Worker

@ Override

public void work () {

/ / TODO Auto-generated method stub

}

@ Override

public void sleep () {

/ / TODO Auto-generated method stub

}

}[/plain]


What is really happening here? Now we have an I_Worker interface with two methods, Work and Sleep. Then we have a class that implements our Human employee who can work, but needs to sleep. The robot does not need to sleep, or maybe just work. This is a violation of the principle of the ISP, because the implementation of these classes always requires the provision of both methods, even when one of them is not necessary. None of the developers may be forced to write empty methods just to meet each other held by the interface. This is the correct solution to this problem. Simply create two interfaces instead of one:

[plain]public interface I_Sleepable {

public void sleep ();

}

I_Workable {public interface

public void work ();

}

public class Robot {implements I_Workable

@ Override

public void work () {

/ / TODO Auto-generated method stub

}

}

public class implements Human I_Workable, I_Sleepable {

@ Override

public void work () {

/ / TODO Auto-generated method stub

}

@ Override

public void sleep () {

/ / TODO Auto-generated method stub

}

}[/plain]


"D" or Dependency Inversion Principle

This principle follows directly from the so-called layered application development. Code of the layers lying above may not be dependent on the code of the lower layers. But both layers are dependent on abstraction. In addition, abstracts should not depend on the specific implementation, the details must depend on abstraction. And so we came to the multi-application architecture. Ready? Here we go!

Multi-tier architecture

In most applications, the individual layers are separated. Mostly these are the view layer, logic and data, but sometimes it is also the domain layer. Chapter applications on these layers strongly accelerate application testing and the development of the code and work on the same code by the individuals. Thanks to this division it is much easier to then modify various architectural applications. Now let's discuss the different layers of our application.

The view layer is the application layer, which does not have to be smart. It is responsible only for what the user sees, and this is her main role in the application. It is also responsible for communication with the user. It was a display of all kinds of buttons and system messages.

The next layer is a layer of business logic applications. It is responsible for all the activities of our application logic. This is where there are usually all kinds of decision-making units and data parsers.

Another no less important layer is the data layer. The data layer holds all operations related to such things as reading the database and reading data from files.

Of course, what I wrote presents the ideal world with a slight bias. In fact, it usually introduces a fourth layer, called the runner. Runner theoretically belongs to the application logic layer but in practice it really serves as a link between all three layers. This is in my opinion the only logical option to break the layers in any application.

In addition, in the more advanced systems we apply other layers such as the rapidly growing seven-time system. If the system must be capable of supporting registered users, it introduces an additional layer of authentication and authorization of users. And if you must be able to handle calls, it introduces a layer multiplexing all calls. Until that occurs in many projects it is in the domain layer.

Advantages and disadvantages of a layered protocol

Let us now turn to the advantages and disadvantages of using multi-layer model. Like any protocol, it has not only the advantages but also disadvantages. So one by one.

The biggest advantage of this model in my opinion, is the decomposition of the whole system to a fully independent elements, it is possible to create a separate analysis. This is very important if you are writing unit tests for the method or class, because we can only invoke its methods. Another advantage of the multilayer system is certainly easy substitution of one component from one layer to another of the same layer. This allows you to modify only one class, and in special cases only one functionality.

Another very important advantage is the ability to model multi-layers to merge into one another in complete protocol to the next or previous layer. This also works the other way. It is possible to separate a single layer on a few and really nothing happens with software created by us. There is another advantage of the use of layers. Thanks to them, we can separate the systems designed only for certain dedicated specific tasks.

Of course, a multi-layer model has not only advantages, but also disadvantages. From my own experience, I can name three major shortcomings of this model. The first drawback is that the multi-layer model is very difficult to implement in systems that have not been designed taking into account the layered model. Another of the disadvantages and advantages may be required for each newly formed model enclosing an additional interface functionality. In total, it has more advantages than disadvantages. In addition, using this approach we always unwittingly implement a strategy design pattern, which is still one of the most implemented interfaces. Even mention, as we're on the interfaces that each implementation of this type introduces difficulties related to ensuring the development of backward compatibility interface.

Summary

This article is something between an introduction to good programming practices and the introduction of testing. For me all the time it is amazing, why so few people use S.O.L.I.D. when you create and write your own applications. But after a while we will have to go back to writing our own code, and all the mistakes we commit in writing are really vindictive. In addition, a well-written application, based on S.O.L.I.D. and multi-layered architecture is much easier then tested.

Learn Secure Coding

Learn Secure Coding

Build your secure coding skills in C/C++, iOS, Java, .NET, Node.js, PHP and other languages.

Learn Secure Coding

Learn Secure Coding

Build your secure coding skills in C/C++, iOS, Java, .NET, Node.js, PHP and other languages.

There are usually not any major problems, and why does the developer have to do unnecessary work as a software tester? Is it better for us to work in an environment based on cooperation and fight? But of course it is your choice which type of work you prefer.