 Okay, now we have overall discussed what sort of the issues or the goals are in design and implementation. Now we go into some of the guidelines that can help you to, in the end, implement better systems. And these are all based on object-oriented systems, so they might be slightly different, but since most systems nowadays at least support the object-oriented system, we will go into that detail. And one of the guidelines that you can follow that helps you deciding how to design and how to write your system are the so-called solid principles. So these are five principles for object-oriented design that help you deciding what should go into one class, what should go into another, how should the interfaces look like. And they are, the S stands for single responsibility. So essentially your system should be doing one thing. It should not be, or your class should do one thing, it should not be a collection of lots of different functionality packed into a single class that somehow does everything, the so-called God class. It should really be having a single responsibility. And the main reason for that is if you have a change in your software, it usually affects fewer classes because they all have their responsibility. It might be easier to understand what's going on because there's not everything in there. And because you have multiple classes with different responsibilities, there are the interfaces in between which might help the overall understanding of how the information flows in your system. So that's the single responsibility principle. The second principle is open closeness. And that says that a class should be open to extension. So you should be able to extend to build on top of the class, use it for building new functionality, for example by doing a subclass of it, but it should be close to modification. So you should not be able to change the internals or everything that's really internal should be kept. For example, in many languages private, so you cannot access it. So open to extension, close to modification. The third one is called LISC of substitution. And that says that if you have a class that depends on another class, so for example you depend on class A, then the implementation should work with all subtypes. So if you have another class B or another class C that inherit from class A, this should not affect the functionality of our original class. So if we have our original class here that somehow has a dependency, so for example it needs one of A, it should just as well work with any kind of subtype. It should not be dependent on the abstract class. It should not be dependent on the internals of the abstract class. So basically replace it, just assume that it's any kind of A with any subtype, it should still work. This is LISC of substitution. It's related to the dependency version, we'll get there. Five, four is the so-called interface segregation. And that is if you have a class that implements an interface, my original class here might have some kind of interface, a number of methods that it implements, then you should try to avoid having one huge interface for everything, but if you have specialized cases, for example different kinds of users, then you should have rather multiple interfaces instead of a single one. So basically every interface should kind of be a specialized thing, it should make sense. It's not similar to the single responsibility, it should not just be one interface for everything. For example, assume you have a class that offers access to some kind of data, you might have different interfaces depending on the persona or the user extending it. Is it some kind of administration functionality the person is supposed to be able to add and delete things or is it more the user access just reading, for example? So that's an example what you might want to do, that depends a lot on your class, but not everything in one interface segregates them depending on their specialization, what they really do. Number five, the last one is called dependency inversion. And this principle says that you should try to, if you have a dependency, your class depends on something else, it should try to depend on something that is rather abstract. So, for example, imagine our original class is used for processing data and as a part of this it has to sort data. There is some kind of sort algorithm and if you have or if you are taking algorithms, classes, you know that there are lots of different ones. For example, we might have quicksort and we might have insertion sort, so different kinds of doing this and the dependency inversion principle says that you should try to just depend on the abstract thing, just some kind of sorting algorithm and then whoever implements the system decides, whoever uses this decides exactly which algorithm to use instead of doing something like this and just depend on a very specific thing, so you should not be doing this. So, usually how this looks like if you program it is, for example, that you have a method, so we have a method for example processes something and in there in the code there is some kind of sorting going on and instead of implementing hard coding a certain algorithm, what you just do is that you as a parameter here add the algorithm and then you call it down here. So, you don't provide a specific algorithm but you give the, whoever uses it, you give the possibility to insert any kind of specific solution and this makes, for example, testing easier. That's one reason it makes extension or reuse much easier and of course if you take, for example, sorting algorithms, sorting algorithms are often, well, many other algorithms as well, they are specific to the use case. So, some algorithm might perform better in one situation than another so whoever calls this function might know much more about what exactly is being processed and can choose the right algorithm. You should maybe not be the person that decides that. So, that's the dependency inversion rule or principle. So, overall, these solid principles give you some kind of guidance on how you can design a system on a micro level and these principles are commonly used or encapsulated in what is known as design patterns or what is discussed next. So, similar to the architectural styles or the architectural patterns, design patterns are some kind of good practice, proven solutions for designing classes in their relationships. In our case, we just look at the object-oriented case and similar to architectural patterns, you have seen a lot of these but in the following we go into different ones, explain them in detail and also explain how they relate to these five principles because these principles are really very often encapsulated in the different patterns.