Ready? Is Sound On?
Cool. Alright. So.
Do you see that red dot?
Why is it red?
It's dangerous.
I like that answer. Watch out! Take me to the Cuba.
Yeah, I've had the security people restricted me from going in the airports, because I'm carrying lasers with me.
They have, you know, sign on and it says dangerous.
But, why is that red?
I have a green laser.
Hey, you know, you gotta have lasers.
Alright? I carry three of them with me.
One of them is red. I always keep them in my back pack with the batteries (??).
Or turned around actually.
So this is my red laser. You can get a red laser for twelve dollars.
There it is. Red laser.
Nice. And I got a green laser.
This one is nice one.
A pretty bright one too.
Not bright enough to do anything interesting, but bright.
There is little adjustment in here.
You can cut a component out and put a different register in here.
Then you can get almost of quarter of Watt out of it.
The battery drains pretty fast. You can pop a balloon with it.
I mean that's cool. Boom.
But this is my favorite laser.
And I like this one because
Well, can you see that?
Little tiny violet dot. Do you see that up there?
See if I can show it to you here. Oh! That’s nice and bright.
On my thing here. That's nice and bright.
But over there, you can hardly see it.
Can you see this thing? No.
Can you see it here? No, not too much.
No, can't see it there much.
But, I found this once.
Just a marker. Litter laser doesn't do too much to the marker.
But the lid!
And look! It's yellow!
It's not blue!
And then see that little orange thing there?
Watch this! I gotta aim it carefully.
Wow! It's orange.
What kind of laser is this?
This is a laser of some other color.
My glasses are the kind that turn dark in the sun light.
I don't know if you can tell. But now there are all dark.
Alright? And I can't see any of you.
This is an ultra violet laser.
They don't bill it as such. You can buy them on amazon. 17$.
They say it's a violet laser. They lie.
It's much cooler than violet laser. It's an ultra violet laser.
Everybody has to have an ultraviolet laser.
It's completely useless as a laser pointer.
But you can draw nice little pictures on you glasses with it.
Oh~ I got my name.
Alright. Whatever.
Look at the code on the screen.
Anybody recognize that code?
I can't see it because my glasses are all dark.
Anybody recognize that code?
That's PDP-8 code.
That what code looked like in 1970s.
That's kind of code I was writing when I was slightly older teenager.
And then on into my twenties as well.
This statement right there.
Anybody know what that means?
That's the memory address which this program would be loaded.
We used to write the address our program into our program.
This program would be loaded at address 200.
And we put the data at address 300.
How about that?
And it makes perfect sense. Of course you would know where programs getting get loaded.
I mean who else is gonna decide that for you?
You are the programmer. You have control over memory.
Now, this works fine.
I'll show you a sequence of pictures here.
Let's see. Yeah, that's a nice one.
Hello. No, that's not the one what I wanted.
That's because nowadays when you open up documents
It opens up every document that's been opened by that application.
Don't save that.
That's the one I wanted, right there.
Imagine you are programmer who's writing this kind of code.
And you've got a program like this one.
My program lives here. It starts at address 200.
And there's a subroutine library that somebody else has written.
By the way subroutine libraries were not real common.
You usually wrote your own subroutine back in those days.
But after a while a few guys write some useful subroutines. You think "You know, I should have those in my program too."
And you think, "Well, just compile them in with my code"
That's what we used to do.
You just take the source code and jam it together.
What was the problem with that?
We were talking about the 1970s here. Right?
Those programs were contained on paper tape.
Paper tapes is being 50 characters per second, if you were lucky.
And so increasing the size of your source code lengthened the size of your compile by minutes.
So after a while these subroutine libraries got too long to continue to add your source code.
So what we did is we would compiled the subroutine library and we would loaded at location 1200.
Then what we could do is we could have a binary file which got loaded at 1200.
And we could have our program at 200.
And we did have a little file that all the symbols in it.
So the symbols would tell us which subroutine was loaded where.
So we knew the Get subroutine was at 205 and the Put subroutine was at 210 and so on.
And our symbols would get compiled in with the program
The subroutine would be loaded separately. And everything worked fine.
What's the problem with this?
When is the last time you saw a program that stayed small?
They grow!
And after a while, well let's see.
I got another picture here.
Yeah, that's that one.
Oh yeah, a program that got too big.
It overwrites the subroutines. This doesn't work.
When your program overwrites the subroutines, your program still thinks that the subroutines are there.
So when it calls the location 1205 it actually jumps into some arbitrary part of you code.
You didn't know this happened of course.
Until finally you debugged it and realized. "Oh, my programs got too big!"
What's the solution to this?
You are programmers, you can come up with the solution to this.
Jump around the subroutine library.
Right? You put it Jump right there to jump over here.
Of course the subroutine library gets bigger too.
And so after a while. Let's see if I've got that picture right.
How about that one? Yeah, that's the one.
After a while you get that problem.
We actually faced to this problems.
We actually had to deal with this stuff.
And you know how we solved it?
We came up with relocatable code.
We said "You know what? This idea of putting absolute address in the program is killing us."
"What we really like to do is compile our programs without telling them where they're going to be loaded."
"And then we'll tell the loader where to load them"
Now there's problem with that.
Because that means that your binary files cannot really be binary.
They have to have codes in them to tell you that certain address are not actually addresses. They are offsets.
And the loader has to find every address that's marked as an offset and add the start address to it.
But that works. We had relocatable loaders.
We made this relocatable binaries and loaders.
But now you've got another problem.
Because how do you know where the subroutines are.
If the subroutines are moving all over the place, how do you know where the subroutines are?
So now you have to add more information to the binary file.
This binary file you thought just binary of your program is now becoming very bizarre files.
It's got all kinds of gunky in it.
Now you have to put the names of the subroutine library into the binary file of the subroutines.
And you have to show what address they will get loaded at
And relocatable loader has to remember where it put those addresses
And then in the program you have to have another thing in there.
That says "Hey, I need to know where this programs gonna be loaded"
"And the loader has to link the subroutine library of the program."
Computers were slow in those days.
Disk drivers were very slow.
And there wasn't a lot of disk memory.
You were lucky if you had megabytes of disk.
And the seek arm took a long time and the rotational latency was high.
So link times took a long time.
Especially as we got more and more libraries.
More and bigger program.
Link time could take an hour.
Anybody have a link that took an hour?
Anybody here working in the 80s?
Oh no! You got one now!
You must be C++ programmer.
That says so, right on your shirt.
OSLO C++ Users Group.
Long link times.
Even in the 70s we had that problem. Although it was much smaller programs.
So the solution to that was to separate the link pace from the load pace.
We would link as a second compile step.
And that would produce a final relocatable file that had all the linkage were resolved.
And then we could load it at run time.
Ant that was relatively fast enough.
And for years and years and years. We lived with this 2 step process.
Compile down to binary files then link all the binary files into an executable.
And then you can load the executable.
And that solved problem until the 90s.
In the 90s something happened.
It was called Moore's Law.
What's Moore's law?
The speed of processors will double every 18 month.
Now apply that from about 1970 when the speed of our processors were half a million instructions per second.
And keep that going forward until the 1990s.
Well that's 20 years, how many 18 cycles is that?
Well, 18 month cycle is that?
That's about 15 cycles.
So we have 2^15 increase in speed.
Think about that.
2^15 increase in speed. What is that?
That's increase about 32000!
That's about right too.
Cause we went from about a half MHz to 2.8 GHz.
Well, maybe 1 GHz by the late 90s.
By that time disks were going faster too.
We spun up a lot faster in the road.
The heads weren't moving as far, we were getting a lot more bits around rim too.
We could get hundreds of MBs on a disk. Oh!
And somebody made a bright thought.
Somebody had a bright thought that
"We don't have to do the link separately anymore."
"We can do the link at the same time we load."
Anybody remember the ActiveX?
Anybody remember OLE?
What does DLL stands for?
Dynamically linked library.
Which means it's linked at load time.
The link step got moved back into the loader.
And we have the situation we have today.
Who's .NET programmer, here?
Look at that. A lot of people.
Java programmer! Raise your hands.
Not so many. How come?
How come it's all .NET? Oh maybe because it's a .NET kind of conference? Huh?
So, in .NET you got DLLs.
Dynamically Linked Libraries.
In Java, you got Jar files.
But they are still dynamically linked libraries. Same idea. Same purpose.
In C++, if you do in the Microsoft thing you still got DLLs.
If you don in UNIX thing you've got shared libraries.
They are still dynamically linked libraries.
Our mode of operation now a days is too dynamic linked libraries.
That's how we got here.
How many DLLs do you have?
Guys with the solutions, Visual Studio solutions.
How many projects?
60? That's not bad.
Who's got more than 60?
Oh, look at that.
Who's got more than 200?
And do you know why?
You separate your code into different DLLs?
Let me ask that question differently.
When you deploy your application,
Do you gather up all the DLLs and just ship the wad?
If you do then why are you dynamically linking them?
Statically link them.
Why would you bother with dynamic linking? If you just gonna take all those DLLs.
Gather them up into one gigantic wad.
Throw the big wad into directory. And says, "It's my system."
Why dynamically link if you not going to dynamically deploy?
Why did we come up with dynamically linked library?
We came up with dynamically linked library so that we could dynamically deploy our applications.
Why?
Well, we gonna get to network speed. Hang on in a minute.
Cause network speed has huge impact on this all thing.
Mid 90s I've got a client. He's got a 250MB executable.
In the mid-90s that was big program. Now it' not.
But then 250MB was big deal, you could not fit it on a CD.
This was CAD system. He shipped it to the company like Ford.
Ford would use it to design gears and levers. Stuff like that.
He statically linked it.
He would deploy the executable to his clients by burning it on several CDs.
If he changed one line of code,
He had to recompile, re-link, re-burn all the CDs and deploy all the CDs to all his clients.
And you can imagine how it cost him a fair bit of money.
I went there in the mid-90s.
And encountered them at a time
when they were trying to chop up their executable into this new Idea, DLLs.
Because they realized that if they had dynamically linked libraries
Then they could change a line of code
And ideally you would only have to ship that DLL.
You could e-mail it!. Back in those days that was a big deal.
You couldn't e-mail 250MB in those days.
Now a days you can as long as the guy you're talking to got a reasonable e-mail server.
But back in those days e-mailing 250MB was impossible, so they could e-mail the 100KB of DLL.
And so that was very very desirable for them.
They worked for month and month and month.
Chopping their application up in the little tiny bits,
turning them all into bunch of DLLs
And that when they realized their critical mistake.
The critical mistake was that chopping your system up into bunch of arbitrary DLLs
doesn’t do you a damn bit of good if they all depend on each other.
If they are all depend on each other then you can...
Was anybody just in Scott Meyer's talk here?
The last talk he just gave an hour ago?
He was talking about the problem of keyholes.
Problem of keyholes is that we arbitrarily constrain someone for no good reason.
Just arbitrary constrain them.
So for example, have you ever seen a text box on a GUI?
That was just too short?
And you had typed bunch of stuffs in it and it wouldn't let you resize the window?
It wouldn't let you scroll and you just had to type blind?
Or maybe the text with scroll but you wouldn't be able to see the beginning of it?
He was mentioning the keyhole problem.
And I know that something just happened here.
Apparently I'm not allowed not touch my computer for more than 5 minutes.
I must apparently touch my computer otherwise I'll be punished.
What was I talking about? Oh yeah, DLLs.
So this guy, he put all his DLLs together.
He forgot that DLLs depend upon each other.
His goal was to be able to touch a line of code
And just ship that DLL that was affected.
But he found that all the '#includes', C++ guys know what I'm talking about
All the '#includes' form the horrible network.
And he had to recompile and redeploy everything anyway.
They went out of business.
The purpose of my talk today, now that I'm getting around to it
is to talk about components.
The problem of component design.
And the first thing we gonna do is to define a component.
What's a component? Component is DLL.
When I talk about the word component what I mean is DLL.
Very particular kind of DLL. A dynamically deployable DLL.
A dynamically deployable DLL.
Why would we want dynamically deploy?
Well, because we would like to be able to change one line of code
Just ship the one DLL that changed and ignore all the others.
What's DLL hell?
A term invented, I believe, by Microsoft
to describe their own situation.
And was to be completely cured by .NET.
Anybody remember that line? "Dear .NET cures DLL hell."
Hu Hu Hu. No, it doesn’t cure DLL hell.
DLL hell is the problem that we've got all these little components with different version numbers
And nobody hell knows which one go should together
So we invented this module maintenance tools like Maven.
What are you guys using in .NET?
What's the tool that lets you keep all of your DLLs are in line.
So you know that download version 1 of that one and version 3 of that one.
Do you have tool for that? What?
NuGet?
Like the soft chewy (??)
Never mind, I'm not going there.
The graph you see on the screen is a graph of x^2.
That's just an x^2 graph.
But it's also something else.
It's the number of dependencies in a system.
Theoretical maximum number of dependencies, given a certain number of modules.
And you can see that the number of modules increases linearly
And the number of dependency increases with square.
The theoretical maximum number of coupling, which I show here
is proportional to the square of the number of modules.
Now of course we would never create a system that has every possible dependency in it.
Or would we?
Look at this curve.
This curve is the productivity of a team in comparison to the number of modules.
By the way this is completely arbitrary I just generated one of x squared curve here.
This is not me collecting actual data.
This is just me recollecting my experience with development teams.
They go slower and slower and slower over time.
Who's had this happened to them?
You start outgoing really fast. You can conquer the world.
A year later you slogging through some kind of horrible wet lands.
And you don't know what the heck has gone wrong.
But estimates that used to be on the order of one week are now three month long.
And by the way you blow all those estimates anyway and introduces more bugs than you fix.
That's the kind of problem that we have as we proceed a long development path.
And one of the reasons for that is accumulation of dependencies.
Why?
Well, that's the theoretical maximum dependency between modules.
This is the theoretical minimum.
If you're going to have an interconnected set of modules, there has to be some dependencies.
And the minimum set of dependencies is a tree structure.
Oh you can do some better with dynamically linking if you want to.
But for the most part, you gonna have a small number of dependencies.
How many do we have? 1. 2. 3. 4. 5. 6.
6 out of 7 modules.
Whereas here you've got
Well, I think that's half of 49.
It can't be half of 49 because that would be happy half dependency.
Maybe it's just a plain 49. I don't know what it is. It's a large number.
It's some relative of N squared.
Maybe it's one half n squared plus one half n.
Something like that.
It's a very large number of dependencies.
We don't want this. We do want that.
We strive very hard to get here.
But then, some shmuck does that.
Visual Studio doesn't allow this.
Uh! Inside solution.
Inside solution. The DLLs cannot have cycles between their graphs.
That's good.
Don't want cycles.
Between separate solutions there's no guarantee.
So you have multiple solutions.
If you're linking with things that come out of different solutions, you can still have cycles in the graph.
If you get cycles in the graph, it looks like it adds only one extra dependency.
But actually it adds more.
Because 6 now depends upon 2. Because 1 depends upon 2.
And dependency is transitive.
So 6 also depends upon 4 and 5. And 6 depends upon 3 and 7.
In fact, 6 depends upon all of them.
So number of dependencies multiplies dramatically as soon as you have a cycle.
This is the n squared graph again.
This is also a graph of C++ compile time.
As you add modules.
Compile time and the link time if you're doing static linking
But even if you're not static linking,
just compile time grows with the square of the number of modules,
if you have a fully connected network of modules.
What that mean is that your '#include' or your import statements or your using statements can be traced in a cycle.
And if you have that, then you gonna wind up with this big increase in compile time.
C++ in particular would do this.
Java and .NET don't.
Their compile time is based on a different metric.
They don't go reading source files. The way C++ does.
Java and .NET read binary files to get their declarations.
C++ reads source files to get his declarations.
And so if you had a cycle in C++, you got punished.
By a big compile time.
And a massive one.
It would go up with square.
So you would had couple of modules your compile time will double.
And that made us do something about it.
Who knows who Ward Cunningham is?
Oh, a few of you do.
Good. And the rest of you.
He's the guy who invented Wikis.
Ward Cunningham invented Wikis.
He's the guy who helped Kent Beck invent pair programming, test-driven development,
And most of the agile stuff.
Get to know who Ward Cunningham. He is very interesting fellow.
Smalltalk Programmer from a long ago.
And I asked Ward once.
"Why did Smalltalk died, Ward?"
And he said, "Smalltalk died because it was so easy to make a mess."
"You, C++ programmer,”
I was a C++ programmer at that time.
"You, C++ programmers are lucky."
"Your language punishes you if make a mess."
"Smalltalk didn't punish you."
Well, neither does Java. Neither does C#.
They don't punish you anymore.
It's very easy to make a very large mess.
And get a very tangled structure and not know you're doing it.
Fortunately Visual Studio keeps some of the cycles out of your graph.
We would like that level of productivity, which is n Log N.
Rather than this level of productivity. That's an n squared.
And one of the ways to help with that is to manage the dependencies between our components.
Then something happened to us in the late 90s and into the 2000s.
Network speed started increasing dramatically.
Now a days, it's not hard at all to download a GB in a couple of seconds,
And to upload a GB in 10 seconds.
That's pretty easy now a days.
Back in the early days it was much harder.
So, back in the early days we thought shipping individual DLL was going to be a benefit.
Now a days we just kind of gather them all together and ship the one big wad.
Why? Well because network speed is fast enough. We can do it.
We can treat our batch of DLLs just like it was statically linked.
But there's another issue.
How many of you work in teams?
Oh look at that. Everybody works in teams.
So, you come in at 8 in the morning.
You got a test to perform.
You work all day to get all your stuff working.
All works by end of the day.
You check it in and go home.
Come back the next day all your stuff is broken.
Why?
Somebody stayed later than you.
And changed something you depend upon.
And so you work all day long to fix whatever the problem was.
You go home and come back the next day and your stuff is broken again.
How many times can you go around that loop?
Lots of time. This is a problem of large teams.
Large teams will start to step on each other.
And of course we've invented tools to help us.
We've got source code control systems.
And we've got all kinds of good stuff to help us with this.
But we still can step all over each other, unless we manage our projects well.
So, how can we manage our projects well?
There is a principle.
A principle called Acyclic Dependencies Principle.
The Acyclic dependencies principle says, "If you have a set of components"
"You would like to be able to arrange without any cycles in the dependency graph."
Now, for whole bunch of reasons we've already talked about one of them.
Which is compile time. We've talked about another which is just dependency load.
Here is another.
Alarm would like to release its version of alarm.
The team that's working on the Alarm would like to make release 1.0.
They've got nobody that they depend upon.
So they are completely free to make any release they want.
So they release their version of 1.0. Alarm 1.0.
They start working on alarm 1.1.
But now Alarm 1.0 has been released.
Which means that Elevator and Conveyor can make their release.
And once Elevator and Conveyor made their releases they can start to work on 1.1.
But now Transport can make its release.
You can see what's happening here. Right?
The version numbers bubble up from the bottom.
1.0 gets created here. Then there. Then there. Here. Here. And finally there.
The version numbers bubble up from the bottom.
If you look at it closely, you'll realize that
the version numbers follows exact same path as the build. The compile.
Dependencies are running in that direction.
And now, some poor shmuck does this.
Who's this?
Well that was me. I did that.
I had an alarm subsystem I was working on.
And I needed it to put a message on the display and the control panel.
There happened to be a class up here that had a function called Display.
And I thought, "Oh! I should just call it." So I called it.
This was not in a language that restrict me from cycles.
And so it compiled and everything was fine and all worked okay.
And then the next day I had a group of angry developers come to my cubicles with club
And tell me "What the hell did you do?"
I said, "Well, I just called the control panel and display class that has display function in it."
"I needed to put this message on the screen."
And they said, "You can't do that."
Why can't we do that?
First of all,
what order should we build those modules in?
You'd like to build them bottom up.
But now there's no bottom.
So there's no correct build order.
If you have cycles in the component graph,
there is no correct build order for the modules in that system.
And therefore the execution of that system is undefined.
What does undefined mean? What's the definition of undefined?
Works in the lab.
Anything undefined will work until you actually deploy it somewhere. Then it will fail.
You can get systems to fail rather badly by having this cycles.
This is pretty common in Java.
If you have a system of Java that has cycles in it.
You can build it.
Although there is no correct build order.
Then you run your test. And test will fail.
Then you build it again. That will choose different build order.
And maybe the test will pass.
I know of companies that put their build in a loop until test pass.
But the problem is worse than that.
Because conveyor would like to make their release.
They want to release 1.1.
Now for them to release 1.1, they have to test with alarm 1.1.
But alarm 1.1 is waiting for control panel 1.1, which is waiting for transport 1.1
which is waiting for conveyor 1.1, which is the one trying to release.
So there's no way to make the release without checking all of that source code out into one place.
Integrating. Anybody remember integration.
The joys of integration.
Integrate the whole system and then make it work.
And while you're doing that you gonna be stepping all over each other.
So, if this cycle will bring back the problem of coming in 8 in the morning and find everything doesn't work.
But it's worse than that.
Because in order to test conveyor I need alarm.
Which needs control panel which needs revenue, which need the database.
The database takes 45 minutes to load and then it crashes.
I can't run my tests.
Ant the guys in conveyor saying, "Why the heck do I need the database?"
"Well, you need the database because of this strange dependency structure."
Anybody ever look at the number of DLLs that got loaded and scratch head and say,
"How come I need those?"
Anybody in C++ world have ever link line?
And wonder "what's all this stuff in the link line?"
"How come I need all that stuff?"
Right? You got cycles in the dependency graphs.
It's bringing in all kinds of gunk.
So the first principle of components is no cycles in the components.
What if you want to do this?
What if you really want to call some function from down here that lives up there?
How you gonna do it?
Well, you can put out another component.
That's one way to do it.
Here I took that class out of the control panel.
I put it in the display component.
Then the alarm component can talk to the display component.
The control panel can talk to the display component.
I can keep the cycles out.
That's common enough technique.
Remember, these are all DLLs.
So number of DLLs in your system will start to grow as people want to add cycles to the dependency graph.
Maybe.
Although there's another way to resolve the cycle.
You can use dependency inversion.
I could put an interface. A display interface.
In the alarm subsystem.
And have the control panel implemented it.
That turns the dependency around.
And changes a cycle into a straight tree.
What's OO?
What is Object Orientation?
Why do we like it?
How come all of our languages are object oriented languages?
We've been doing this for 30 years. We gotta know.
(Someone says) "Models the real world."
Models the real world! Thank you!
I planted him here so that he would say that.
So then I could rip him to shred.
No, that's absurd.
And that whole idea that OO has better way to model real world is plain non-sense.
It's something. Some guy concocted long time ago
To convince his manager to spend 12,000$ on C++ compiler.
Cause he couldn't figure out any other ways to get his manager to do it.
12,000$. Early C++ compiler costed a lot of money.
"12,000$. I'm not spending that for a compiler."
"Well, it will help me model the real world!"
"Oh. Okay then."
This whole notion of modeling the real world is downright silly.
What in the world is OO other than a bunch of functions using a bunch of data structure? Right?
Encapsulated. Okay fine. Encapsulated.
But bunch of functions using bunch of data structures.
How is that different from Non OO?
The answer to that is not easy to describe.
How that's different?
Well, okay. We kind of put the data structures in the functions together.
But we always used to do that.
Old C programmers used to that all the time.
Data structures in programs always went together.
There is a famous book called 'Algorithms plus data structures equals programs.'
Data structures now (??) working together.
So nothing really fancy about OO there.
There is one thing that OO gave us that we did not have before.
Because it wasn't safe.
And that's polymorphism.
Very very convenient polymorphism.
We used to have it in C.
Device independence in any operating system is an example of polymorphism.
If you can write a program, you don't need to know what device that program is gonna use.
It's a clearly polymorphic interface.
But that's dangerous in most languages.
Or it was back in those days.
Because you have to fiddle with pointers to functions.
And that was always dangerous.
What OO gave us was very very convenient polymorphism.
Polymorphism without thinking about it.
Java in particular all the methods are polymorphic.
There's no choice.
C#, you have choice. You can use that funny virtual keyword.
C++ programmers you've got a choice. You better use that virtual keyword. Especially on your destructors.
But most of us we don't even pay attention anymore.
All our functions are polymorphic. We don't even think about it.
Why?
Because when a function is polymorphic something amazing happens.
The flow of control goes down towards to derivatives.
But the source code dependency goes back towards base.
We can take a source code dependency and turn it around without changing the run time dependency.
How do you get DLLs?
How do you get components?
You isolate them.
But you have to maintain the run time dependency.
Visual Studio people
Are you using ReSharper?
Who is? ReSharper?
Look at that. Everybody.
Does Visual Studio know about ReSharper?
No.
Does Visual Studio call ReSharper?
Yes.
The flow of control goes from Visual Studio into ReSharper.
There are function calls in Visual Studio that their way into ReSharper.
But there is no source code dependency that moves from Visual Studio into ReSharper.
Because they've been inverted the dependencies.
You can create DLLs that your application will call.
But your application doesn't know it exist.
And you do that by inverting dependencies.
Turn them around.
So this is one nice way to do that.
Now the control panel is a plug-in to the alarm system.
The alarm system doesn't know the control panel exists.
The control panel is a plug-in.
And the alarm system would accept any kind of plug-in.
A lot of different things to do implement this display function here.
So we could have a lot of different things that we alarmed.
What would rather depend upon?
A component that was stable?
Or a component that was unstable?
Trick questions.
Right? Everybody knows that you want to depend on something that's stable.
But now let me define stability.
Is my laser stable?
It's not changing.
But is it stable?
Stability is not a Boolean.
Stability is a continuous variable.
And it is defined as the amount of work required to make a change.
If it takes a lot of work to make a change, it's stable.
If it takes very little work to make a change, it's unstable.
That is unstable.
Cause it doesn't take much work to make a change to its state.
This. Well I won't say that it's stable.
Cause it would take much work to upset it.
And this whole stage doesn't feel very stable to me.
So I may have to be careful about the way I move.
So let me ask the question again.
What would you rather depend upon?
Something easy to change?
Or something hard to change?
Modify the source code.
What would you rather depend upon?
A module whose source code was hard to change or a module whose source code was easy to change?
Same answer.
You wanna depend upon thing that hard to change.
And the reason behind that is very simple.
Do you mind depending on string?
No.
Why don't you mind depending on string?
Cause if those guys ever change string, they'll be held to pay.
They would suffer more than you.
That's the equation that we're talking about here.
You are happy to do depend upon something,
if it will hurt the authors of that thing more to change it than hurts you.
That's the equation.
You are happy to depend upon things
as long as you're not likely to change or at least the bastards gonna pay if they change.
So alright, we don't want to depend on things that are easy to change.
Think about that very carefully.
I don't want to depend on something easy to change.
Do we design parts of our system so that they will be easy to change?
Yes.
What parts of our system do we most want to be easy to change?
The GUI.
GUIs are volatile.
They change for no good reason at all.
People will change GUI just because they feel like it.
There will be some committee (??) to say,
"You know, our system look so old."
What the hell does that mean?
"Our system look so old, we need to give it a face lift."
"Marketing people have decided, we’ve gotta have whole new look and feel."
"Not gonna change any behavior."
"Just look and feel of the GUI."
GUI has to be easy to change.
The modules that hold that source code have to be easy to change
And that means that none of you modules should depend on the GUI.
No source code dependency should land on the GUI.
Your components should not have dependencies that land on the GUI.
GUI components have to depend upon the application.
Application component cannot depend upon the GUI.
Otherwise you wind up with the systems that wear the GUIs hard to change.
How many of you test your systems?
Automated test.
Through the GUI.
Got a couple of people.
You write test code through the GUI.
You are depending upon something that supposed to be easy to change.
You'll make it hard to change.
If you test your system through the GUI.
I have a client who have 15,000 tests all go through the GUI.
Same client, by the way.
Same one went out of the business.
15,000 tests through the GUI.
He had so many tests he didn't know what they were anymore.
He just knew they all had to pass.
If somebody touch the GUI
a thousand of those test would break.
He couldn't find the time to fix them.
So he came up with real simple rule.
What do you think that rule was?
No body touches the GUI.
They made the GUI hard to change.
The other thing of course could happened there is that you could lose your tests.
You spend a man year putting together nice automated test suite that go through the GUI.
And then somebody decides, "We need a face lift on our site."
"Pull all out the old GUI and put a brand new GUI"
And all those tests are gone.
And you get to rewrite them again, but you've got other systems you gotta test.
Don't test through the GUI.
Don't do anything through the GUI.
All dependencies point away from the GUI.
What other things do we want to be easy to change?
The database.
We want the database to be easy to change.
We want to be able to make changes to database without rippling through the whole applications.
All dependencies you should point away from the database.
Put the database in a component with all the dependencies pointing outwards.
Put the GUI into a component with all the dependencies pointing outwards.
I don't want to depend on anything that is unstable.
How can we measure instability?
See this guy up here?
That component up there?
Is he Stable? Or Unstable?
He's got lots of incoming dependencies.
No outgoing dependencies.
He's hard to change.
If I make a change to him, it impacts all those guys.
So this component here is responsible to those guys.
Oh and this component here is independent.
It doesn't depend on anybody.
It's responsible and independent.
I's an adult.
Stable. Adult.
This guy.
He depends on lots of other components.
No body depends upon him.
Is he responsible?
And dependent?
He's teenager.
And he's unstable.
These are the two extreme kinds of components.
At the two sides of component spectrum.
You've got the adults that highly stable.
And you’ve got the teenager who are highly unstable.
The unstable ones are easy to change.
That's what we wanna put all of our little code.
The stable ones are hard to change.
We can measure that stability by creating a metric.
That metric is a metric that I call "I"
'I' is equal to the fan-out. Number of outgoing dependencies.
Divided by the fan-in plus the fan-out.
And if you think about that for very long.
You'll realize that 'I' is a metric that goes from 0 to 1.
0 being stable. 1 being unstable.
0 being an adult. 1 being a teenager.
It’s all about the dependencies.
And now we can re-phrase the principle to say this.
Every dependency in a component graph should point at something more stable than it is.
Or, if use the metric, these arrow should point in the direction of decreasing 'I'.
Decreasing instability. Increasing stability.
And you can do the math on just the fan-ins and fan-outs and verify that's correct.
Why was the cycle bad idea?
Something stable depended on something unstable.
But that leaves us with a problem.
And the problem is this.
What's that guy?
Stable? Or unstable?
He's really stable.
He's sitting down here the bottom of the graph.
Everything over here depends on him.
He's very hard to change.
If I touch that component, all these other components will be affected by.
For no other reason than the release number changes.
That means the stuffs down here at the bottom of graph is very difficult to work with.
But there's an escape to that.
Back to polymorphism.
How can you make something easy to extend?
Even though it's hard to modify.
You make it abstract.
Abstract classes can be extended trivially.
Without having it modified.
You can add new features to a system
if those new features live inside the derivatives of base classes.
So the final principle is this.
We would like abstractness to increase as we go down the zeros. (??)
Stuff up here concrete.
Unstable and concrete.
Stuff down here abstract and stable.
Abstractness becomes more and more prevalent as we go down this tree.
In fact, we could say that abstractness is a number
which is the number of abstract classes divided by the total number of classes in a component.
And if you did that, you get this number 'A' which goes 0 to 1.
0 being concrete.
1 being entirely abstract. Composed of nothing but interfaces.
And then we can do this very interesting thing.
We can say that for any particular component 'A' plus 'I' should equal 1.
Either it's abstract where 'A' is 1.
And stable where 'I' is 0.
Or it is instable where 'I' is 1.
And concrete where 'A' is 0.
'A' plus 'I' equals 1.
The magic formula of components. 'A' plus 'I' equals 1.
Now you've got the adults up here which are abstract
And everybody depends upon them. So they are stable.
You've got the teenagers down here.
Everybody that's got no incoming dependencies but they're very concrete.
What do you got here?
This is the line 'A' plus 'I' equals 1.
This is where we would like our components to sit if they can sit. One of those two end points.
Why?
Well, what's up here?
Highly abstract. Nobody depends upon on it.
An interface that nobody implements. Useless.
This is the zone of uselessness.
We don't want our components going that way.
What's down here?
Very concrete. Everybody depends upon on it.
Database schemas.
Concrete. Everybody depends upon them.
Fun to change.
Right? We don't want things down here.
This is the zone of pain.
We would like our components to be as far from those 2 points as possible.
Ideally if we could get them here and here that would be best.
But it turns out the components are persnickety that way.
So at least we'd like them to be sitting along this line.
Or close to the line.
Which leaves us the one last metric.
'D'
How far away is a component from the line?
Well, 'D' could be the absolute value of 'A' plus 'I' minus 1.
You can do the math on this. It's not very difficult.
'D' is the metric that goes from 0 to 1.
0 means that right on the line.
1 means that one of the two bad end points.
If you wanna know which end point you can take the absolute value signs off.
But I don't care.
You can measure 'D' by looking at the fan-in and the fan-out of the component.
Measuring its abstractness.
Doing the math is not very difficult math to do.
And find out whether your component sits nicely on that line.
If it does then it is abstract as it is depended upon.
If it doesn't that means either it's very abstract and not depended on
or very concrete and heavily depended upon.
Both of which are very bad ideas.
There are lots of tools that automatically calculate these metrics for you.
If you ever used NDepend. That will calculate the metrics for you.
If you ever used any of the other static analysis tools,
they can generate all these metrics. I. D. All of them for you.
So that you can look at your components and see if they fit.
And then think about what should be easy to change.
Things that are easy to change should be in teenagers.
Things that are hard to change should be in adults that are abstract.
Concrete teenagers hold the stuff that's easy to change.
Abstract adults hold the stuff that's hard to change.
Any questions?
We started with PDP-8 assembly code and got here.
Any questions? No?
Good.
Oh, damn.
It's alright. It's okay.
(Someone is questioning.)
Yep.
(Someone is questioning)
2 versions.
(Someone is questioning)
Yeah, 2 versions. Same component. You kill the programmers.
Yeah.
Don't have multiple versions of same component in you system please.
That's DLL Hell.
Anybody else? Yeah.
Where do you place...? Very very good question.
String class sits right there.
It's in the worst possible place but nobody ever changes it. So we don't care.
This is all about the stuff we are actively developing.
The stuff that is being changed.
So we pay very close attention to the stuff that's in our libraries that are changing.
The stuff that we get from other libraries that's not changing.
Or the stuff that's in our old libraries that's not changing.
We not gonna pay attention to that here.
A lot of that stuff may live here.
And that's okay.
None of it's gonna live here.
Well, some of it might.
Anybody pull out any dead code?
Abstract classes that nobody implements?
Yeah, okay. So maybe you see some stuffs there.
But String, Vector, a lot of libraries live down here we don't care because they're not volatile.
Think of another axis is coming out from this graph, right, towards you.
That's the axis of volatility.
This is a slice where volatility is close to 1.
The stuff where volatility is 0, we don't care about it.
Anybody else?
Yo! In the back.