And with that, let's go to the next principle, which is the open-closed principle. There we go. Here is the open-closed principle. Lovely, lovely. Let's make sure that we fit that into our space just right. And I want to do that. Good. All right. The open-closed principle. We're going to finish this principle, then we're going to take a quick break, and then we will come back and we will finish this lecture. All right, so the open-close principle was first articulated in the books that you see on your screen there. The book on the left is called Object-Oriented Software Construction by Bertrand Meyer. And the book on the right is the same book, but a decade later, it's the second edition. And both of them are wonderful books, although they're both quite old at this point. The first book was written in 1988, and the second book was written in the 90s. By the way, I should say that old books are not out of date, especially in software, especially if they're about software design and architecture. Software design and architecture is not evolving. It's not changing. It has remained constant for the last 70 years. Books on those topics are as valuable today as they were when they were written. So don't fall into the trap of thinking that a book that is five years old is out of date. These books are still very valuable. Now, you will find in these books that they use a language that has disappeared. They use the Eiffel language. Both of them do. And the Eiffel language is a language written by Bertrand Meyer, but nobody used it except for Bertrand Meyer. And so nobody, you wouldn't recognize it today. That's all right, though. I mean, the book still describes many principles and many ideas, very valuable, very valuable ideas. So in these books, Bertrand Meyer coined this principle called the open closed principle. What is this principle? It says that a software artifact should be open for extension, meaning that you should be able to change what the module does. This is the thing that we do, right? Software developers make changes to the behavior of modules. So that's what he's talking about here. A software architect should be open for extension. You should be able to change the behavior. should be open for extension. You should be able to change the behavior. But that same module should be closed for modification. You should be able to change what a module does without changing the module. That's the open-closed principle. And at first, that sounds impossible. I mean, how could you possibly change the behavior of a module without changing the module itself? But, but you remember that copy program that I showed you so long ago. There it is again. Here is a module whose behavior we can change without changing the module, without even recompiling the module. This module was originally written to copy characters from the keyboard to the printer, which it does very well. But later on, we can change the behavior to copy characters from the paper tape reader to the paper tape punch, or from the optical character reader to the voice synthesizer. It doesn't matter because we wrote it in a way where the behavior can be extended without modifying the code. And how do you do that? How do you write systems such that the behavior can be modified without modifying the code? And you do that by dependency inversion. You do that by separating the high-level policy, which is in that copy module, from the low-level details, which is down there in those I.O. drivers, keyboard reader and printer writer, and you make sure that the source code dependencies on those lowest level modules are inverted to point at abstractions. And the high level policy has source code dependencies that point toward abstractions. This is how you do the open-closed principle. You separate high level policy from low level detail, High-level policy from low-level detail, and you route designed your code such that you can change its behavior without modifying it, think of what that means. That means that every time you change behavior, you change behavior by adding new code, not by changing old code. You are allowed under this principle to add all the new code you want to add because you're not changing any existing code. The principle is just saying add new behavior without changing existing code. Open for extension, closed for modification. Add new code, just don't change any old code. Is it possible? And the answer to that is almost. It's almost possible. In our current software systems, there is almost no way to protect every module from change. Some modules are going to have to be open to modification, but you can limit them. You can minimize the number of modules that are open to modification. Generally speaking, you can focus those modifiable modules down towards main. Main, the first program to execute, main probably calls some configuration functions. And within those functions, you may have to make some modifications. But everything else in the system can be designed, if you are careful, so that you can add new features by only adding new code without changing any existing code. How do you do that? Sounds like a big design up front, doesn't it? Well, the big design up front idea just doesn't work that well at all. Because, and by the way, we tried it in the 90s. That was the big deal in the 90s. In the 90s, when we were studying object-oriented design, we thought that the solution to the problem was to think really hard for a very long time and come up with a design. And this design would protect us from changes anywhere in the system. And we would have to imagine all of the possible changes that occur. We got a big crystal ball out, and that crystal ball would let us see the future. And we would protect from everything that could possibly happen. We would think really, really hard and build these designs that sprawled all over the place. And then we realized two things after many years of trying this. Number one, the designs that we created were almost impossible to maintain because they were so large and so complicated. And secondly, and more importantly, it turns out that customers are really good at outsmarting you. They will come up with changes that you had not anticipated. In fact, we kind of think that maybe all the customers have a sneaky way of spying on our designs, and then they purposely choose the changes that violate our designs. So in the late 90s, we decided on a different alternative. And that, by the way, is called Agile. The Agile alternative is this. We will build our code as simply as we can build it. We're not going to do a lot of big design up front. We're not going to plan out lots and lots and lots of abstraction. We're going to build it as simply as we can. And then we're going to put it out in front of our customers every week. Or some people do it every two weeks. I like once a week. Depends on what your iteration size is or your sprint size is if you're doing agile. but I like to do it as short as possible because I want the system to go in front of the users or at least good proxies for the users every week because I want the feedback. I want them telling me, oh, well, we thought it would work like this, but it really ought to work like that. And we don't like the way this looks on the screen. Can you move that over here? I want to get the changes coming soon because when the changes come then I can design the abstractions that will protect me from that kind of change in the future. It turns out that the best predictor of future change is past change. So we want to get the customer to start making changes as early as possible so that we can begin to integrate the designs that protect us from those changes long before we have written too much code. We want to get that stuff into the design as early as possible. And that is the agile mindset for the way we integrate the open-close principle. That is the agile design process. We put things out in front of the customer frequently and early. And when they make changes, that's the moment that we protect ourself from those changes. Does that mean there's never a time that you think ahead and protect yourself from changes that you expect? No, it doesn't mean that at all. Sometimes we do. The truth is somewhere in the middle here. There are things that you can look ahead and say, well, I know the customer is going to do that. They're just going. And OK, maybe you're right. And maybe it's worth building the abstraction for that. But be careful with that. Don't do too much of it. Better to depend on the the actual changes that the customers make, because they're often very different from what you thought they were going to do.