To deal with complexity, the first thing that we have to do is to choose the appropriate design goals at the very beginning of the project. Let's say if you want to build an online transaction handling system, then you have to make sure that your system has to be efficient and also reliable. Notice that it's often impossible to achieve all of them simultaneously, all of them at the same time because of the time and budget that you have for the project. Notice that some of the design goals, they may be conflicting with one another. So that's why it's not possible for you to achieve all the design goals at the same time. To choose the appropriate design goals, you need to clearly understand the client's design goals at the very beginning of the project. If the client tells you that I want a system to be efficient and to be reliable, then those have to be the design goals that you choose for the project. Then you need to prioritize the design goals for a different project and then base the development around these design goals. Again, you have to choose two or three or four most appropriate design goals at the beginning of the project. Having clear design goals is going to reduce the complexity of designing the system because you know exactly what you need for your software system. Eventually when you design a system, it's going to be much easier. To deal with complexity, another thing that we can do is to apply modularity and also incremental development, because there is a limit to human understanding. When we are building a large software system, then we can apply an approach which is called divide and conquer to divide the large software system into many smaller pieces. Instead of handling the large software system all at once, we're going to build the smaller pieces, smaller modules one at a time. The definition of a module is a part of the system that makes sense to consider separately. Notice that these modules are going to interact with each other because one module may be using some of the functionalities or some of the operations from the other modules. So that's why they interact with each other. Another approach to deal with complexities is to use information hiding. When we try to assess a particular module, we are only allowed to assess the module or interact with the module via interfaces. By using an interface, we achieve both abstraction and encapsulation at the same time. What are the definition of abstraction and encapsulation? Abstraction means we skip details. When we try to use a module, we don't have to actually understand what's inside a module, that means the source code and the implementation within the molecule. We only have to understand how to use the interface, that's it. Encapsulation means if you want to maintain a particular module or when we want to modify a particular module, then it's going to be just within this module. We don't have to touch the other modules. That's what we mean by abstraction and encapsulation. The good thing with abstraction is that a module can be used by only understanding the interface, but not the actual implementation within the module. This is going to reduce the complexity of understanding the system because you only have to understand how to use the interface instead of understanding the content. That means the source code and the implementation within the module. An interface also provides encapsulation. If you want to change a module, you have to only change that particular module without affecting the rest of the system. This is going to reduce the complexity of maintaining the system, because when you maintain the system, when you want to change something, you only have to touch one thing, but not the other things. Now by applying modularity and also incremental development, that means you chunk the large software system into smaller pieces and then you handle one small piece at a time, and then also using interfaces for the modules for the smaller pieces. Then it allows more productivity in team development, because one team is going to be just responsible for one small thing. It's just because people, they are focusing on one small thing instead of a large software system. Then eventually, we may get fewer bugs in system development and also more maintainable software and also more reusable software, and resulting in more predictable software development. This is going to reduce the complexity of cost and time estimates for developing the system. Another way to deal with complexity is to provide training to software engineers. What do engineers do. Engineer they apply scientific knowledge, for example, mathematics, physics and then develop solution for some technical problems. Then engineers, they have to design materials, they have to choose the appropriate materials, structures, and also system while considering some limitations. For example, the time and budget that you have for the project. What do we have to do as a software engineer? There are two things that we have to do as a software engineer. One is programming-in-the-small, that means coding. Another thing is programming-in-the-large, that means software engineering. So apart from coding, there are many things that you have to do within software engineering. For example, you have to talk with users in terms of the application, you have to communicate with your client, and also communicate with your users. Then also translate the vague requirements into something that's going to be more precise. Then you have to build models of a system at different levels of abstraction so that when you communicate with your client, when you communicate with your users, you can use your models to communicate with different stakeholders within your project. Also you have to use and apply several software development processes, and we're going to talk about different development processes in one of the upcoming lectures. Also you have to choose the appropriate design and also make design trade-offs and work as a team. This is going to reduce the complexity of building the system.