So here comes an example. Your boss comes to you and says, I need you to write a program. And this program needs to copy from the keyboard to the printer. That's all. Just type on the keyboard and have it come out on the printer. That's all I need. And you think about that problem for a while and you realize that it's a very simple problem, and you can even conceive of the code in your mind. Here's a very simple little C program that will do that program. And look at what it does. It hangs in a loop, reading the keyboard until you hit an EOF character. And for each character you read, it writes it to the printer. Hallelujah. You have finished that program. That program works. You have finished that program. That program works. And if you look at the design of that program, you will see that it depends on the keyboard and the printer. The high-level module, the copy module, depends on the keyboard and the printer. And this, of course, is a source code dependency. Because if you look at the source code of the module, the source code actually mentions the keyboard and the printer. Now, that's lovely. Until your boss comes to you and says, you know, sometimes we would like it to read from the paper tape reader. Well, okay, now that we've got this code, we might as well modify it to read from the paper tape reader. And you'd like to pass an argument into this function, this copy function, but you can't because hundreds of other programmers are already using it. So you don't dare change the signature of the function, but you can always sneak a global in here. So we will create a global named gTapeReader and initialize it to be false, and then we will put a little if statement, in this case it's a question mark colon operator, into our code. If the gTapeReader global is true, then read from the tape instead of the keyboard. So the way you will use this is that before you want to read from the tape reader, you must set the global to true, then call copy. And you better remember to clear it back to false later. Otherwise, the next person who calls it is going to read from the tape reader. And notice what's happened to the design. The design has sprawled. It has spread out. It now has dependencies not only on the keyboard, but also on the tape reader. And of course, this is going to continue because at some point our boss is going to come to us and say, well, sometimes we need it to write to the paper tape punch. And so we might as well add another global and we made by the programmer very early on to depend directly on the keyboard and the printer. That did not have to be that way. Because the program could have been written like this. A program which reads from something. Get char, get char reads from something, in Unix it would be called the standard input, and put char writes to the standard output, which can be changed at runtime. At runtime, you can change standard input from the keyboard to the paper tape reader. And at runtime, you can change standard output to write to something besides the printer, perhaps the paper tape punch. If we had written our program this way at the start, then when our boss came to us and said, hey, can you make it read from the paper tape reader? We would have been able to say it already does without changing the program, without even recompiling the program. It already does. And if you look at the design of this program, it looks like this. It looks like this. The copy program up at the top is now depending on something that looks like an interface. In Unix, that interface had a special name. It was called the file or the stream. And the IO drivers below that implemented those interfaces. They were not written in an object-oriented language. They were written in C, but they were written using the same mechanism that an object-oriented language would use. That's, again, dependency inversion. The copy program depends on the abstraction presented by the operating system. The IO drivers inside the operating system implement that abstraction. Once again, dependency inversion. This is how we're going to manage everything.