(The talk starts at 4:45)
Alright you all hear me okay?
Way in the back up there you hear me alright? Well it's OK, good good good
Um what is an electron?
So part of atom, everybody knows that, I think
It's um.. (Screams from other room) yeah I think so, . I think that's royal ???
Electron is part of atom
It's carries a unit of electronic charge, negative charge, as oppose to a proton which carries a positive charge
It apparently has mass, though not very much, thousands of electron or something like that. Very very small amount of mass
And we think of it as a particle, although that's misleading. The electron actually behaves much more like a wave than like a particle
Why do we think of it as particle?
And the reason we do that is that when an electron interacts it interacts at a location like a particle would
But when electron is moving through the space it does not moves the way a particle would
It moves as a wave and the wave has no location
You look at an ocean wave, and ocean wave can be huge
It has no distinct location it has a well defined energy but no distinct location
This is how an electron moves
Electrons obey a principle and it's a mistruster principle
It's called the poly exclusion principle
Two electrons bound into the same system will not be in the same state
For whatever reason they cannot be in the same state
so if there are two electrons in an atom
those two electrons must be different somehow
Now they might different in the direction of their spin
An electron can spin to the left or spin to the right
Two electrons that have exactly same energy could fit together spinning one left and one right
There's no way to get a third one in there
So the next electron must have higher energy and then you can have two more
One spinning left one spinning right
But if you wanted to add another that would have to be something different about them
And you could arrange them differently in space
So you could have one group of two this way and another group of two this way and another group of two this way and one group of two in a sphere and that adds up the eight by the way.
Most of our atoms that we know of have this need to have 8 electrons in their shells
The reason for that is just this nice little geometry. the sphere and then three rows and each one of those can contain two
Have you ever thought about water?
I got some here. Fascinating substance
What's it made of?
Two hydrogen atoms one oxygen atom that's what makes a water molecule
And what's it shaped like?
Mickey mouse! yes, there is big oxygen in the middle and two little hydrogens forming the ears
The angle there is the result of (??) the shell arrangement.
What makes the hydrogen and oxygen stick together?
Think of two atoms, two atoms covered by electrons, two electrons are parallel each other
What would make two hydrogens and an oxygen stick together?
And it turns out that if you take these two hydrogens and big oxygen you lay them next to each other
And you think of the electrons as waves, not particles, then where those waves like to be?
And those waves would like to be mostly between protons. Protons in hydrogen atom and protons in oxygen atom
So they will congregate those electron waves will congregate more
Between two atoms, between three atoms actually, then everywhere else
They still go everywhere else that just that more likely to be between them
That means there's little extra negative charge between the atoms and that little extra negative charge to tracks the protons and that's covalent bonds
Now if you take this Mickey mouse atom and you divide it in half
You find there's more negative charge above the one and below the one
Cause all that negative charge likes to sit there between the two hydrogen atoms and oxygen atoms
So there's more negative charge on one side than the other which means that water molecule is a dipole
It is negative one side and positive on the other
This is why water is wet.
Water sticks to your hand because all the water molecules rotate to stick to the electrically charged surface of your skin
Even though it is not very electrically charged
This is why water makes it good solvent because the little water molecules would rotate to attract to the parts of the other molecule that they want want to stick to
This is why water makes it a good cleanser
And this is why water will do one of the most wonderful things you can do with water. Who's done this experiment?
You get a water faucet. You turn it on just so you get a really thin stream of water. Not very fast, just tiny stream of water
And then you get a balloon and you rub the balloon on your head. And then you hold the balloon close to that stream of water and watch the water bend towards the balloon
As all the water molecules turn around get it tracked the electric charge
Of course that's not what we supposed to be talking about
The name of the talk I'm about to give you is called "Architecture the lost years". It a talk I've been doing for several years.
It's about the next step after clean code after clean design.
This is about clean system structure
And it begins with that
This is a directory structure of an application I wrote close to ten years ago now
I was studying Rails. Anybody here Ruby programmer, Ruby on Rails programmer?
We got a guy over there, waving his hand around. OK.
I was learning Rails at that time. And I wrote this application
And it was I followed the book. You get the books out. You follow the book
Follow all the recommendations of the book and that's what I wound up with
And I was happy with that. I put the application away and I didn't look at it again for very long time.
Then about three years ago. My son, at my request, wrote an application.
And I looked it in and I saw that.
Same directory structure.
These are two completely different applications. It had nothing to do with each other.
But they had same directory structure. And I looked at it and I thought.
Wait why did these two applications have the same high level structure?
They are two completely different applications.
And it occured to me that they had same directory structure because they were both Rails applications.
And I asked my self, okay but why is that important?
Why is Rails or any framework so important that it would dominate the high level directory structure of an application?
And the reason I asset question of myself was because of this.
The web is a delivery mechanism. The web is an I/O channel.
The web is not architecturally significant.
We think of ourselves as writing web applications.
We are not writing web applications.
We are writing applications that happened to deliver their content over the I/O channel known as the web.
And why should that I/O channel dominate us?
Does anybody remember when the web became important? 1980? 1990?
Anybody remember what a change that was? How radically different everything was?
Except that it wasn't. Because we weren't really doing anything new?
We were just gathering input from an input source. Processing it and spitting it out to an output source.
That's all the web is.
Why would web dominate so much?
So I started to thinking about architecture. And I started to looking at blue prints.
There's blueprint. and if you didn't have the word library staring at you. it wouldn't take you long to figure out that it was a library.
Because it's obviously a library.
You got a bunch of book shelves in there. You got a bunch of reading tables.
There's little computers sitting on tables. There's an area upfront where you have the desk you can borrow or return books
It wouldn't take you long to look at that and think "Um.. that must be something like a library."
Or here's another one. That's a church. It's obviously a church.
Oh, you might mistake it for a theater. Theater and church do have certain synergy to them.
But no this is definitely a church. The puse(??), the altar, the classrooms on the outside, the greeting area around the front
This is clearly a church.
The architecture of this buildings is not telling you how they built. The architecture of this buildings is telling you what they are for.
Their intent. Architecture is about intent.
And the high level structures of those Rails apps were not communicating intent to me.
They were telling me that they were Rails apps. Something wrong with that.
And then it occurred to me.
This is known problem? It's a solved problem. It was recognized and solved by Iva Jacobson in 1992 when he wrote this book.
Who got this book? Anybody read this one? I got a guy here, anybody else?
Object-Oriented Software Engineering, if you have. Wonderful Book.
It's 1992 little bit old, but it doesn't matter. The principles inside still perfectly good.
Notice the subtitle, the subtitle says "A usecase driven approach"
Who remembers usecases? Uh.. See? It was very popular in the early 90s. big big deal.
In fact it was so popular that it was utterly destroyed by all the consultants who invaded the realm and ruined what usecases were supposed to be.
You may recall if you remember that era that one consultant after another would publish on the Internet their own particular format for usecase.
And the format became all important. We had PDFs all out there, force you to fill in the blanks of a standard usecase form.
Anyway the fill in the name of the usecase and the input to the usecase and the precondition and postconditions
and primary actor and secondary actors and the (???) actor. What the hell is the (???) actor?
You had to fill in all the stuff and the whole problem of usecases became one of form instead of one of function.
And right about the peak of the era, the agile movement began.
And we stop talking about usecases and we started talking about stories and whole usecase thing fell on the floor. Nobody talked about it again.
And so I brought it up again and I read through the manual again, the book again.
And I remembered what Jacobson wrote.
Here is a usecase. Typical of the kind of usecase that Jacobson would have written.
If you notice that it has very little form.
Oh a little bit. It's got a name up there created order. Imagine this is a usecase for order processing system.
And it's got some input data like the customer id and customer contact information and the shipment destination.
Notice that I'm not supplying any details. I'm not saying what the customer Id is.
Whether it is a number or string, I don't care.
I'm not saying what the customer contact info is, I assume it's got a name and a date and a address and few other things. But I don't care.
I'm not trying to specify the detail here.
And then you've got the primary course.
And the primary course is the set of steps that computer will undertake to satisfy the usecase. these're the processing steps. (??)
And the first one is the order clerk issues the create order command that's actually not something the computer does.
And the second step is the system validates all the data. Notice I don't say how. Just validate somehow it doesn't matter.
Third step is system creates the order and determines the order Id.
I presume that some kind of database operation but I'm not going to say that here.
And then fourth step is at the system delivers order id to the clerk. Probably a web page but I'm not going to say that.
In fact, this whole usecase says nothing about the web.
This usecase would work no matter what the input output channel was.
I can make this usecase work on a console app, a desktop app, a web app, a service oriented architecture app, I Phone app it doesn't matter.
Because the usecase is agnostic, it doesn't care about the I/O channel.
Jacobson said you can take that usecase and turn it into object.
He called the object a control object. I've changed the name to an interactor to avoid confusion with Model View Controller.
Maybe I should have change the name to usecase. But I didn't. Interactor is what I've written here.
The interactor object implements the usecase, it takes as its input, the usecase's input, it delivers as its output, the usecase's output.
And it implements at least the high level. The rules, the processing steps of the usecase
Notice there's the caption below there. It says interactors have application specific business rules
There are two kinds of business rules
There are the kinds of business rules that are global, they are true no matter what the application is. They are application independent business rules
And then there are other business rules that are tied to the application you're writing
So for example, let's say that we've got an order entry application and an order processing application. Two completely different applications
Both of them might have an order object and that order object might have common business rules
Regardless of which of the two applications you're inside, but only one of those applications would have insert order usecase
So usecases are application specific, they're bounded to the particular application they're in
Business rules that are not application specific are bound to entity objects, some people would call these business objects
I don't like the term, entity objects that's what Jacobson called them as well
You put all of the application independent business rules into your entities and the interactor will control the entities.
Then you have to figure out the way to get the input and the output out of the usecase into another usecase
We do that in this case with interfaces. I have drawn these as object-oriented interfaces
And notice that the interactor uses one of the interfaces and derives from the other.
The one it derives from is the input interface. The one it uses is the output interface
Notice that the arrows point the same direction, that's important
We'll come to why that's important in a minute
So these are the three objects the Jacobson identified as part of his architecture for applications
Now let's trace this through, let's see how it works.
There's typical application. I've got some user out there that's that little man standing there
That's actual real person and that real person is interacting with system through some delivery mechanism.
Maybe it's the web, maybe it's not, who cares.
The person, user, pushes some buttons or type on the keyboard or does something that stimulates the system to accept data.
The delivery mechanism, maybe it's the web, maybe it's something else, it doesn't matter
Translates that into the creation of something that called request model.
A Request Model is a pure data structure.
A Plain Old .Net Object(POCO) or Plain Old Java Object(POJO), a raw data structure it has no idea where data came from there's no trappings of the web
If there's the trappings of the web anywhere
It's just a plain old data structure, no methods on it. No nothing.
Bunch of public elements in a data structure, it contains all the input data
That gets passed into an interface, the input boundary interface which the interactor derives from
The interactor receives the requests model and reads it and interprets it
And turns it into set of smaller commands which it sends to the entities
All the little business objects out there, it controls the dense of all the methods calls to the entities.
And once the job is done, then it reverses the flow. And it queries those entities and says, 'OK what happened to you?'
And there's the result of that it builds up yet another data structure called Result Model.
Result model is still just a plain old data structure, nothing knew about it, just an old plain .Net or Java object bunch of public fields no methods
That result model gets passed through the output boundary to the delivery mechanism where gets displayed somehow to the user.
That's the flow of just any other application.
Could you test that interactor?
must be easy wouldn't it?
Create the input data structure, invoke the interactor
look at the output data structure
Do you have to the web server running to do that?
No, because the interactor, just plain old Java object or plain old .Net object, so all the data structure
Do you have to the database running to do that? Well you might. But we'll deal with that in a minute.
I can test this without the delivery mechanism in place at all
If my delivery mechanism is the web? I don't care! I don't have to have the web server running?
I don't have to test it with the web pages.
I can test the functioning of the system without going all the way from the inputs to the outputs
What about MVC?
Isn't MVC the thing we all supposed to doing?
What is the MVC stands for? Model View Controller. Who invented it?
That guy. Now I'm going to completely mispronounce his name. You can probably say it better than I
But I'm gonna call him Trygve Reenskaug. You can probably say it better than me.
I met him once. This is the guy who invented model view controller in late 1970s.
I met him once. I met him here at this conference two years ago.
I was up in speakers lounge and I was hunting for a power outlet
And this old guy walks up to me and hands me a power outlet
I looked up and... Trygve Reenskaug!
And as he handed me the power outlet our fingers touched!
I haven' washed that hand. Trygve Reenskaug.
Some people came up and took their picture with me today. I'm a fan boy too.
In the early 80s and late 70s, Trygve Reenskaug came up with this structure called model-view-controller.
He did this in the Smalltalk platform.
And the idea behind it is very simple.
You've got a model object, the model object contains the business rules.
It does not know how it's displayed. It does not know where the input comes from
It's pure business rules nothing more. There's a controller down there. The controller handles all the input.
The job of the controller is to look at whatever the input device is, keyboard doesn't matter. And translate the actions of the user into commands to the model.
Then you've got the View.
And I've drawn the view with the funny double arrow. That's an Observer relationship.
The View registers with the model. And whenever the Model is changed it calls back to the View, telling the View to re-display.
The job of the View is to display or represent or somehow convey the contents of the Model to something else.
It works nicely on a graphical user interface. It also works just as well on a console device or service oriented architecture or any other kind of application you wish.
You have something that controls the input, (Controller)
something that controls the process (Model)
something that controls the output (View)
This probably the very first named design pattern ever, was meant to be used in the SMALL.
You would have a model view controller for a button. You would have a model view controller for a checkbox. You would have a model view controller for a text field
We did not have model view controller for a screen
Since those early days, this has been twisted and warped and turned because like anything in the software.
If it turned out to be a good idea, everyone else would copy it. And use the same name for something completely different and call it good.
This happened with OO
It happened with structure
It happened with Objects
It happened with Agile
This happened with anything if the name connected with something good, then someone else will connect the name with their stuff and try call it good.
And that's what happened with MVC now. Nowadays we have these MVC frameworks
They don't look anything like that. They are not model view controller in the sense of Trygve Reenskaug's model view controller
They are something very different. In fact, they're kind of look like this.
Here you've got a bunch of controllers up there. Now the controller, if we think of the web, the controller are somehow activated by the web framework in the sky
The web framework in the sky, whatever it is, who cares, Rails, Springs God know what
will somehow route the complicated and horrible URLs that come from the web to a set of functions that we call Controller.
And it will pass into those controllers the arguments and the data came from the web.
And those controllers will then reach over and start yelling at the business objects, telling business objects what to do
Then they'll gather the data from the business objects and talk to the Views. And Views will then reach back into business objects and gather a bunch of data out of them and represent them.
And what you wind up with are business objects that get polluted with Controller like functions and with View like functions.
It's hard to know where to put the different function sometime they go into the business objects when they really shouldn't.
How can we deal with the output side?
It's gathered the data from the entities the job of the usecases done. The response model has been built. We're about to pass the response model through the output boundary
Here I show you the interactor. The interactor has done its work
And what implements that output boundary? Something called Presenter.
The job of the presenter is to take that response model which, remember, is a pure data structure.
And translate it into yet another pure data structure, which we would call a View Model.
The view model is a model of the output, the representation of the output. It still a data structure.
But if there is a table on the screen, there will be a table in that data structure
If there is a text field on the screen, there'll be a text field in that data structure
If the numbers on the screen need to be trimmed to two decimal places, there will be TrimToTwoDecimalPlaces and ConvertIntToStrings in the view model.
If they have parenthesis around them if they're negative those parenthesis will have been put on them by the Presenter and put into the View Model.
If there are menu items, names of those menu items are in the View Model.
If some of those menu items need to be grayed out because they're inactive, there are booleans in the view model that tell you that they should grayed out
Anything displayable is represented in the view model data structure in a displayable but still abstract way.
And then that get feds the View.
And View is stupid. View doesn't have anything to do with, just takes all the fields from the View Model. Put somewhere they have to go. Boom Boom Boom
No processing, No if statement, it might be a while loop to load up a table. But that's about it.
The View is too dumb to worry about we don't usually even bother about testing the view. Because we gonna look at it with our eyes on it anyway.
Can you test that Presenter?
Yeah! You handed it the data structure with response model. And You look to get the View Model data structure out.
You can test that Presenter. Do you need the webserver up and running to test Presenter?
No, You can test all the stuff without webserver running.
You don't have to fire up Spring or whatever God knows all the container You've got
You don't know how to fire up all this goop.
You test all this stuff just like the little old objects
And by the way that's a goal. You wanna test as much as you can test without firing up anything.
You don't have to start the server, start that server, start this thing, start this thing which takes 30 seconds to a minute.
You don't have to any of that. You want to just be able to run your test Just like that boom boom boom boom, fast as you can.
There's the whole piece.
From the interactor out, you can see the interactor takes data in from the request model through the input boundary
delivers data through the output boundary through the response model into the Presenter
And now look at that black line. That black line is the line that divides the delivery mechanism from the application.
And notice that every arrow crosses that black line pointing towards the application.
The applications knows nothing about the controller or the presenter.
It knows nothing about the web, it knows nothing about what that I/O channel is.
The I/O channel knows about the application, the applications does not know about the I/O channel.
If you are to put them in the separate Jar files, there would be no dependence from the application jar file upon the web jar file
And that also ways to go. You'd like to be able to put them in the separate Jar files. So that you could have a Jar file for the web and a jar file for your application
And maybe another Jar file for some other I/O mechanism.
And the way that you would change I/O mechanism is simply swap out the jar files.
Think of the I/O mechanism, the web, as a plug-in. How many of you use .Net Sharp isn't it?
You guys all .Net are you? Who's .Net?
What IDE do you use? Do you have any plug-ins? So a plug-in
Which of the two authors, the author of the IDE and the author of the Plug-in. Which of the two authos knows about the other?
The plug-in authors know about the IDE authors. The IDE authors don't know anything about the plug-in authors.
Don't care.
Which of the two can harm the other? Can the plug-in author harm VisualStudio?
Who's using Resharper? Yeh. Can the Resharper guys, JetBrains guys can they harm VisualStudio?
- (Listeners) Yes, yes
- (Robert Martin) Well, they can break it.
But can they harm it in the way that the authors of VisualStudio must respond to?
The software developers at Microsoft will they ever respond to JetBrains?
No, they don't care about JetBrains.
Can the developers at Microsoft force the developers at JetBrain to respond to them?
Yeh, Big time!
Now, think about that in your application's point of view.
Which parts of your application do you want to be protected from other parts?
Which parts do you want to be forced to respond the changes in the other and which ones do you not want to be forced to change in response to the other?
And the answer to the ought to be very very clear.
You would like to protect your business rules from changes to the web.
You don't wanna protect the web from changes to the business rules.
But changes on the web side should have no affect at all on the business rules side and that's what the architecture guarantees you.
All those dependencies point inward towards the application. Keep that in mind. That is the plug-in architecture.
Which leads us to the database.
What about the database?
Is that your view of the database?
Do you think of the database is the great god in the center with little minions around outside being applications?
Does anybody have a job function of DBA? Do we have DBAs in the room?
Aha I'm safe. Good.
Anybody know about the DBA? Rolled it over the applications. Panned out the schema. Make sure the database is right.
Is this how you think about the database?
Because here's my point.
The Database is a detail!
It's not architecturally significant!
The database is a bucket of bits!
It is not an architecturally significant element of you system.
It has nothing to do with business rules.
God help you if you are putting business rules in the stored procedure.
What goes in the stored procedure are enhanced queries, validations, integrity checks, but not business rules.
Why do we have databases?
Where did this whole database thing come from? Why is there Oracle?
Where did we store all that data?
We stored it on spinning disks. Is anybody written a disk driver?
Anybody written a software that controls memory in and out of spinning disk?
Nobody! Oh gosh. Oh... Yeah! disk driver!
What? Diskette? That's good enough!
So getting data in and off of a disk is hard. Why is it hard?
Because of the way the data is organized on the disk.
The way the data is organized on the disk in the circular tracks.
The circular tracks go around the surface of the platter. There can be many platters.
There are heads that move in and out to find the track, so you've got to move the head to the right track.
Then the disk spins around and you've got to read the data off the disk.
You try get to the sector you want. There might be fifty of sixty sectors around the surface of a track. Each of the sectors might have 4k bytes.
So you gotta wait for the disks spin around until your sector comes then you gotta read the sector.
And then you go into that sector and find the byte you want.
That's a pain. And it's slow.
And if you don't optimize it can take forever to get anything in and off the disk!
So we wrote the systems that optimize for that particular problem. We called them databases.
But somethings happened.
See my lap top there? My lap top has half of terabyte of Solid State Memory. Doesn't have a disk. That shouldn't be a surprise to you.
Is anybody have disk in the room?
Is there a spinning disk in this room?
Oh my god, really?
Huh, you know, nowadays we don't even think about spinning disks anymore. We think about Solid State Memory.
Oh we think back in the server room. There's probably spinning disks. But, there are going away too.
You watch over next few years. spinning disks begin to disappear. Everything gets replaced with RAM.
And I said RAM, didn't I?
RAM is directly addressable at a byte level.
What we are approaching is a virtually infinite amount of directly addressable RAM that is persistent.
That's where we are going to be storing our data.
And if that's where we are going to be storing our data, why in hell would we want to use SQL to access it?
SQL's pain. Tables are a pain.
Wouldn't you rather be following pointers around when you rather looking things up in hash tables?
Isn't that what you do anyway? You read all the tables into memory and then put the data into better organizations You can actually use it?
What if we just left it in that format that we want to use it?
If I were Oracle I would be scared to death.
Because the reason for my existence is disappearing out from underneath.
The notion of a big database system is beginning to go away.
How can I protect my application from this detail?
This detail of database tends to dominate everything and I can protect it the same way I protected my application against the web.
I draw another one of those nice big heavy black lines.
And I make sure all the dependencies cross that line going inward towards the applications.
I make the database a plug-in to the application.
So that I can swap out Oracle with MySQL
or I can yank out MySQL and put in CouchDB
or I can take out CouchDB and put in Datomic or whatever I wish.
I can plug in the database.
You may never change the database but it's nice to be able to. Even if you don't have to.
How do we do it? Well, fairly straight forward, there's another interface up there.
I called it here the Entity Gateway.
You probably have one per entity and the methods in the gateway are all the query methods.
Anything you might query, there's function for, method for
You implement that method down in the entity gateway implementation below the line.
And that implementation uses the database whatever it is.
Notice that no part of the database manages the leak into the application.
Where the entity objects come from. Well entity objects are probably fetched out of the database although got knows what crazy way they've been spread out in the tables.
The implementation of entity gateway will gather the data together.
Create entity objects and then pass them across the line.
So once you get them above the line, they are real entity objects.
Guys using something like Hibernate? Some ORM tool?
Who's using something like that?
Where would that be in this diagram?
In the implementation! Below the line!
No part of that ORM tool would be known above the line.
Are You using those funny little annotations and attributes in business objects? Get them out of your business objects.
You dont' want your business objects to know that there are built by Hibernate.
Let them be built below the line by somebody who's polluted already by the database concept.
Keep your business objects pure. Why?
What's an object?
I've got time for this.
What's an object? An object is a set of public methods
And well you are not allowed to know the rest, are you?
There might be data in there. But you're not allowed to see it. It's all private, isn't it?
From you point of view, object is bunch of methods. Not a bunch of data.
And object is a bunch of methods.
An object is about behavior.
An object is about business rules.
It is not about data.
We presume there's data in there somewhere, but we don't know where.
And we don't know what formats in it. We don't want to know.
What is a data structure?
A data structure is a grouping of well known data elements. Public. Visible to everybody.
And there's no methods in them.
Data structures don't have functions.
These two things are exact opposite of each other.
A data structure has visible data and no methods. An object has visible functions and no visible data.
Precisely the opposite.
There's no such thing as an ORM.
Object relational mapper? Can't do it.
Because what comes out of database is a data structure and you cannot map a data structure to an object.
Cause they are completely different things.
What's happening here is that the data needed by entities gets put somewhere. God knows where.
And somehow magically passed to an entity that uses it somehow. And I don't care how.
Those entities are not constructed by Hibernate.
Probably those entities use bunch of little data structures that Hibernate did construct but I don't care how.
I don't want any knowledge of Hibernate or any other framework to cross that black line.
Stuff below the line can be polluted.
Above the black line, those are my family jewels. I'm gonna keep them protected.
Those are my business rules. I'm not going to allow my business rules to be polluted with frameworks.
Frameworks. We like our frameworks. We think they're cool.
We think frameworks save us a lot of time and they do.
But the authors of frameworks entice us to bind to them.
They offer us base classes for us to inherit from.
When you inherit from a base class, you marry that class.
You bind yourself strongly to that base class. There's no relationship stronger than inheritance.
So by deriving from someone else's base class, you're making a huge commitment to them.
But they, on the other hand, are not making any kind of commitment to you.
So it's an asymmetrical relationship.
The framework author gets the benefit of your commitment. But the framework author makes no commitment to you at all.
I leave you to make that comparison to yourself.
A wise architect does not make that binding.
A wise architect looks at the framework cynically. Looks at and says that framework ought to screw me.
That framework wants me to bind to it. And I don't think I'm going to.
I think I'm gonna put boundaries between my business rules and that frameworks.
So that my business rules are not forever tied to Hibernate or Spring. God know what.
I'll use the framework. And I'll use the framework carefully.
Because the author of the framework does not have my best interest at heart.
Long ago, my son and I and several other people wrote a tool called Fitnesse.
Is anybody use Fitnesse? Oh bunch of you, good.
Fitnesse is a tool for writing customer acceptance test.
It's based on a Wiki and that's really all you need to know it's based on a Wiki.
Who invented Wiki?
Ward Cunningham. Who's Ward Cunningham?
Guy invented Wiki. Ah~ He's a lot more than that.
Ward Cunningham is one of those Gurus of Gurus. All the Gurus know who Ward Cunningham is.
All the guys who go around speaking at conferences, like me, we all know who Ward Cunningham is.
And we review him from on high.
He was the guy made phone call to Eric Gamma
Said "You know Eric, you gotta write a book called design patterns."
This is the guy mentored Ken Beck. Taught him things like Pair Programming and Test Driven Development and Agile Development.
Ward Cunningham is a one of those guys, if you know a lot about the history of software. You think "Wow he had his hands in everything!"
Fitnesse is based on two inventions of Ward, the Wiki and Fit.
I'm not going to describe Fit. I'll describe Wiki however.
My son and I and bunch of other folks decided to write this in Java about 12 years ago. 13 years ago something like that.
We knew we wanted make a Wiki.
And so we thought "Well we got a place to store the pages, let's store them in a database and what database would that be?"
Well back in those days the only opensource database was MySQL. So we decided put everything in MySQL.
And we were about to go fire up MySQL and start building a schema and somebody said.
"You know we don't really have to do that. Right yet"
"I mean we will later but not right now because we can get away right now with another problem"
And that problem was translating Wiki text to HTML. That's what Wiki does.
Takes the funny text you typed into the Wiki and turns it into HTML.
And there was a lot of that translation that we needed to do.
So about 3 month we just forgot about the database altogether.
And we translated Wiki text to HTML. We needed an object for this which we called WikiPage.
You can see it here.
We created an abstract class named WikiPage and we implemented it with something called MockWikiPage.
The methods of WikiPage had database like funtions such as Load and Save.
But they were unimplemented. The didn't do anything.
And for about three months we worked that way.
Once we had all the translation done. Then we said "Well it's time to fire up the database."
"Cause now we need to actually store these pages somewhere"
And somebody said "Well, we don't need to do that yet."
"Because what we could do instead is take this pages and store them in a hash tables in RAM."
"I mean we don't really need to store them on disk yet, do we?"
The answer to that was no. Cause all we were doing was writing unit test anyway.
So we decided to create a another version of the Wiki page called the InMemoryPage which stored all the data in hash tables.
And we continued to work for a year.
Continuing to write more and more Fitnesse keeping all the data in memory.
We actually got all of Fitnesse working.
Without ever putting it into a disk.
And it was very cool because all the test went really fast. No database.
On the other hand it was frustrating because we would created a bunch of tests and shut the computer down and then all be gone.
So it's some point we finally said "Well now it's the time for database, let's fire up MySQL."
And Michael Feathers was there at that time.
And Michael said "Well you don't really have to fire up MySQL yet."
"All you really need is persistence. And you can get that persistency really cheaply by taking the hash tables to be written into flat files."
And we thought that's kind of ugly but it'll work for the time being. And then later on we'll switch it all over MySQL. So we did that.
And for another 3 months we continued to develop more and more about Fitnesse.
And that was kind of cool. Cause we could take on the road. We could show it to people. We could save pages.
Started work like real Wiki.
About 3 months after that we said "We don't need that database"
"It's working fine! Flat files are fast enough."
"Works okay, that way."
We took that highly significant architectural decision and pushed it off to the end of planet.
We never put that database in. That's not quite true actually. Somebody else did.
A customer of ours came along little latter and said "I gotta have the data in database."
We said "But why? It's working fine in the flat file"
He said "Corporate policy, all corporate assets must be in a database."
I don't know who they'd been talking to. But these database salesman were pretty convincing.
So, we said "Well Look. If you really needed it in a database."
"Here's this structure all you have to do is create a new derivative called MySQL page. And everything ought to work fine."
And he came back a day latter and the whole thing running MySQL.
We used to ship that as a plug-in but nobody ever used it so we stopped.
Here's an architectural decision that we deferred and deferred and delayed and delayed.
We delayed right up to the end of project. Ne never did it.
Something that we thought we had to do it first, we never did it.
That leads to the final principle.
A good architecture is an architecture that allows major decisions to be delayed! Deferred!
The goal of an architect is to not make decisions.
To delay those decisions as long as possible so that you have the most information with which to make them.
You structure design and the high level structure of your code so that all these high level decisions can be pushed off.
Don't tell me that the architecture of your application is a bunch of frameworks.
"What's the architecture of your application? Yeah, we're using a SQL server and MVVM and blah.. "
You're not telling me anything.
You're telling me the tools.
That's not the architecture of your application.
The architecture of your applications are the usecases.
And you want your usecases to not know about those tools.
You wanna be able to defer the use of those tools for as long as possible.
You should be able to have the whole application running without ever firing up a database, without ever firing up the web.
Or maybe you fire up some gunky little web thing that you can toast together in a day or two.
Just so that you can see some pages without firing up some gigantic framework.
Maybe you fire up some dumb little database thing just so that you can see some persistence running.
Without ever having a license of Oracle and all the nonsense you have to go through to get that running.
Next time you have a application to write, think about what you can delay.
The application of a system should a plug-in architecture. The architecture of a system should be a plug-in architecture.
Well all of the details like the UI, the databse, the frameworks plug in to the usecases.
Which are the real core of your application.
Now of course, customers are gonna wanna see web pages.
Okay, you can stil make a plug-in architecture and show them web pages running.
You don't have to make a lot of commitments to the frameworks.
You don't have to make a lot of commitments to the web framework.
You can probably put something simple up it first.
Or if you want actually use a real framework, fine go ahead. But maintain the plug-in structure.
So that at a moment's notice you can unplug it and plug something else in.
And that probably brings to me the end of my talk.
I already talked about that earlier. (TDD)
So thank you all very much. are there any questions?
Very difficult to see, so I'm gonna come down here.
Oh that doesn't help at all.
Okay, anybody have any questions?
You gonna have to like hollow. Because I won't be able to see your hands up.
Yep.
(Someone is asking a question)
So I'm speculating the demise of Oracle and relational databases. What do I suggest to will replace them?
What an interesting question!
It could be nothing more than RAM. Why do you need anything to replace them?
If you gonna organize the data in RAM and if that RAM is persistent, what else do you need?
Oh but let's say you need something.
Okay what might it look like?
Well, who's heard of the CQRS?
Oh yeah, few of you.
CQRS, what an interesting idea?
If we have infinite amount of high speed memory. High speed RAM.
Or maybe it's even disk but who cares.
Why would we store the state of anything.
Why wouldn't we simply store the transactions?
Instead of storing a bank account, Why wouldn't we store the transactions that caused us to create the bank account.
The transactions that forced us to change the name in the bank account or the address of the bank account or the balance in the bank account.
Why wouldn't we store the transactions and reconstruct the state.
And you say to yourself "Well it will take a lot of time"
Yeah, but we've lots of processing power.
We can do that now, we have almost infinite amount of processing power and almost infinite amount RAM.
Why wouldn't we store just the events?
And I think that's an interesting idea.
If we store just events, then we would never delete anything.
We would never update anything.
You know CRUD? Create. Read. Update. Delete?
We'd loose the last 2 letters there. All our applications would be CR.
Create and Read. We would never update. We would never delete.
And when you don't update and you don't delete you don't need transactions.
There can't be any concurrent update problems if you're not updating.
That's interesting!
Are there frameworks out there that allow you to do things like that? There are.
There are number of them out there.
That are write only databases. Write once and read many times.
You can find them on the web. I'm not gonna tell you the names right now.
But you can go out there and look for them. There are out there.
You might replace them something like that.
You might replace them with Couch or Mongo. Or you might create some other thing.
It really doesn't matter. You don't have to have some massive vendor offering.
From some gigantic company in the sky.
That blesses you and says "Yes son, you may use my database system."
Maybe you can just make your own. Not that hard.
Anybody else?
Yeah, that actually helps a lot.
Okay, anybody else with questions?
(Someone is asking a question)
Differing decisions does not work very well when..
When you have a family? (People laughing)
You mean in general. There are decisions you can differ.
For example, what language we gonna write this thing in?
You gonna have to make that decision pretty early.
Right? Cause you know you gotta write some.
The fact that you're going to have a database, probably something you gonna have to make a decision on pretty early.
The fact that it's gonna be a web application, well you probably have to make that fairly early.
You have to commit to framework. No.
A family vacation that's what you were saying here.
We could plan out where we were going. Would we have to also plan out which car we would use?
If we're planning a six month in advance, we might decide buy whole new car just for the heck of it?
Maybe our car break down in the middle. Or before we go on the vacation.
The car itself is just a vehicle, it doesn't matter as long as our luggage fits in it. And our family.
We can still go on the vacation.
The database system is like the car. We don't need to make that decision as part of vacation plan.
That one can be differed to the last minute.
You could buy a new car the last minute, the day before you decide to go on vacation.
And why would you do that?
You might have gotten a race. You might have more money.
You might have a baby. Need more space.
A lot of reason you might wanna buy that car at the last minute.
Anybody else?
Yeah, way back there.
(Someone is asking question)
How do you deal with legacy architecture?
Okay, that's gonna take me more than a minute.
So I'm gonna use one word to answer that question and I'll explain that word.
Incrementalism.
Everybody faced with legacy code wants to throw it away and write it over.
Please don't do this.
They generally fails, Horribly you'll spend tremendous amount of money and waste a load of time.
Take little bits of it.
And rewrite those tiny little bits one at a time.
And get them working one little bit at a time.
That will leave you with a patch work. But the patch work will be cleaner than the original.
And then start over and start re-implementing the patch work.
Gradually cleaning it making it better and better. It'll take you long time, a lot of effort.
You wanna do that while you also adding new features.
In fact, that's just generally cleaning your code.
Please don't try the big re-design. You'll get hurt.
Thank you all for your attention. I'll see you another time.
(4분45초에 시작. 실제 강연과 한글 자막은 11:05에 시작)
뒤에 잘 들리나요?
저 뒤에도 잘 들리나요? 오케이 좋습니다.
Um what is an electron?
So part of atom, everybody knows that, I think
It's um.. (Screams from other room) yeah I think so, . I think that's royal ???
Um electron is part of atom
it's carries a unit of electronic charge, negative charge, as oppose to a proton which carries a positive charge
It apparently has ??? not very much, thousands of electron... very very small amount of mass
And we think of it as a particle, although that misleading um.. electron actually behaves much more like a wave than like a particle
why do we think of it as particle?
and the reason we do that is that when electron interacts a location like a particle would
when electron is moving through the space it does not moves the way a particle would
moves as a wave and the wave has no location
you look at an ocean wave, and ocean wave can be huge
it has no distinct location it has well defined energy but no distinct location
this is how an electron moves
electrons obey a principle and it's a mistruster principle
It's called the poly exclusion principle
two electrons bound into the same system will not be in the same state
for whatever reason they cannot be in the same state
so if there are two electrons in an atom
those two electrons must be different somehow
now they might different in the direction of their spin
an electron can spin to the left or spin to the right
two electrons that have exactly same energy could fit together spinning one left and one right
there's no way to get a third one in there
so the next electron must have higher energy and then you can have two more
one spinning left one spinning right
but if you wanted to add another that would have to be something different about them
and you could arrange them differently in space
so you could have one group of two this way and another group of two this way and another group of two this way and one group of two in a sphere and that adds up the eight by the way.
most of our atoms that we know of have this need to have 8 electrons in their shells
The reason for that is just this nice little geometry. the sphere and then three rows and each one of those can contain two
have you ever thought about water?
I got some here. Fascinating substance
what's it made of?
two hydrogen atoms one oxygen atom
that's what makes a water molecule
and what's it shaped like?
Mickey mouse! yes, there is big oxygen in the middle and two little hydrogens forming the ears
The angle there is the result of (??) the shell arrangement.
What makes the hydrogen and oxygen stick together?
think of two atoms, two atoms covered by electrons, two electrons are parallel each other
what would make two hydrogens and an oxygen stick together?
And it turns out that if you take these two hydrogens and big oxygen you lay them next to each other
and you think of the electrons as waves, not particles, then where those waves like to be?
and those waves would like to be mostly between protons. Protons in hydrogen atom and protons in oxygen atom
So they will congregate those electron waves will congregate more
between two atoms, between three atoms actually, then everywhere else
they still go everywhere else that just that more likely to be between them
that means there's little extra negative charge between the atoms and that little extra negative charge to tracks the protons and that's covalent bonds
now if you take this Mickey mouse atom and you divide it in half
you find there's more negative charge above the one and below the one
cause all that negative charge likes to sit there between the two hydrogen atoms and oxygen atoms
So there's more negative charge on one side than the other which means that water molecule is a dipole
it is negative one side and positive on the other
this is why water is wet.
Water sticks to your hand because all the water molecules rotate to stick to the electrically charged surface of your skin
even though it is not very electrically charged
this is why water makes it good solvent because the little water molecules would rotate to attract to the parts of the other molecule that they want want to stick to
this is why water makes it a good cleanser
and this is why water will do one of the most wonderful things you can do with water. Who's done this experiment?
You get a water faucet. You turn it on just so you get a really thin stream of water. Not very fast, just tiny stream of water
And then you get a balloon and you rub the balloon on your head. And then you hold the balloon close to that stream of water and watch the water bend towards the balloon
as all the water molecules turn around get it tracked the electric charge
물론 오늘의 발표 주제는 이게 아니지요.
오늘 이야기할 주제는 "아키텍처, 잃어 버린 시간" 입니다. 지난 몇 년 동안 강연해왔던 주제인데요.
클린 코드와 클린 디자인의 다음 단계에 대한 이야기입니다.
클린 시스템 스트럭쳐에 대한 이야기 입니다.
화면을 보세요.
이 그림은 내가 10년 전에 작성했던 어플리케이션의 디렉터리 구조입니다.
당시에 Rails를 배우고 있었지요. 여기 Ruby 프로그래머가 있나요? Ruby on Rails 프로그래머?
저쪽에 손 흔드는 사람이 한 명 있네요. 오케이.
당시에 Rails를 배우면서 이 어플리케이션을 작성했지요.
책의 내용을 그대로 따라 작성했습니다.
책에서 이야기하는 데로 그대로 작성했더니 이런 형태의 결과가 나왔습니다.
만족스럽게 마무리했고 그뒤로 오랫동안 보지 않았지요.
그리고 한 3년 전에 아들에게 어플리케이션을 하나 작성해달라고 했습니다.
작성된 어플리케이션을 봤더니
디렉터리 구조가 똑같았어요.
이 둘은 전혀 다른 어플리케이션이고 아무런 연관도 없습니다.
그런데 디렉터리 구조는 똑같아요. 이걸 보면서
왜 두 어플리케이션의 최상위 구조가 같은지에 대해서 고민했습니다.
이 둘은 전혀 다른 어플리케이션이거든요.
두 어플리케이션의 디렉터리 구조가 동일한 이유는 둘 다 Rails 어플리케이션이기 때문이었습니다.
그러자 이게 왜 중요한지가 궁금해졌습니다.
Rails 같은 프레임워크가 얼마나 중요하길래 어플리케이션의 최상위 디렉터리로 구조를 결정지어버리는 걸 까요?
내가 생각한 이유는 바로 다음과 같습니다.
웹은 전달을 위한 장치입니다. 웹은 I/O 채널이에요.
웹 자체는 아키텍처적으로 중요하지 않습니다.
흔히 웹 어플리케이션을 작성한다고 이야기합니다.
하지만 그렇지 않습니다.
우리는 어플리케이션을 작성하고 있는 것 입니다. 단지 어플리케이션이 웹 이라고 하는 I/O 채널을 통해 콘텐트를 전달하는 것뿐이지요.
그러면 왜 I/O 채널이 그렇게 중요할까요?
혹시 웹이 번성하기 시작한 시기를 기억하나요? 1980년대? 1990년대?
얼마나 큰 변화였는지 기억하나요? 얼마나 모든 것이 근본적으로 변했는지 기억하나요?
그다지 큰 변화는 없었습니다. 왜냐하면 실제로 크게 달라진 것이 없었기 때문이지요.
우리는 단지 입력 소스로부터 입력을 받고, 처리하고, 출력 소스로 내보내기만 했습니다.
웹은 그냥 그런 거에요.
그런데 왜 웹이 모든 것들을 결정해버릴까요?
그래서 나는 건축에 대해서 생각해봤습니다. 건축 도면을 봤어요.
저 도면을 보세요. 저 위에 도서관이라는 글씨가 없더라도 깨닫는데 얼마 걸리지 않을 겁니다.
도서관이라는게 너무 명백하거든요.
책장들이 많이 있고 책상도 많습니다.
책상위에 컴퓨터도 보이고요 책을 대출하고 반납하는 곳도 보여요.
저 도면을 보고 도서관이라는 것을 알아채는 데에 오랜 시간이 걸리지 않을 겁니다.
다른 것도 봐볼까요? 저건 교회에요. 누가 봐도 교회지요.
어쩌면 극장이라고 생각할 수 도 있겠지요. 극장이랑 교회는 공통 부분이 있으니까요.
하지만 이건 분명히 교회입니다. 제단, 바깥의 교실,
분명히 교회지요.
이 건물의 아키텍처는 어떻게 지을 수 있는지 말하지 않습니다. 이 건물의 아키텍처는 그 의도를 말하고 있습니다.
아키텍처는 의도를 표현하는 것 입니다.
하지만 저 Rails 어플리케이션들의 최상위 구조는 그 의도가 보이지 않습니다.
단지 Rails 어플리케이션이라고 말하고 있지요. 무언가 잘못되었어요.
그리고 이런 생각이 들었습니다.
이건 이미 알려진 문제인가? 이미 해결되었던 문제인가? 이 문제는 1992년에 이바 야콥슨이 저술한 책에서 거론되고 해결되었었습니다.
이 책을 가진 사람이 있나요? 읽어 본 사람? 여기 한 사람있네요 또 없나요?
Object-Oriented Software Engineering. 아주 훌륭한 책이에요.
1992년에 출반된 책이지만 상관없어요. 책에 담긴 원칙들은 여전히 유효합니다.
부제를 보세요. 부제는 'A Usecase driven approach' 입니다.
유즈케이스 기억하는 사람 있나요? 1990년대에는 아주 아주 유명했었습니다.
사실 너무 유명해서 수많은 컨설턴트들이 본래의 의미를 변질시켰지요.
기억하나요? 수많은 컨설턴트들이 자신의 유즈케이스 양식을 앞다투어 인터넷에 올렸었지요.
결국 양식만 중요하게 되어 버렸어요. 표준 양식의 빈칸을 채우도록 강요 받았지요.
유즈케이스의 이름, 입력값, 사전조건, 사후조건, 주액터, 부액터 등을 채워야 했습니다.
.
우리는 모든 빈칸을 채워야만 했고 결국 유자케이스의 가장 중요한 점은 그 기능이 아니라 양식이 되버렸습니다.
그 즈음에 에자일 운동이 시작되었습니다.
우리는 유즈케이스에 대한 이야기는 멈추고 유저 스토리에 대해 이야기했습니다. 유즈케이스에 대해서는 아무도 이야기하지 않게 되었지요.
그래서 나는 이 책을 다시 읽어봤어요.
야콥슨이 쓴 것들을 다시 기억해냈습니다.
여기 유즈케이스가 있습니다. 전형적인 야콥슨 스타일의 유즈케이스에요.
보다시피 매우 작은 양식이에요.
'주문 생성'이라는 이름이 있네요. 주문 처리 시스템의 유즈케이스라고 생각해보세요.
입력 값으로 고객 아이디, 고객 연락처, 수신처 등이 보이네요.
여기에는 세부적인 내용은 없어요. 고객 아이디가 어떤 것인지 기술하지 않습니다.
숫자이건 문자열이건 상관없어요.
고객 연락처가 어떤 것인지 기술하지 않습니다. 아마도 이름 날자 주소 등등 이겠지요.
하지만 세부사항들은 여기에 명시되어있지 않습니다.
여기 메인 흐름이 있네요.
메인 흐름은 유즈케이스를 만족시키기 위해 컴퓨터가 실행하는 단계들이에요.
첫 번째로 주문 담당자는 '주문 생성'을 요청합니다.
그리고 시스템이 데이터를 검증합니다. 어떻게 검증한다는 이야기는 안 했지요? 어떻게든 검증을 하는지는 중요하지 않습니다. 그냥 검증을 한다는 게 중요합니다.
세번째로 시스템이 주문을 생성하고 ID를 결정합니다.
아마도 어떤 데이터베이스 작업이겠지만 이야기는 안 하겠습니다.
그리고 시스템은 담당자에게 ID를 전달합니다. 아마도 웹 페이지를 통해서겠지만 이야기는 안 하겠습니다.
실제로 이 유즈케이스는 웹에 대해 아무런 이야기도 하지 않습니다.
이 유즈케이스는 어떤 I/O 채널을 통해서도 구현이 가능하겠지요.
이 유즈케이스는 콘솔 앱, 데스크탑 앱, SOA 앱, 아이폰 앱에서도 구현이 가능합니다.
유즈케이스는 I/O 채널을 모르기 때문에 가능한 것 입니다.
야콥슨은 유즈케이스를 오브젝트로 바꿀 수 있다고 했습니다.
야콥슨은 저것을 Control Object라고 불렀지만 MVC의 Controller와 헷갈릴 수 있으므로 Interactor라고 이름을 바꿨습니다.
어쩌면 유즈케이스라는 이름이 더 좋겠지만 그렇게 하지는 않았습니다. Interactor로 부르겠습니다.
Interactor 오브젝트는 유즈케이스를 구현합니다. 유즈케이스의 입력값을 입력 받아서 유즈케이스의 출력 값을 출력합니다.
그리고 유즈케이스의 처리 흐름을 구현합니다.
밑에 설명을 보면 어플리케이션 별 비즈니스 규칙들을 가진다고 되어있지요?
거기에는 두 종류의 비즈니스 규칙이 있습니다.
먼저 글로벌 한 비즈니스 규칙이 있습니다. 모든 어플리케이션에 적용이 가능하지요.
그리고 개발중인 어플리케이션에만 해당하는 비즈니스 규칙들이 있습니다.
예를 들어서 주문 입력 어플리케이션과 주문 처리 어플리케이션이 있다고 생각해봅시다.
둘 다 '주문'이라는 오브젝트가 있을 겁니다. 그리고 그 주문 오브젝트들은 같은 비즈니스 규칙을 가지고 있겠지요.
하지만 둘 중 하나의 어플리케이션만 주문 추가라는 유즈케이스를 가지고 있을 겁니다.
유즈케이스는 어플리케이션에 따라 다릅니다. 유즈케이스는 특정 어플리케이션에 종속되지요.
비즈니스 규칙은 어플리케이션에 따라 다르지 않습니다. 엔티티 오브젝트에 종속됩니다. 비즈니스 오브젝트라고도 이야기 하지요.
나는 비즈니스 오브젝트라는 말은 좋아하지는 않습니다. 야콥슨도 엔티티 오브젝트라고 불렀지요.
어플리케이션 비종속적인 비즈니스 규칙들을 엔티티 오브젝트에 넣고 Interactor가 엔티티 오브젝트들을 관장합니다.
그리고 입력값과 출력값을 다른 유즈케이스에 전달하는 방법을 정합니다.
이 경우 인터페이스를 사용합니다. 객체지향 방식의 인터페이스로 표현을 했는데요.
Interactor는 인터페이스 중 하나는 사용하고 있고 다른 하나는 구현을 하고 있습니다.
Interactor가 구현하고 있는 것은 입력 인터페이스이고요 Interactor가 사용하고 있는 것은 출력 인퍼테이스입니다.
두 인터페이스와 Interactor 사이의 화살표가 같은 방향이지요? 아주 중요한 포인트입니다!!!!!
이게 왜 중요한지는 조금 뒤에 이야기하겠습니다.
야콥슨은 이 세가지를 어플리케이션 아키텍처의 일부로 이야기했습니다.
자 그럼 이것들이 어떻게 작용하는지 봅시다.
평범한 어플리케이션이 있습니다. 저기 작은 사람이 유저입니다.
이 사람이 어떤 전달 매커니즘을 통해서 시스템과 상호작용합니다.
전달 매커니즘은 웹일 수도 아닐 수도 있겠지요. 아무런 상관 없습니다.
저 유저는 버튼이나 키보드를 사용해서 시스템이 데이터를 받아들이도록 합니다.
어떤 전달 메커니즘을 통하는지는 전혀 중요하지 않습니다.
시스템에 전달된 데이터는 Request Model이라는 것으로 변형됩니다.
Request Model은 순수한 데이터 구조입니다.
POJO나 POCO와 같은 순수 데이터 구조 입니다. 데이터가 어디에서 왔는지 모르고 웹과 아무런 연관도 없습니다.
메소드도 없는 단순한 데이터 구조입니다.
Public 데이터만 있는 구조로서 모든 입력 값을 저장하게 됩니다.
Request Model은 입력 인터페이스를 통해 Interactor에게 전달됩니다.
Interactor는 Request Model를 읽어 해석하고
작은 여러 커맨드들로 변환하여 엔티티에 보냅니다.
모든 비즈니스 오브젝트들은 엔티티로 호출되는 메소드들을 컨트롤합니다.
작업이 끝나면 반대 방향으로 진행됩니다. Interactor는 엔티티를 조회하여 변경사항을 확인합니다.
그 결과로 Result Model이라는 또다른 데이터 구조를 만들게됩니다.
Result Model도 역시 순수한 데이터 구조입니다. 단순한 POJO나 POCO이지요.
Result Model은 출력 인터페이스를 통해서 전달 매커니즘으로 전해집니다. 출력 인터페이스를 통해 어떻게던 유저에게 전달이 됩니다.
어플리케이션의 일반적인 처리 과정입니다.
그럼 Interactor를 테스트할 수 있을까요?
매우 쉽겠지요?
입력 데이터 자료를 생성해서 Interactor를 호출하고 출력 데이터를 보면됩니다.
테스트를 위해 웹 서버가 필요할까요?
아닙니다. Interactor는 단순히 POJO나 POCO만을 사용하기 때문이지요.
테스트를 위해 데이터베이스가 필요할까요? 어쩌면 필요할 수도 있겠지요 하지만 이 문제는 조금 있다가 이야기하겠습니다.
전달 메커니즘이 없어도 테스트가 가능합니다.
전달 매커니즘이 웹 인가요? 상관 없습니다. Interactor를 테스트하는데에 웹 서버는 실행할 필요가 없어요.
웹 페이지도 없이 테스트가 가능합니다.
처음 입력단 부터 마지막 출력단까지 확인하지 않아도 테스트가 가능합니다.
MVC에 대해 이야기 해볼까요?
MVC는 당연히 따라야 하는 거 아닌가요?
MVC는 무엇의 약자이지요? Model View Controller 입니다. 그럼 누가 발명했나요?
저 사람입니다. 난 저 사람의 이름을 제대로 발음할 줄 모릅니다. 여러분이 제대로 발음할겁니다.
트릭뷔 륀스카욱. 여러분은 정확히 발음하겠지요.
(역주: 트릭뷔 륀스카욱은 청중들과 마찬가지로 노르웨이 사람임.)
나는 저 사람을 만나봤습니다. 저 사람이 1970년대에 MVC를 발명한 사람입니다.
나는 2년 전에 여기에서 만나봤습니다.
그때 대기 라운지에서 전원 콘센트를 찾고 있었지요. 그때 어떤 나이든 사람이 다가와서 콘센트를 건네 줬습니다.
누군가 돌려 보니 "트릭뷔 린스카욱!"
멀티탭을 주고 받을 때에 손가락이 스쳤어요!
나는 한동안 손을 안씼었습니다. 트뤽뷔 린스카욱.
오늘 몇 사람이 내게 와서 사진을 찍었는데요, 나도 역시 비슷한 부류입니다.
70년대 말에서 80년대 초에 트뤽비 린스카욱은 Model View Controller라고 부르는 이 구조를 제시했습니다.
스몰토크 플랫폼 위에서 이걸 만들었지요.
기본 개념은 매우 간단합니다.
모델 오브젝트가 있습니다. 모델 오브젝트는 비즈니스 규칙을 담고 있지요.
모델 오브젝트는 자신이 어떻게 유저에게 보여질지 전혀 모릅니다. 입력 값이 어디에서 오는지도 몰라요.
단지 순수한 비즈니스 규칙입니다. 저기 아래에 있는 컨트롤러는 입력 값들을 처리합니다.
컨트롤러는 입력 기기들을 쳐다 봅니다. 어떤 입력 기기인지는 중요하지 않습니다. 사용자의 행동을 커맨드로 만들어 Model에게 전달합니다.
그리고 View가 있지요.
View에 쌍선으로 그려진 화살표가 있는데요. 옵저버 관계를 의미합니다.
View는 Model에 등록을 해놓습니다. 그리고 Model이 변하면 View는 이를 통지 받아 화면을 업데이트합니다.
View의 역할은 Model의 컨텐츠를 표시하거나 전달하는 것 입니다.
MVC는 GUI 환경에 아주 적합합니다. 그리고 콘솔, SOA 등에도 잘 적용될 수 있습니다.
일부는 입력을 전담하고 (Controller)
일부는 프로세스를 전담하고 (Model)
또 일부는 출력을 전담합니다. (View)
MVC는 최초로 이름을 가진 디자인 패턴일 텐데요 원래는 아주 작은 것들에 사용하는 게 목적이었습니다.
MVC는 버튼에 쓰일 수 있지요. MVC는 체크박스에도 쓰일 수 있습니다. 그리고 MVC는 텍스트 필드에도 쓰일 수 있습니다.
스크린에는 MVC가 쓰이지 않습니다.
아주 오래 전 부터 MVC는 비틀어지고 변형되어 왔습니다. 소프트웨어 분야에서 흔히 일어나는 일이지요.
무언가 매우 좋은 것이라고 여겨지면 다른 모든 사람들이 모방을 시작합니다. 그리곤 완전히 다른 것에 같은 이름을 붙이고는 그 역시 좋은 것이라고 주장합니다.
객체지향도 그랬고, 구조, 오브젝트 에자일 등도 마찬가지였습니다.
어떤 이름이 좋은 것을 의미한다면 다른 사람들이 그 이름을 자기 것에 붙이려고 합니다.
MVC도 마찬가지 입니다. 요즘 MVC 프레임워크들이 많이 있습니다.
그런 MVC 프레임워크들은 원래 MVC와는 전혀 다릅니다. 트릭뷔 린스카욱의 MVC와는 전혀 다른 개념의 것 입니다.
아주 많이 달라요. 보통 이렇게 생겼지요.
저기 많은 컨트롤러들이 있지요. 웹 환경에서는 저 컨트롤러들은 웹에 의해 작동됩니다.
저 구름 너머에 있는 웹 프레임워크지요. Rails 일지 Spring일지 어떤 것이든지 상관없어요.
그 복잡하고 끔찍한 URL을 어떻게인가 전달해서 컨트롤러에 전달합니다.
웹으로부터 받은 파라메터와 데이터를 컨트롤러에게 전달합니다.
그러면 컨트롤러들은 비즈니스 오브젝트들에게 일을 하라고 소리를 칩니다.
그리고 비즈니스 오브젝트에서 데이터를 모아서 뷰에게 이야기합니다. 그러면 뷰들은 다시 비즈니스 오브젝트들에게서 데이터들을 조회하고 화면에 표시합니다.
결국 비즈니스 오브젝트에는 컨트롤러나 뷰에나 있을 법한 펑션들로 채워지면서 오염되어 버립니다.
펑션의 적절한 위치를 찾기가 어려워서 비즈니스 오브젝트에 구현하면 안 되는 것 들을 구현해 넣기도 합니다.
그럼 출력은 어떻게 처리할까요?
여기 Interactor는 일을 끝냈습니다.
유즈케이스를 끝내면서 데이터를 조회했지요. 조회된 Response Model을 출력 인터페이스를 통해 전달하려는 시점입니다.
저 출력 인터페이스를 구현하는 것은 무엇 일까요? Presenter라 불리우는 것 입니다.
Presenter의 역할은 순수 데이터 구조인 Response Model을 받아서
View Model이라는 또다른 데이터 구조로 변형시킵니다.
View Model은 출력 값을 표현하는 순수한 데이터 구조입니다.
하지만 만약에 화면에 표가 있다면 View Model에도 표가 있을 겁니다.
만약에 화면에 텍스트 필드가 보인다면 View Model에도 텍스트 필드가 있을겁니다.
화면의 숫자를 소수점 이하 두 자리 까지만 표현하겠다면 ViewModel은 TrimToTwoDecimalPlaces와 ConvertIntToString라는 메소드를 가지게됩니다.
음수를 괄호로 표현하고 있다면 Presenter가 데이터에 괄호를 붙여서 View Model에 저장을 한 것 입니다.
메뉴 아이템들이 있다면 그 이름들도 View Model에 저장이 됩니다.
비활성화된 메뉴 아이템은 회색으로 보여져야 한다면 View Model에는 활성 상태를 저장하는 불린 값이 있을 겁니다.
화면에 표시되는 모든 것들은 View Model에 저장이 됩니다. 여전히 추상화된 방식으로요.
그리고 View에 입력이 됩니다.
View는 멍청해요. View는 저것들과 아무런 관련이 없고 단순히 View Model로 부터 데이터를 가져갑니다.
아무 것도 처리하지 않습니다. If 문도 없습니다. 아마 테이블을 표시하기 위한 루프문 정도는 있겠만 그 정도가 전부 입니다.
View는 아주 멍청해서 신경 쓸 이유가 없습니다. 일반적으로 테스트도 잘 안 하지요. 어찌되었건 우리 눈으로 보게 되니까요.
그럼 Presenter를 테스트 할 수 있을까요?
할 수 있습니다. Request Model을 입력한 후에 결과로 나온 View Model을 체크하면 됩니다.
Presenter를 테스트 할 때에 웹 서버가 실행되어야 할까요?
아니지요. 웹 서버가 없어도 모두 테스트할 수 있습니다.
스프링 같은 컨테이너들을 실행할 필요도 없지요.
그런 것 들을 실행하는 방법을 몰라도 됩니다.
그냥 평범한 데이터 구조체를 테스트하는 것처럼 모두 테스트 할 수 있습니다.
그나저나 이게 목표입니다. 다른 아무것도 실행하지 않고 가능한 많은 테스트를 하는 것 입니다.
30초에서 1분씩이나 써가면서 이것 저것들을 구동하지 않아도 됩니다.
다른 것들 없이 테스트만 실행할 수 있으면 됩니다. 다른 거 없이 가능한 빠르게 착착착 끝내면 됩니다.
저게 전체 그림입니다.
Interactor는 입력 인터페이스로 들어온 Request Model에서 데이터를 읽습니다.
그리고 Response Model에 데이터를 저장하고 출력 인터페이스를 통해 Presenter에게 전달합니다.
저기 검정색 선을 보세요. 저 선이 어플리케이션과 전달 매커니즘을 구분하는 선입니다.
그리고 검정선을 지나는 모든 화살표가 어플리케이션을 향하는 것을 보세요.
따라서 어플리케이션은 Controller나 Presenter에 대해 아무것도 모릅니다.
어플리케이션은 웹이나 I/O 채널에 대해 아무 것도 모릅니다.
I/O 채널은 어플리케이션을 알고 있지만 어플리케이션은 I/O 채널에 대해 모르고 있습니다.
만약에 저 둘을 서로 다른 Jar 파일에 담는다면 어플리케이션 Jar 파일은 웹 Jar 파일에 의존하지 않게됩니다.
저 둘을 다른 Jar 파일에 담는 게 바람직하겠지요. 하나는 웹에 대한 Jar 파일이고 하나는 어플리케이션이 담긴 Jar 파일입니다.
그리고 어쩌면 또 다른 I/O 매커니즘에 대한 Jar 파일을 만들 수도 있겠지요.
그리고 I/O 매커니즘을 변경하려면 그냥 Jar 파일만 바꿔치면 됩니다.
웹이라는 I/O 매커니즘을 플러그인이라고 생각하세요. 여기 .Net Sharp 사용자가 있나요?
여기 모두 .Net 개발자 아닌가요?
어떤 IDE를 사용하지요? IDE용 플러그인을 사용하나요?
IDE 개발자와 플러그인 개발자 중에 상대방에 대해 아는 사람은 누구일까요?
플러그인 개발자가 IDE 개발자를 알지요. IDE 개발자는 플러그인 개발자에 대해서 아무것도 모릅니다.
상관 안 합니다.
둘 중에 누가 상대방에 피해를 줄 수 있을까요? 플러그인 개발자들이 비주얼 스튜디오를 해칠 수 있을까요?
여기 Resharper 쓰는 사람? Resharper 제작자들이 비주얼 스튜디오를 해칠 수 있을까요?
- (청중) 예!
- (로버트 마틴) 아마 실행 중에 죽일 수는 있겠지요.
하지만 그렇다고 비주얼 스튜디오 개발자들이 대응을 해야 할까요?
MS의 개발자들이 JetBrains에게 신경 쓸까요?
아니지요! 그들은 JetBrains는 신경쓰지 않습니다.
그럼 MS의 개발자들이 JetBrains의 개발자들이 자신들을 따라오게 할 수 있을까요?
그렇지요!
그럼 여러분 어플리케이션에 대해 생각해봅시다.
어플리케이션의 어떤 파트가 어플리케이션의 다른 파트로부터 보호되어야 할까요?
어떤 파트가 어플리케이션의 다른 파트의 변경에 따라 수정되어야 할까요? 어떤 파트가 다른 파트의 변경에도 영향을 받지 않아야 할까요?
답은 아주 명확합니다.
비즈니스 규칙을 웹으로부터 보호해야 합니다.
그 반대는 안됩니다.
웹에 어떠한 변경이 생기더라도 비즈니스 규칙에는 영향이 없어야 합니다. 아키텍처적으로 보장되어야 합니다.
저기 모든 화살표가 어플리케이션을 향하고 있습니다. 명심하세요. 저게 플러그인 아키텍처입니다.
이제 데이터 베이스에 대해 이야기해봅시다.
저 그림 속의 데이터베이스가 당신이 생각하는 것과 비슷한가요?
데이터베이스가 세상의 중심이고 어플리케이션은 변방에 위치한 아랫것들 인가요?
여기 DBA 있나요?
아! 없군요 좋습니다.
혹시 이런 DBA와 일 해본 경험 있나요? 어플리케이션은 구석으로 밀쳐버리고, 스키마를 정해버리고, 데이터베이스만 우선시하는?
이게 여러분이 생각하는 데이터베이스인가요?
내 이야기의 요점은 이 것입니다.
데이터베이스는 디테일이에요.
아키텍처적으로 큰 의미가 없습니다.
데이터베이스는 그냥 데이터 저장소일 뿐입니다.
시스템에서 아키텍처적으로 중요한 것이 아닙니다.
비즈니스 규칙과도 아무런 연관이 없지요.
설마 Stored Procedure로 비즈니스 규칙을 구현했나요?
Stored Procedure에는 비즈니스 규칙 대신 쿼리, 검증, 무결성 검증 등이 들어가야 합니다.
그럼 왜 데이터베이스를 사용할까요?
데이터베이스는 왜 생겨났을까요? 오라클은 왜 존재할까요?
데이터베이스 이전에는 데이터를 어디에 저장했었을까요?
회전하는 디스크에 저장했었습니다. 여기 디스크 드라이버 개발해본 사람 있나요?
회전하는 디스크에 데이터를 입출력 하는 프로그램을 개발해본 사람 있나요?
없나요?
디스켓? 그것도 마찬가지지요.
데이터를 디스크에 저장하고 읽는 것은 매우 어렵습니다. 왜지요?
디스크에 데이터가 저장되는 방식 때문입니다.
데이터는 디스크의 원형 트랙에 저장됩니다.
플래터 표면에 원형의 트랙이 있습니다. 플래터는 여러 개가 있을 수 있지요.
헤드가 트랙을 찾기 위해 전/후로 움직입니다. 그러므로 원하는 트랙으로 헤드를 움직여야 하지요.
그리고 디스크가 회전하면서 데이터를 읽게 됩니다.
그 다음에 원하는 섹터를 찾아야 합니다. 트랙에는 50~60개의 섹터가 있고요 각각의 섹터는 4k 바이트의 데이터를 가지고 있습니다.
그러므로 디스크가 회전해서 원하는 섹터가 올 때까지 기다렸다가 데이터를 읽어야 합니다.
그리고 읽은 데이터에서 원하는 바이트를 찾아야 합니다.
어렵습니다. 그리고 느려요.
제대로 작성하지 않으면 아주 아주 오래 걸릴 수도 있습니다.
그래서 사람들은 이 문제를 전담할 시스템을 만들었습니다. 데이터베이스 말입니다.
그런데 상황이 변했습니다.
여기 내 노트북 보이나요? 내 노트북은 500GB짜리 SSD가 있습니다. 디스크는 없어요. 놀랍지는 않지요?
여기 디스크를 가진 사람 있나요?
여기 회전하는 디스크를 가진 사람?
이런! 진짜로요?
요즘 HDD를 사고싶은 사람은 없어요. SSD가 대세입니다.
어쩌면 서버 룸에는 HDD가 있을지도 모릅니다. 하지만 거기도 조만간 없어질 겁니다.
앞으로 몇 년 후에는 HDD는 사라질 겁니다. 모든 것이 RAM으로 교체되겠지요.
RAM 말입니다.
RAM은 원하는 바이트를 직접 읽을 수 있습니다.
무한한 용량을 가진 비휘발성 RAM이 우리가 추구하는 것 입니다.
가장 이상적인 저장 매체이지요.
그렇게 직접 액세스할 수 있는 저장 매체가 있다면 왜 SQL을 써야만 할까요?
SQL은 어렵습니다. Table도 어렵습니다.
해시 테이블에서 데이터를 검색하기 보다는 포인터로 바로 액세스하는 것이 좋겠지요?
지금도 그렇게 하고 있지 않나요? 테이블에 저장된 데이터를 읽은 후에 사용하기에 더 좋은 구조에 저장합니다.
그냥 우리가 사용하는 포맷 그대로 저장하면 어떨까요?
내가 오라클이라면 아주 겁이 날 겁니다.
존재의 이유가 서서히 사라지고 있거든요.
대규모 데이터베이스 시스템이란 개념은 점차 사라지고 있습니다.
그럼 어플리케이션을 이런 사소한 것으로 어떻게 보호할까요?
이런 사소한 데이터베이스가 모든 것을 결정해버리곤 합니다. 하지만 웹을 격리한 방법으로 어플리케이션을 데이터베이스로부터 보호할 수 있습니다.
자 여기 또 하나 굵은 선을 그립니다.
자세히 보세요, 이 선을 지나는 모든 선은 어플리케이션을 향하고 있습니다.
데이터베이스를 어플리케이션의 플러그인으로 만들었습니다.
이제 오라클을 MySQL로 바꿀 수 있습니다.
아니면 MySQL을 버리고 CouchDB로 바꿀 수도 있지요.
아니면 CouchDB를 버리고 Datomic이나 다른 걸로 바꿀 수 있습니다.
데이터베이스를 플러그인처럼 교체할 수 있습니다.
데이터베이스를 실제로 바꾸지 않을지도 몰라요. 하지만 그럴 수 있다는 것은 좋은 겁니다. 실제로 필요하지 않다고 해도 말입니다.
그럼 어떻게 하면될까요? 저 위에 인터페이스를 하나 더 두면 됩니다.
엔티티 게이트웨이라고 이름을 붙였습니다.
보통 엔티티 하나에 게이트웨이 하나를 둡니다. 엔티티 게이트웨이의 메소드들은 모두 쿼리 메소드들 입니다.
모든 쿼리문에 해당하는 메소드가 존재합니다.
엔티티 게이트웨이의 구현부는 저 선 아래에 위치합니다.
구현부는 아마도 데이터베이스를 사용하겠지요.
자세히보세요. 데이터베이스에 관한 어떤 부분도 어플리케이션에 노출되지 않습니다.
그럼 엔티티 오브젝트는 어디에서 올까요? 아마도 데이터베이스에서 읽어져 올라올 겁니다. 테이블에 어떤 모양으로 저장되어있건 말이지요.
엔티티 게이트웨이의 구현체는 그 데이터들을 읽어 모아 엔티티 오브젝트에 저장합니다.
그런 후에 저 선 위로 전달하는 거지요.
저 선을 넘어오면 어플리케이션에게 엔티티 오브젝트가 되는 겁니다.
여기 Hibernate 쓰는 사람 있나요? ORM 툴?
누구 쓰는 사람 있어요?
ORM 툴은 저 그림에서 어디에 있을까요?
구현부에 있습니다. 저 선 아래지요!
저 선 위에선 ORM 툴의 존재에 대해 아무것도 모릅니다.
혹시 비즈니스 오브젝트에 어노테이션이나 어트리뷰트가 붙어있나요? 없애 버리세요!
비즈니스 오브젝트들은 Hibernate 같은 툴과 직접적인 연관이 없어야 합니다.
저 선 아래의 것들은 데이터베이스 등에 오염된 사람이 개발하게 하세요.
비즈니스 오브젝트는 오염되지 않아야 합니다. 왜일까요?
오브젝트란 무엇인가요?
천천히 이야기해봅시다.
오브젝트란 무엇인가요? 오브젝트는 퍼블릭 메소드들의 집합입니다.
그 외에는 알려져선 안됩니다. 그렇지요?
그 안에 데이터가 있을지도 몰라요. 하지만 그걸 볼 수 있으면 안됩니다. 모두 비밀입니다.
여러분의 관점에서 오브젝트는 메소드 덩어리입니다. 데이터 덩어리가 아닙니다.
오브젝트는 메소드 덩어리입니다.
그러므로 오브젝트는 행위에 대한 내용입니다.
그러므로 오브젝트는 비즈니스 규칙에 대한 내용입니다.
데이터가 아닙니다.
아마도 안에 데이터가 있긴 하겠지요. 하지만 우리는 몰라요.
어떤 형태로 저장되는지 모릅니다. 알 필요도 없어요.
그럼 데이터 구조체는 무엇일까요?
(역주: Object와 Data Structure를 구분하여 사용하고 있음)
데이터 구조체는 잘 알려진 데이터 요소들입니다. 누구에게나 공개되지요.
(역주: Object와 Data Structure를 구분하여 사용하고 있음)
데이터 구조체에는 메소드가 없습니다.
데이터 구조체는 펑션이 없어요.
오브젝트와 데이터 구조체는 완전히 반대되는 것들입니다.
데이터 구조체는 공개된 데이터를 가지고 메소드가 없습니다.
오브젝트는 메소드를 가지지만 공개된 데이터가 없습니다.
정확하게 반대이지요.
ORM이란 말은 틀린 말입니다.
오브젝트와 관계데이터는 매칭할 수가 없어요.
데이터베이스에서 나온 것은 데이터 구조체입니다. 데이터 구조체는 오브젝트에 매칭할 수가 없는 것 이지요.
서로 완전히 다른 것이기 때문입니다.
엔티티에 저장되는 데이터는 어딘가에서 제공됩니다. 어딘지는 아무도 몰라요.
그리고 엔티티로 전달됩니다. 어떻게 전달되는지는 상관없어요.
그 엔티티 오브젝트들은 Hibernate가 생성한게 아닙니다.
아마도 엔티티 오브젝트들은 Hibernate가 만든 데이터 구조체들을 사용하고 있을지도 몰라요. 어떻게 하는지는 관심 없습니다.
저 검정선 아래의 Hibernate나 프레임워크에 대해선 아무 것도 몰라도 됩니다.
저 선 아래의 것들은 오염될 수도 있습니다.
저 선 위의 것들은 내 속살과 같이 소중한 것 입니다. 아주 소중하게 보호해야 하는 것 이지요.
저 위의 것들은 비즈니스 규칙들입니다. 나는 내 비즈니스 규칙들이 프레임워크로 오염되지 않게 할겁니다.
프레임워크. 사람들은 자신들이 사용하는 프레임워크를 좋아합니다. 아주 멋지지요.
프레임워크는 많은 시간을 절감해준다고 생각합니다. 실제로도 그렇습니다.
하지만 프레임워크 제작자는 우리를 프레임워크에 종속되도록 유도합니다.
그들은 베이스 클래스를 만들어서 우리가 그것들을 상속해서 사용하기를 바랍니다.
프레임워크의 베이스 클래스를 상속하는 순간 우리는 벗어나지를 못합니다.
그 베이스 클래스에 아주 강하게 엮이게 되는 거지요. 상속보다 더 강한 관계는 없습니다.
다른 사람의 베이스 클래스를 상속한다는 것은 아주 무거운 맹세를 하는 것과 같습니다.
반대로 프레임워크는 당신에게 아무런 맹세를 하지 않습니다.
비대칭적인 관계이지요.
프레임워크 제작자는 우리의 헌신으로 이익을 챙기지만 그들은 우리에게 어떤 책임도 지지 않습니다.
곰곰히 생각해보세요.
현명한 아키텍트는 저런 관계를 맺지않습니다.
현명한 아키텍트는 프레임워크를 비판적으로 바라봅니다. "저 프레임워크가 일을 어렵게 만들 수 있겠는 걸"
"어플리케이션을 프레임워크에 단단히 엮으려고 하는 걸. 그럴 순 없지."
"비즈니스 규칙과 프레임워크 사이에 경계를 만들어야겠어."
"그래야 비즈니스 규칙들이 Hibernate나 Spring 같은 것들에 영원히 묶이지 않게 말이야."
나는 프레임워크를 이용할 겁니다. 아주 조심스럽게요.
왜냐하면 프레임워크 제작자는 내가 가장 중요하게 생각하는 것이 무엇인지 모르기 때문입니다.
Fitnesse는 나와 아들 그리고 몇 몇 사람이 오래 전에 만들었습니다.
여기 Fitnesse 쓰는 사람이 있나요? 오 많군요 좋습니다.
Fitnesse는 인수테스트를 작성하는 툴입니다.
위키 기반으로 개발되었지요. 위키 기반이라는 것이 중요합니다.
누가 위키를 개발했지요?
워드 커닝햄. 워드 커닝햄은 어떤 사람인가요?
위키 개발자! 하~ 그 것 보다 더 많습니다.
워드 커닝햄은 구루들의 구루입니다. 모든 구루들은 워드 커닝햄이 누구인지 압니다.
나처럼 컨퍼런스에 연사로 초빙되는 사람들은 모두 워드 커닝햄에 대해 알고있습니다.
우리는 워드 커닝햄을 리뷰합니다.
그가 에릭 감마에게 전화 걸어 이야기 했지요
"이봐 에릭, 디자인 패턴이란 책을 써보는 게 어때?"
그는 캔트 백의 멘토이기도 했지요. 캔트 백에게 페어 프로그래밍, TDD, 에자일 개발 등을 가르쳤습니다.
당신이 소프트웨어의 역사를 유심히 본다면 아주 많은 곳에서 그의 흔적을 찾을 수 있을 겁니다.
Fitnesse는 Wiki와 Fit를 기반으로 개발되었습니다. 둘다 워드 커닝햄의 발명품이지요.
오늘은 Wiki에 대해서만 이야기하겠습니다.
우리들은 Fitnesse를 자바로 개발하기로 결정했습니다. 12년이나 13년 전에요.
우리는 위키 형태로 만들기로 했습니다.
우린 처음에 생각했습니다. "위키 페이지들을 저장할 공간이 필요하겠군, 데이터베이스에 저장합시다. 어떤 데이터베이스가 좋을까"
그때는 오픈소스 데이터베이스는 MySQL밖에 없었습니다. 그래서 MySQL을 사용하기로 했지요.
그래서 MySQL을 설치하고 데이터 스키마를 정하려고 할 때에 누군가 이야기했습니다.
"지금 당장 할 필요는 없지 않겠어?"
"그건 나중에 하고 일단 다른 문제들 부터 해결하는게 좋을 것 같아."
다른 문제들이란 위키 텍스트를 HTML로 변경하는 작업이었습니다. 위키의 기본 기능이지요.
위키에 입력한 텍스트들을 받아서 HTML로 변경하는 것 말입니다.
그런 변환 작업이 아주 많이 있었어요.
그래서 3개월 동안은 데이터베이스는 잊고 지냈습니다.
위키 텍스트를 HTML로 저장하기위해 우린 WikiPage라는 오브젝트를 만들었습니다.
저기 위에 있지요.
추상 클래스인 WikiPage는 MockWikiPage가 구현하고 있습니다.
WikiPage는 Load, Save 같은 펑션들을 가지고 있습니다.
하지만 실제 구현은 되어있지 않습니다. MockWikiPage의 Load/Save는 그냥 빈 껍데기입니다.
한 3달 동안 그렇게 작업했습니다.
모든 페이지 변환 코드가 끝난 후에 말했습니다. "자 이제 데이터베이스를 구동합시다."
"저 페이지들을 어딘가에는 저장해야만 해요"
누군가가 말했습니다. "글쎄 아직 데이터베이스는 없어도 될 것 같은데"
"대신에 변환된 페이지를 메모리에 저장하면 될 것 같아"
"아직은 디스크에 저장할 필요는 없지 않아?"
그럴 필요는 없었지요. 그때 단위테스트 작성하느라 바빴거든요.
그래서 우린 WikiPage를 구현하는 또 다른 클래스를 만들었습니다. InMemoryPage였지요. 우린 그 안의 해시테이블에 모든 것을 저장했습니다.
우린 그렇게 1년을 더 보냈습니다.
데이터를 메모리에 저장하면서 계속 개발 했습니다.
드디어 Fitnesse가 동작을 했습니다.
실제 디스크에 저장하지 않는 상태로요.
아주 좋았던 점은 테스트들이 매우 빠르게 실행된다는 거였습니다. 데이터 베이스가 없었거든요.
반면에 전원을 끄고나면 모든 것이 사라지는건 좀 불편했지요.
그러다가 누군가 말했습니다. "자 이제 데이터베이스를 구동할 시간이야. MySQL을 설치합시다."
마침 그때 마이클 페더스가 같이 있었는데요
마이클이 이야기 했습니다. "글쎄 아직은 MySQL이 없어도 되지 않겠어?"
"실제 필요한 것은 저장하는 거잖아. 그냥 해시 테이블의 내용을 파일에 저장하는게 훨씬 간단하지 않겠어?"
좀 옹색하지만 당분간은 괜찮아 보였습니다. 나중에 MySQL로 바꾸면되니까 일단 그렇게 했습니다.
그 뒤로 3개월간 계속 개발을 했습니다.
우린 들고 다니면서 사람들에게 보여줄 수 있어서 좋았습니다. 실제 저장도 되었고요.
진짜 위키처럼 동작을 했지요.
3개월 뒤에 누군가 이야기했습니다. "데이터베이스가 필요 없겠는걸."
"잘 동작하는데. 파일에 저장해도 충분히 빨라"
"이거면 충분한데."
우린 아키텍처적으로 매우 중요한 결정을 최대한 연기했고 결국엔 결정할 필요가 없게 되었습니다.
데이터베이스는 아예 넣지 않았습니다. 그런데 실제로는 다른 누군가가 추가하긴 했었지요.
고객 중 한 명이 와서 이야기 했습니다. "우린 데이터베이스가 필요합니다."
"왜요? 파일시스템으로도 잘 동작합니다."
그가 이야기했습니다. "회사 정책입니다. 모든 데이터는 데이터베이스에 저장되어야 합니다."
누가 그렇게 이야기했는지는 모르겠습니다. 아주 유능한 데이터베이스 영업 사원이 있었나봅니다.
그래서 이야기했습니다. "꼭 데이터베이스가 필요하다면"
"여기 WikiPage를 구현하는 MySQLPage를 만드세요. 그렇게만 하면 될겁니다."
바로 다음 날에 MySQL과 연동 작업은 끝났습니다.
MySQL 연동 기능을 플러그인으로 배포했었는데요 아무도 사용하지 않아서 이젠 배포하고 있지 않습니다.
우린 아키텍처에 대한 의사결정을 미루고 미루고 또 미뤘습니다.
프로젝트의 마지막까지 미뤘고 결국에는 하지를 않았습니다.
우리가 가장 먼저 결정해야 한다고 생각했던 것인데 결국엔 안했어요.
따라서 이런 원칙을 이야기할 수 있겠지요.
좋은 아키텍처는 중요한 의사결정을 뒤로 미룰 수 있게 합니다.
아키텍트의 목표는 결정을 안 하는 것이에요.
가능한 정보를 많이 가지고 결정 할 수 있게 미루고 미루는 것 이지요.
상위 레벨의 결정을 미룰 수 있도록 아키텍처나 코드 구조를 설계해야 합니다.
어플리케이션 아키텍처를 설명할 때에 프레임워크 이름을 말하지 마세요.
"어플리케이션의 아키텍처가 무엇입니까? 네 우린 SQL서버, MVVM, ..."
이건 아키텍처에 대한 설명이 아닙니다.
단지 사용하는 툴들을 나열하는 것뿐입니다.
그건 어플리케이션의 아키텍처가 아닙니다.
어플리케이션의 아키텍처는 유즈케이스들입니다.
유즈케이스는 툴에 대해 몰라야 합니다.
저런 툴에 대한 결정은 가능한 늦게 해야 합니다.
웹이나 데이터베이스 없이 어플리케이션의 모든 부분을 실행 할 수 있어야 합니다.
어쩌면 설치가 쉬운 작은 웹 프레임워크를 잠시 쓸 수는 있겠지요.
간단한 시연을 위해서요. 거대한 웹 프레임워크를 구동하지 않고도요.
어쩌면 아주 심플한 데이터베이스를 사용할 수도 있겠지요. 단순히 데이터가 저장되는 것을 확인하려고요.
오라클 등으로 저런 작업을 하려면 라이선스 비용처럼 이것 저것 복잡한게 많습니다.
다음에 어플리케이션을 개발할 때는 어떤 결정을 미룰 수 있는지 생각해보세요.
어플리케이션은 플러그인 구조이어야 합니다. 아키텍처는 플러그인 구조여야 합니다.
GUI, 데이터베이스, 프레임워크 같은 디테일들은 모두 유즈케이스의 플러그인이 되어야 합니다.
유즈케이스가 어플리케이션의 핵심이기 때문입니다.
물론 고객은 웹 페이지를 보고 싶어하지요.
플러그인 아키텍처로도 역시 고객에게 웹 페이지를 보여줄 수 있습니다.
프레임워크에 큰 헌신을 맹세할 필요가 없습니다.
웹 프레임워크에 막대한 헌신을 맹세할 필요가 없습니다.
처음엔 간단한 웹 프레임워크를 사용해서 보여주면 됩니다.
만약에 꼭 제대로 된 프레임워크를 사용하고 싶다면, 그렇게 하세요. 단 플러그인 구조는 유지하세요.
그래야 필요할 때 빠르게 대체할 수 있습니다.
이제 마지막 주제입니다. (TDD)
TDD는 이미 이야기했지요?
감사합니다. 질문 있습니까?
잘 안보이네요. 밑으로 내려가보겠습니다.
여전히 안보이군요.
자 질문 있습니까?
손드는게 안보이니까 크게 이야기해주세요.
예
(질문 중)
오라클 같은 관계형 데이터베이스의 종말을 예고했는데 그 다음은 어떤 것이 될 거라고 생각하냐고요?
아주 좋은 질문입니다.
그냥 RAM으로 충분할지도 모르지요. 왜 데이터베이스를 대체할 것이 필요할까요?
RAM에 데이터를 구성하고 RAM의 데이터가 비휘발성이라면, 더 필요한 게 있을까요?
하지만 더 필요한 게 있다고 가정하고 이야기해봅시다.
그 다음은 어떤 것 일까요?
여기 CQRS에 대해 들어본 사람 있나요?
조금 있군요.
CQRS는 참 흥미로운 아이디어입니다.
우리가 무한대의 고속 메모리를 가졌다고 생각해봅시다. 아주 빠른 RAM이요.
어쩌면 디스크일 수도 있겠지요.
상태 값을 저장할 이유가 있을까요?
그냥 트랜즈액션만 저장하면 되지 않을까요?
은행 계좌의 잔고를 저장하는 대신에 계좌를 생성한 트랜잭션을 저장하면 어떨까요?
은행 계좌의 이름, 주소, 잔고를 변경시키는 트랜잭션들이요.
왜 트랜잭션들을 저장한 후에 상태 값들을 재구성하면 어떨까요?
아마도 시간이 오래 걸린 거라고 생각할겁니다.
맞아요. 하지만 CPU의 처리능력은 막강합니다.
이제는 할 수 있어요. 우린 거의 무한대의 처리능력과 메모리를 가지고 있습니다.
그냥 이벤트들만 저장하는 건 어떨까요?
매우 흥미로운 아이디어라고 생각합니다.
이벤트들을 저장하면 아무 것도 삭제할 필요가 없습니다.
업데이트를 할 필요도 없지요.
CRUD 알지요? Create. Read. Update. Delete.
U와 D 두 글자를 없어지고 C와 R만 남게될 겁니다.
생성하고 조회만합니다. 업데이트나 삭제 할 필요가 없어집니다.
업데이트나 삭제를 안한다면 트랜잭션은 없어도 됩니다.
업데이트를 안 한다면 동시성과 관련된 문제가 없어집니다.
아주 흥미롭지요.
이런 생각들을 기반으로 하는 프레임워크들이 있을까요? 네 있습니다.
몇 개인가 있지요.
Write Only 데이터베이스들이지요. Write Once & Read Many Times.
지금은 이야기를 하지 않겠습니다만 웹에서 검색을 하면 나옵니다.
한 번 찾아보세요.
관계형 데이터베이스를 그런 것 들로 대체할지도 모르지요.
Couch나 Mongo DB로 교체할지도 모릅니다. 어떠면 새로 만들 수도 있겠지요.
상관없어요. 대형 벤더에서 제공하는 것을 사용할 필요가 없습니다.
저 하늘 위의 거대한 회사들이요.
저 하늘 위에서 말합니다. "그래 우리 데이터베이스 시스템의 사용을 허락하노라."
그냥 DB를 만들어 써도 됩니다. 그렇게 어렵지 않아요.
다른 질문 있나요?
그렇게 하니까 잘 보이네요.
오케이. 또 다른 질문 없나요?
(누군가 질문 하는 중)
의사결정을 미루는 것이 어려울 때도 있는데...
가족이 있을 때요? (청중들이 웃음)
가족 동반 휴가처럼 여러 요소들이 같이 결정되는 것을 이야기하는 것 이지요? 결정이 필요한 것 중에 연기가 가능한 것들이 있습니다.
예를 들어, 어떤 언어로 개발을 할까? 와 같은 결정은
일찍 해야겠지요.
그렇지요? 뭔가 작성을 해야 합니다.
데이터베이스가 있어야 한다는 것은 아마도 일찍 결정해야 할 겁니다.
웹 어플리케이션이어야 한다는 것도 일찍 결정해야 할 겁니다.
어떤 프레임워크를 사용할지 결정하는 것? 아닙니다.
가족 동반 휴가에 비유했었지요?
휴가로 어디를 갈지는 일찍 결정해야겠지요. 어떤 차 모델을 선택할지도 미리 결정해야 할까요?
6개월 전에 여행을 계획할 때에 미리 신차를 뽑아야 할까요?
여행 전에 차가 고장이 날지도 모릅니다.
차는 단순히 이동 수단입니다. 짐을 싣고 가족이 탈 수 있으면 충분한 거지요.
여행을 갈 수 있으면 되는 겁니다.
데이터베이스 시스템은 차와 같습니다. 여행의 초반에 미리 결정할 필요가 없는 거지요.
가장 최후까지 지연시킬 수 있습니다.
여행가기 전 날에 신차를 살 수도 있는 거지요.
왜요?
복권에 당첨될지도 모르지요.
어쩌면 아기가 태어나서 공간이 더 필요할지도 모릅니다.
여행가기 직전까지 여러 일들이 발생할 수 있습니다.
다른 질문 있나요?
네 저기 뒤에요.
(누군가 질문 중)
레거시 시스템은 어떻게 하냐고요?
(역주: 에자일 세계에서 레거시 시스템은 단위 테스트가 없는 시스템을 의미함)
남은 시간으로 설명하긴 힘들겠군요.
그래서 한 단어로 답변하고. 그에 대해 설명하겠습니다.
점진적인 접근입니다.
사람들은 레거시 코드를 없애 버리고 새로 개발하고 싶어합니다.
그렇게 하지 마세요.
보통 실패하게됩니다. 많은 시간과 돈을 낭비하고 말입니다.
시스템의 작은 부분을 선택한 후에
그 부분만 다시 작성하고
동작하게 만드세요.
결국 군데 군데 수정이 되겠지요. 하지만 수정된 부분은 원래 코드보다 개선됩니다.
그렇게 계속 반복합니다.
오랜 시간 동안 많은 노력을 기울여 점진적으로 개선이 될 것 입니다.
신규 기능을 추가할 때에도 같은 방법으로 합니다.
사실 이건 일반적인 코드 개선 과정입니다.
크게 변경하는 것은 하지 마세요. 위험합니다.
감사합니다. 다음에 봅시다.
(演讲从 4:45 开始)
好吧,你们都能听到我吗?
这种备用的方式能听到我吗?好的,不错不错不错。
嗯...什么是电子?
那么我想每个人都知道,它是原子的一部分
嗯...(从其他房间的尖叫声)是啊,我是这么认为的。我认为这是严肃的(不会翻译)??
电子是原子的一部分
它携带单位负电荷,对立于带有正电荷的质子。
它显然也有质量,但是却非常小,成千上万的电子或类似的东西。质量非常非常小
我们认为它是一个粒子,但是这是误导。电子的实际行为更像是一个比波就像一个粒子
那为什么我们认为它是粒子?
,我们这样做的原因是,当一个电子相互作用,在它就像一个粒子那样在一个位置相互作用
但当电子通过空间移动时它不会像粒子那样移动
它像波浪一样移动,并且波浪移动式没有具体位置的
比如大海的波浪,它可以变得巨大
它有明确的能量,但没有明显的位置
这就是电子如何移动的
电子遵守一个原则,就是mistruster原则
它被称为泡利不相容原理
两个电子绑定到同一个的系统不会有相同的状态
无论出于何种原因,他们不能有相同的状态
因此,如果有两个电子中的原子
那两只电子一定是不同的
现在,他们可能以不同的方向旋转
电子可以向左旋转,也可以向右旋转
两个电子具有完全相同的能量可以结合在一起,一个向左转,一个向右转
有没有办法让第三个电子也在那里?
所以下一电子必须具有更高的能量,那么你可以另外有两个
一个向左边旋转,一个向右边旋转
但是如果你想增加另一个,那将是不同的东西
而你可以在不同的空间安排他们
所以,你可以有一组的两个这样的,另一组两个这样的,另一组两个这样,一组的两个球体的这汇总方式增加了八个。
我们所知道的大部分原子都有8个电子在它们的壳中
原因是眼前这个可爱的小几何形状。球体中三行每行可以包含两个
你有没有想过水?
我这里就有一些。迷人的物质
它是什么做的?
两个氢原子一个氧原子构成一个水分子
它是什么形状?
米老鼠!是的,中间一个大的氧原子和旁边两个像耳朵一样的氢原子
它们的角度是外壳安排的结果
是什么使氢气和氧气粘在一起?
想想两个原子,上面覆盖着电子,两个电子互相平行
是什么让两个氢原子和一个氧粘在一起?
而事实证明,如果你把这些两个氢原子和氧放在一起
那么你想想电子的波浪,而不是粒子,那些波浪会想去哪里呢?
那些波浪都想在氢原子的质子和氧原子的质子之间
因此,他们聚集电子的波浪会越集越多
两个原子之间,实际上是三个,然后再是其他地方
它们还是会去其他地方,只是这更可能是质子之间
这意味着原子之间有额外的负电荷,并且负电荷还要跟踪质子,这就是共价键
现在,如果你把这个米老鼠原子并且一分为二
你发现有更多的负电荷以上的一个和下面的一个
原因是全部负电荷都喜欢坐在两个氢原子和氧原子之间
因此,有比另一侧更多的负电荷,这意味着这是水分子的偶极
它一面是负极,一面是正极
这就是为什么水是湿的。
水粘到你的手,因为所有的水分子旋转,粘到你的皮肤上带电的表面
即使它不是很带电
这就是为什么水会是良好的溶剂,因为小的水分子会旋转吸引他们想要的粘上其它分子的部分
这就是为什么水使它成为一个很好的清洁剂
这就是你为什么可以用水来做最美好的事情(清洗?)。谁是做过这样的实验?
你找到一个水龙头。然后你打开一点非常小的水流。不是很快,水只是涓涓溪流
然后你拿一个气球,在你的头发上擦一擦。然后拿着气球慢慢接近水流,水会朝着气球弯曲
正如所有的水分子转身把它跟踪的电荷
当然,这不是我们应该谈论的
这次演讲的题目叫做“架构----逝去的年华”。这个演讲我已经做了好几年。
这是关于干净的设计简洁的代码后的下一个步骤。
这是关于干净的系统结构
这从那开始,
这是一个十年前左右我写的应用程序的目录结构。
那时我正在研究的Rails。有人是Ruby on Rails的程吗序员?
在那边有一个,他在挥舞他的手。很好。
我当时学习的Rails。我写了这个应用程序
它是我跟着书写的。你得到的书籍了。你按照书的提示
我按照书上的所有建议完成了它。
对此我很高兴。然后我很长时间没有去管他
然后大约三年前,我的儿子在我的要求下,写了一个应用程序
然后我看着那个程序,我看到那个目录结构。
一模一样的目录结构
这是两个完全不同的应用程序。它们之间一点关系也没有
可是他们有相同的目录结构。我看着它开始思考。
为什么这两个应用程序具有相同的高层次目录结构?
它们是两个完全不同的应用程序。
我认为他们有相同的目录结构,是因为他们都是Rails应用程序。
我又问我自己,好的,但为什么那么重要?
为什么Rails或者其他框架这么重要,它会占据应用程序的高层次目录结构主导地位?
而我之所以对自己的资产问题是因为这个。
Web是一个传递机制,是一个I / O通道
Web不是架构设计中的重点
我们认为自己是编写Web应用程序。
其实我们不是编写Web应用程序。
我们正在编写一种通过I/O通道(我们熟知的Web)传递它们的内容的应用程序
那为什么应该是I / O通道主宰我们?
有谁还记得当Web变得重要起来?1980年?1990年?
有谁还记得那是一个怎样的变化?如何从根本上让一切变得不同?
除非它不是,因为我们没有真正在做什么新的东西?
我们只是从输入源将输入汇集起来,处理它,将它扔向一个输出源
这就是Web的所有
为什么Web会主宰这么多?
于是我开始思考架构。我开始寻找蓝图
这里有一张蓝图。如果那上面没有写着”library“这个单词。不用多久,你也会弄清楚这是一个图书馆
因为它显然是一个图书馆。
那里有一堆书架。那里有一堆读书用的桌子。
桌子上有一些电脑。还有的地方,那里有可以借阅或归还图书的前台
这不会花太长时间让你弄清楚去:“嗯..这一定是这样一个图书馆。“
这里还有另外一个。这是一个教堂。这显然是一个教堂。
哦,你可能会误以为这是一个剧场。剧院和教会确实有一定的相似的地方。
但是,没有,这绝对是一个教堂。PUSE,祭坛,在外面教室,前面围绕着的祷告区
这显然是一个教堂。
建筑的架构不会告诉你它们是如何构建的。而是告诉你它们是什么。
他们的意图。架构就是关于意图的。
但是Rails应用程序的高层次目录结构并没有传达意图给我。
他们只是告诉我,他们是Rails应用。更蹊跷的是
然后它发生在我身上。
这是已知问题?这是已解决问题。人们意识到,1992年伊娃·雅各布森解决并写了这本书。
谁有这本书?谁读过这本书?这里有一个人,其他人呢?
《面向对象的软件工程》,如果你有,它是一本精彩的书。
1992年有点老了,但没关系。里面的原则还是非常好的。
注意副标题,它写着:”用例驱动法“
谁还记得”用例“?呃..看到了吗?那是在90年代初非常流行。非常的火
事实上,它是如此受欢迎,甚至被那些侵入并摧毁了用例本来该有的样子的顾问们彻底摧毁
如果你还记得那个时代,你可能还会记得一个又一个的顾问在互联网上发布自己特定格式的用例
格式成为了所有的重点。我们的PDF文件都在那里,它让你填写一个标准的用例形式的模板。
就是填上用例的名称,再填上”输入“以及用例"前提"和"后置"
和主要角色和次级角色以及三级角色。三级角色是什么鬼?
你必须填写所有的东西,用例的整个问题变成了一种形式,而不是一种功能。
当正好时代的巅峰,敏捷运动开始。
我们不再讨论用例,我们开始讨论故事,用例有关的全部东西被扔弃在地板上。没有人再讨论它
于是我又将它拿出来,重新一遍手册,读一遍书
我想起了雅各布森写到的东西
这里是一个用例。雅各布森写的那种典型的用例
你是否注意到它只有有非常小的形式。
哦~一点点而已。 created order是它的名字,想象一下,这是订单处理系统的用例。
它有一个像” customer id“和”客户联系信息“和”运输目的地“等一些输入数据。
注意,我没有提供任何细节,我不是在强调”客户ID“是什么
无论是数字或字符串,我不在乎。
我没讨论客户联系方式是什么,我只是认为它有名字和日期和地址以及其他的东西。但我不在乎
我并不想在此处指定明确的细节。
然后,到了主要课题
主要课题一套计算机运行满足用例的步骤,是处理的步骤
第一步是订单业务员发布的创建订单的命令,实际上不是计算机的做的事。
第二步是有系统来验证数据是否有效。注意,我没有讨论如何验证,怎么验证并不重要
第三步是系统创建的订单,并且确定订单的ID。
我假定这是某种数据库的操作,但我不会在这里讨论。
第四步是系统将订单号返回给业务员,也许是一个Web网页,但我不会在这里讨论
事实上,整个的用例只字未提Web。
这个用例的运行与什么样的输入输出通道没有任何关系。
我可以在一个控制台应用程序,桌面应用程序,一个Web应用程序,面向服务的架构应用这个用例的运行,我的手机应用程式也没关系。
因为用例是无关的,它并不关心I / O通道的具体实现。
雅各布森说,你可以采取的这样的用例,并把它变成对象。
他把这个对象叫做控制对象。我已经更名为”interactor “,以避免与Model View Controller混乱。
也许我应该把名字改成”用例“。但我没有。我在这里写的是interactor 。
interactor 对象实现了用例,它的输入,就是用例的输入,它提供的输出,就作为用例的输出。
它至少在高层去实现那些用例的具体的规则,处理步骤等
注意下面的注释,它写着interactors拥有具体的应用业务规则
其实有两种业务规则
有一些是全局性的业务规则,他们不关心应用程序是什么。
然后还有一些是绑你正在编写应用程序的其他业务规则
例如,我们有一个订单录入应用程序和订单处理应用程序。两个完全不同的应用程序
他们都可能有一个订单对象,并且订单对象可能有共同的业务规则
无论你使用哪一个应用,只有其中一个应用程序有插入订单用例
所以这样的用例是应用程序特定的,他们有他们的特殊应用
不在特定应用中的业务规则就绑定到实体对象,有些人称为业务对象
我不喜欢这个词,雅各布森提出的entity objects(实体) 比较合适
你把所有的应用程序业务规则放到实体里,interactor将控制的这些实体。
然后你要搞清楚,如何从一个用例获得输入和输出放到到另外一个用例
我们用接口来实现这个功能,我画了这些作为面向对象的接口
注意,interactor使用了其中一个接口,以及从其他派生的。
其中一个是从输入接口派生的,另一个是输出接口
注意,箭头指向相同的方向,这很重要
我们马上会知道为什么它会这么重要
这三个对象都是雅各布森提出的应用程序架构的一部分
现在让我们继续探索,就让我们看看它是如何工作的。
这是一个典型的应用。那里有一个用户,这么个小人站在那里
那是一个真实的人,他正在通过某种传递机制与系统进行交互
也许是Web,也许不是,谁在乎
用户,也许是按下键盘上的一个键,也许类似的事情,来通知系统接收数据
这种传递机制也许是网络,也许不是,没多大的关系
可以理解这是一种请求模型。
请求模型是一个纯粹的数据结构
一个普通的旧.NET对象(POCO)或普通Java对象(POJO),一种原始数据,它不知道数据从哪里来, there's no trappings of the web
If there's the trappings of the web anywhere
这只是一个普通的数据结构,它没有函数。什么都没有。
一串的数据结构的公共元素,它包含了所有的输入数据
然后被传递到interactor派生的输入边界接口,
interactor收到请求模型,读取它,并解释它
并且把它变成一套发送到实体的较小的命令
所有小业务对象在那里,它控制着密密麻麻的所有调用实体的函数。
一旦工作完成,那么它反向转动。它开始查询这些实体,并说,'OK,你有什么事?“
同时他也制造出了另一种数据结构,叫做结果模型
结果模型也是一个普通的数据结构,不知道任何事情,只是一个POCO或者POJO,只有公共字段,没有函数
结果模型通过输出边界接口被传递到用户那被显示或者其他的
那些都是其他应用程序的流程了。
你能测试Interactor吗?
当然可以,而且很简单,不是吗?
创建输入数据结构,调用Interactor看看输出的数据结构
你需要一台Web服务来完成这件事吗?
不,因为interactor,只是POCO或者POJO,这就是所有的数据结构
你需要一个数据库来完成这件事吗?好吧,也许你需要,但是我们只需要一分钟就能完成
我可以在没有具体传递机制的情况下测试它
我的传递机制是否是Web?我不在乎!我不需要运行一台Web服务器
我也不需要通过网页来进行测试
我可以测试整个系统的运作而不去关心具体的输入/输出的传递机制
什么是MVC?
是不是MVC的事情是我们都应该做的?
MVC代表什么? Model View Controler 是谁发明的MVC
那家伙。现在我要彻底念错他的名字。你也许可以念的比我好
可是我要叫他Trygve Reenskaug。你也许可以念的比我好
我见过他一次。那个在70年代末发明的模型视图控制器的家伙。
我见过他一次。两年前我在这里遇见了他。
我在休息室找电源插座,而这个老家伙走到我面前,递给我一个电源插座
我抬头......Trygve Reenskaug!
当他递给我电源插座时,我们手指接触了
我当然不会洗手,Trygve Reenskaug!
有些人过来找我合影,现在我也是一个有fans的人了。
在80年代初和70年代末,Trygve Reenskaug想出了这个结构称为模型-视图-控制器。
他在Smalltalk的平台上这样做
它背后的原理非常简单
你已经有了一个模型对象,模型对象包含业务规则。
它不知道它是如何显示的。它不知道输入从哪里来
这是纯粹的业务规则,这里有一个控制器,它处理所有的输入
控制器的工作就是盯着输入,不管是什么设备,键盘什么的都无所谓,然后翻译用户的动作为命令针对model
然后,View就出现了
我画的View有一个有趣的双箭头,这是一个观察的关系
View 在Model 上注册,当Model发生变化,便回调到View,告诉View重新显示
View的工作是要显示或代表或以某种方式传达模型的内容的。
它可以很好地在一个图形用户界面上工作,它同样也可以同样运行在其他的你想要运行的系统上
你有一些东西控制输入(Controler),你有一些东西控制过程(Model),你有一些东西控制输出(View)
这可能是最早命名的设计模式了,运用在Smalltalk中
按钮里有MVC模式,复选框里有MVC模式,文本字段里有MVC模式
我们还没有关于屏幕的MVC模式
在那些早期的日子里,这已经被扭曲和摧毁,像在软件里的任何东西一样。
如果它原本是一个好主意,其他人就会复制它。并使用同样的名字,但是完全不同的东西,还要叫好
OO发生过这事情,structurel发生过这事情,ObjectsIt 发生过这事情,Agile发生过这事情
这会发生在任何东西上,只要它们的名字与好的东西有关,就有人把他们自己的东西冠以其名,并叫好
那么MVC现在怎么样了?现在我们拥有许多MVC框架
他们不顾任何事情,他们不是Trygve Reenskaug所描述MVC
它们是非常不同的东西,事实上,他们看起来是这样的
那里你有一大堆的controler,现在的controler,如果我们想一想Web,控制器是空中的Web框架通过某种方式激活的
空中的Web框架?管它是什么,谁在乎。Rails?spring?上帝才知道那是什么
通过某种方式从Web路由过来复杂又可怕的URL到一堆函数里,这就是我们说的Controler
它会把从Web获得的参数和数据传入每个Controler
然后Controler会接收这些数据,并且向business objects大喊,告诉business objects该做什么
然后Controler收集来自business objects的数据,又开始向View大喊,然后视图将返回到业务对象,并收集了一堆数据,并表示它们
最终你的下场就是business objects 被Controller 的功能和View的功能给污染了
把不同的功能放在什么地方,这很难知道。有时候他们在business objects 里,但是确实却是不应该的
我们如何处理与输出端?
在这里,我向您展示了Interactor。Interactor完成了这些事情
它从用例处理好的实体中收集的数据。该Response Model已经准备好。我们要通过输出边界传递Response Model
什么实现了输出边界?一种叫Presenter的东西
Presenter的工作是获得Response Model,记住它,是一个纯粹的数据结构。
并且把它转换成另一种纯粹的数据结构,我们称之为View Model
View Model 是输出的一种Model,一种输出的表示。它仍然是一个数据结构
但是,如果有屏幕上有一个表格,那么数据结构中也将会有一个表格
如果屏幕上有一个文本字段,那么数据结构中也会有一个文本字段
如果屏幕上的数字需要保留小数点后的两位,View Model中会有TrimToTwoDecimalPlaces和ConvertIntToStrings
如果他们被括号括起来,或者需要取消那些由Presenter加上的括号,这也被放在 View Model里
如果有一个菜单,那么每一个菜单项的名字也在 View Model里
如果有一些菜单因为不可用而需要变成灰色,控制这个状态的booleans 也在View Model里
任何可以显示的表示都在 View Model 数据结构里,当然是以一种抽象的形式
然后,它将影响到View
View是愚蠢的,它什么事情也没做,只是把View Model中的字段拿出来,放到该放的地方,Boom Boom Boom
没有处理,没有if语句,也许有一个循环用来加载表,仅此而已
View太愚蠢了,以至于我们通常不会担心怎么去测试它。因为就算我们直接用眼睛来检查View也无妨
那么Presenter可以测试吗?
你可以将Response Model的数据结构交给它。然后检查生成的View Model数据结构
所以Presenter是可以测试的。你需要搭建Web服务器并运行来测试Presenter吗?
不,你在没有Web服务器运行的情况下测试Presenter
你不需要Spring或者其他类似的那些只有上帝才知道的容器
你不需要知道任何关于它们的细节
你可以像小的普通对象一样测试所有的东西
顺便提一句,我们有一个目标,就是不用启动任何东西就可以进行尽可能多的测试
你不需要启动一个服务器,光是启动服务器这个事情就得花上30秒到1分钟
你不需要做任何那样的事情,你可以以最快的速度进行测试,就像Boom Boom Boom
这就是在整个过程
从Interactor开始,你可以发现他通过输入边界获得来自Resquest Model的数据
通过输出边界,将数据通过Response Model 传递给Presidenter
现在注意那条黑线。黑线代表应用程序的传送机制(比如Web)。
注意每一个穿过黑色的箭头,它们都指向应用程序
应用程序对Controler和Presenter一无所知
它不知道关于Web的细节,也不知道关于I/O通道的细节
I/O通道知道应用程序,但是应用程序不知道I/O通道
如果你把他们放在单独的Jar包里,应用程序Jar包和Web Jar包没有任何依赖
也许你会这么做,你想把它们放在独立的Jar包中,所以,你可能有一个Web的Jar包,一个应用程序的Jar包
也许还有另外一个I/O传递机制的jar包
那么,你替换I/O机制的方式就是替换Jar包而已
想一想I/O机制作为一个插件,就像Web。你们有多少人使用.Net Sharp?
你们全部都用.Net?谁用.Net?
你们用什么IDE?你们用了插件吗?那么 一个插件
IDE的作者和插件的作者,他们彼此了解吗?
插件的作者了解IDE的作者,但是IDE的作者不了解插件的作者
一点都不关心
他们谁能影响谁?插件的作者是不是可以影响到Visual Studio的正常运行?
有谁使用ReSharper,使用ReSharper的人和使用JerBrains的人能影响到Visual Studio吗?
- (听众)是的,没错
- (罗伯特·马丁)好了,他们可以打破它。
但是他们这样影响它,Visual Studio的作者需要做出响应吗?
微软的软件开发者,他们会响应JetBrains吗?
不,他们根本不关心JetBrains
微软开发者可以强迫JetBrains的开发者响应他们吗?
当然,经常这样!
现在,从应用程序的角度想想这件事
你的应用程序哪些部分应该得到保护,从而免受其他部分的影响
哪些部分是你希望强制响应改变,哪些部分不需要强制响应改变?
而答案应该是非常非常清楚的
你想保护你的业务规则,不被Web的变化所影响
相反,你不想再你的业务规则发生变化时,Web却被保护起来没办法改变
但是,Web上的任何变化都不应该影响到你的业务规则,这就是架构能提供的保障
所有的依赖都朝向应用程序,记住这一点,这既是plug-in architecture
将我们来看看数据库
什么是数据库?
这是不是你对数据库的认识?
你是不是认为数据库才是中间的上帝,周围都围绕着各种各样的小应用程序
有谁的工作是DBA?这间屋子里有DBA吗?
哦~我很安全,很好
有人知道DBA是什么吗?将应用程序颠覆,脱离该有的模式。确保数据库才是正确的
这是不是就是你心中的数据库?
因为这是我的观点
数据库是一个细节上的东西
这不是架构中重要的东西
数据库是一个装满Bits的桶而已
这不是你的系统架构中最重要的东西
它和业务规则没有任何关系
我的天,除非你把业务规则放在存储过程里
存储过程里做的事情都是查询,验证,完整性检查只是增强功能,但不是业务规则
为什么我们要有数据库?
数据库这种东西从哪来?为什么会有Oracle?
我们所有的数据存放在哪里?
我们存储在磁盘上,有人写过磁盘驱动吗?
有人写过一个软件,用来控制内存的数据和磁盘交互吗?
没有人写过!哦,天哪,哦 耶!磁盘驱动程序!
什么?软盘?那还不够
从磁盘获取数据,或者将数据存入磁盘是非常难得事情,为什么?
因为数据在磁盘上的组织方式
数据在磁盘上圆形轨道上的组织方式
这种圆形轨道可以在布满盘面
有一个磁头可以在这些轨道上来回移动,所以,你的控制磁头移动到正确的轨道上
然后磁盘开始转动,你就可以读取你需要的数据了
你找到你想要的扇区,一个轨道的表面大概有5,60个扇区,每个扇区可能有4K字节
所以你必须等待磁盘旋转,当你的扇区到来时,你就可以读取数据了
然后你进入扇区,读取你想要的字节
这非常痛苦,而且速度非常慢
如果你不优化,这可能会花上一辈子时间来读取或者存储数据
所以我们写了一个解决这个问题的系统,我们叫他数据库
可是发生了一些事情
看见我的笔记本了吗?我的笔记本有512M SSD内存,没有磁盘。这对你来说应该不会惊讶
这间屋子有人还在用硬盘吗?
这间屋子里有人用旋转的那种硬盘吗?
哦 我的天,这是真的吗?
嗯,大家都知道,现在已经没有人再去考虑旋转的那种磁盘了,我们考虑的都是SSD
哦,我们想想服务器机房里,也许还有那种硬盘,不过它们始终会被淘汰
放眼未来几年,那种硬盘开始消失,所有的都被RAM取代
我说的是RAM?
RAM直接在字节级寻址
我们正在使用直接寻址的内存几乎无限量也是持久的。
这就是我们将要存储数据的地方
如果这就是我们要存储数据的地方,为什么还要像在地狱般一样使用SQL来访问它们呢?
SQL是痛苦的,Table也是苦痛的
在你打算用哈希表来查询事情的时候难道不是跟随周围的人一样?
那就是你所做的吗?你把所所有的table读入内存里,然后把数据组织的更好,你真的可以使用它吗?
如果我们只是把它放在我们想使用的格式?
如果我是Oracle我会被吓死。
因为我存在的理由彻底消失了
大数据库系统的概念已经开始消失了
我们应该怎么样保护我们的应用程序不受这种细节的影响?
数据库这个细节往往主宰了一切,但是我可以保护我们的应用程序就像保护它们不受Web的影响一样
我画了另一条可爱的黑线在那
我确保所有的穿过这条线的依赖都指向应用程序里面
我把数据库做成了一个应用程序的插件
那么,我就可以切换使用Oracle还是MySQL
又或者我可以放弃MySQL从而使用CouchDB
又或者我可以放弃CouchDB从而使用CouchDB或者别的我想用的
我可以像插件一样使用数据库
也许你永远都不会更换数据库,但是会的话会更好,即使你没必要这么做。
我们怎么实现呢?好吧,相当直接了当,在那里还有另外一个接口
我在这里把它叫做Entity Gateway
Gateway中有对应的每一个Entity的查询方法
他提供一个功能一个函数,让你你要查询任何你想要的东西,
你在黑线以下的Entity Gateway Implementation 实现具体的方法
这个实现可以是数据库,或者其他什么,管他的
注意,没有任何数据库的管理部分渗透到了应用程序中
从Entity Object来的地方。Entity Object 有可能被数据库以某种疯狂的方式取出,并映射到Table里
Entity Gateway 的实现会汇集数据
创建Entity Object,然后将他们送过黑线
因此,一旦它们穿越黑线之后,它们就是真正的Entity Object了
有人用过类似Hibernate的东西吗?或者ORM工具?
谁在使用类似的东西?
它们在这个图里面的哪个位置呢?
在具体实现里,黑线的下面
黑线以上对ORM工具的任何部分都不了解
你在Business Object中使用那些有趣的小的注解或者属性吗?让他们从你的Business Object滚开
你不会想要让你的Business Object知道他们是由Hibernatez创建的
让它被那些已经被数据库污染了得来自黑线下面的东西创建
保持你的Business Object 纯洁,为什么?
一个对象是什么?
我为这个问题花了很多时间
什么是对象,一个对象就是一组公共方法的集合
你想知道其他的东西?这是不允许的,不是吗?
那里可能有数据,但是你不能看到它,这些都是私有的,不是吗?
从你的角度来看,Object是一堆方法,不是一堆数据
既然Object是一堆方法
那么Obejct就是和行为有关的
一个Object是和业务规则有关的
它不是和数据有关的
我们估计那里面有数据,但是我们不知道在哪
我们也不知道是什么格式,我们也不想知道
什么是数据结构?
一个数据结构是一组已知的数据元素,公开的,大家都能看到
并且,里面没有任何方法
数据结构没有任何功能
对象和数据结构正好是相反的
数据结构有明显的数据,但没有方法,对象有明显的功能,但没有明显的数据
正好相反
没有任何东西能这样,比如ORM
对象关系映射?不能做到
因为从数据库得到的是一种数据结构,你不能把一个数据结构映射到一个对象
因为他们根本就是不同的两个东西
实际上这只是Entity所需要的数据被存放在什么地方了,上帝才知道在哪
然后不知道怎么神奇的传递到Entity那,又不知道怎么神奇的开始使用它。我不在乎
这些Entity不会有Hibernate创建
也许这些Entity使用了一些由Hibernate创建的数据结构,但我不在乎
我不想任何Hibernate的功能或者其他框架的功能穿过这条黑线
黑线以下的东西可以被污染
黑线以上的东西都是我的宝贝,我要保护他们不受影响
这些都是我的业务规则,我不会让我的业务规则受到框架的污染
框架。我们都喜欢使用框架,我们觉得它们很酷
我们认为框架做的事情确实为我们节省了不少时间
但框架的作者引诱我们绑定到他们那
他们为我们提供的父类让我们继承
当你从一个父类继承时,你已经嫁给了那个类
你将自己的狠狠的绑定在了父类上,没有比继承更强的关系了
因此,通过从别人的父类派生,你给了它们一个巨大的许诺
但是,作为他们来说,没有做任何一种对你的许诺
所以这是一种不对称关系
框架的作者从你的承诺中获得好处,但是框架的作者却不对你做出任何承诺
我让你自己去评估一下其中的利弊
聪明的架构师不会去做这种绑定
聪明的架构师对框架不屑一顾,它们认为框架会绑架我
这个框架希望我绑定到它那,但我想我不会这么做
我想我应该在我的业务规则与框架之间设置一个边界
那么我的业务规则永远不会依赖于Spring或者hibernate或者其他什么只有上帝才知道的东西
我会去使用框架,并且我会小心的使用它们
因为框架的作者对于我最感兴趣的部分一点都不在乎
很久以前,我和儿子还有其他几个人写了一个叫做FitNess的工具
有人在使用FitNesse吗?哦,大部分都用了,很好
FitNesse是用于编写客户验收测试的工具
它是基于Wiki的一个东西,这就是你确切该知道的所有事情
谁发明的Wiki
沃德·坎宁安。谁是沃德·坎宁安?
创造Wiki的人,啊,他的事迹不止这些
沃德·坎宁安是大师中的大师。所有的大师都知道沃德·坎宁安是谁
那些到处去演讲的人,比如我,我们都知道沃德·坎宁安是谁
我们仰望他
他是那个打电话给埃里克·伽马的人
他说:"你知道吗埃里克,你得写一本书叫做设计模式。"
他也辅导过肯·贝克,传授一些东西比如结对编程,测试驱动开发和敏捷开发
如果你知道很多关于软件业的历史,你就会知道他。你会发现:“哇~哪里都有他的身影”
FitNesse是基于沃德的两项发明,Wiki和Fit
我不打算描述Fit。不过我会描述Wiki
大约12或者13年前,我和我的儿子还有其他一些人觉得用java来写这一个类似Wiki的东西
我知道我们想要一个Wiki
所以我们这么想:“好了,我们有一个地方来存储网页,让我存储他们在数据库里吧,我们该用什么样的数据库呢?”
嗯,在那些日子里,只有MySQL是开源数据库,所以我们觉得把一切都放在MySQL中
于是我们准备去搭建MySQL环境,建立一套规则,这时有人说
“你明白,其实我们不需要马上这么做”
”我的意思是,我们以后会这么做,但不是现在。因为我们可以先处理另外一个问题“
这个问题就是怎么把Wiki文本翻译成HTML,这才是Wiki该做的事情
把你的输入的有趣内容放到Wiki里,然后把他转换成HTML
我们需要做很多翻译的事情
于是接下来的3个月 ,我们把数据库彻底遗忘了
我们把Wiki文本翻译成HTML,我们需要一个叫做WikiPage的对象
你可以在这里看到
我们创建一个名为WikiPage的抽象类,我们有一个叫做MockWikiPage的实现
WikiPage的方法里有一些很想数据库功能的方法,比如Load和Save
但是它们没有被实现,它们没做任何事情
3个月以来我们都这么干
当我们把所有翻译工作都完成的时,我们说:“嗯,是时候搭建数据库了”
“因为现在我们确实需要把这些页面存储在实际的地方了”
又有人说:“嗯,其实我们不需要那样做”
“因为我们可以替换成用哈希表在RAM中存储这些页面”
“我的意思是,我们并不需要真正的把他们存储在硬盘上,不是吗?”
这个当然是肯定的,因为所有我们该做的事情反正只是编写单元测试
因此,我们决定创建名为InMemoryPage的WikiPage,其中存储的实现是用哈希表完成的
然后我们继续工作了一年
继续编写更多的FitNesse,并且把所有的数据都放在内存里
事实上,我们让所有的FitNesse都正常工作了
而且并没有把他们任何一个放入磁盘里
这非常酷,因为没有数据库的所有的测试都非常快
但是另一方面它也让人失望,因为我们创建的这一大堆测试再计算机关闭后都消失了
所以这个时候我们终于说:“现在好了,我们需要数据库,让我们搭建MySQL吧”
那时候 Michael Feathers在那
他说:“嗯,你还是没有必要搭建MySQL呢”
“你真的需要的是持久化,而你可以采取将哈希表写入到文件的方式来实现,这也更容易”
我们认为这是一种丑陋的实现,但工作初期它暂时可以运行。以后我们再把他换成MySQL,因此我们这么做了
又是3个月的时间,我们继续开发了越来越多的fitnesse
那非常酷,因为我们可以在带着他出门,向别人展示。我们可以保持网页
像真的Wiki一样开始运行
3个月以后,我们说:“我们不需要数据库”
“它的工作很正常,文件的速度已经足够快了”
“这种方式运行得很好”
我们选择的架构中更重要的部分,并且把数据库仍到了地球的另一端
我们从来没有使用数据库,虽然那确实不是很正确
我们的一位客户说:“我得在数据库中存储数据”
我们说:"为什么?他在文件上工作的一样很好"
他说:“公司的规定,公司所有的资产都必须在数据库中”
我不知道谁和他们这么说的,但是这些数据库推销员确实很有说服力
所以,我们说:“好吧,你看,如果你真的需要在数据库存储它”
“这就是这种结构,你要做的就是创建一个MySQL Page的子类,然后一切都会运行的很好”
一天以后他再来的时候,所有的东西都通过MySQL存储了
我们把它当作一个插件来使用,但是没有人这么用,所以我们把它停止了
这就是一个我们推迟了无数遍的架构中的决定
我们推迟直到项目结束,我们也没这么做
那些我们想放在最开始做的事情,却最终没有做
这告诉我们终极原则
一个良好的架构是允许架构中重要决定被推迟的,延期的
架构师的目标不是做决定
尽可能长的推迟这些事情,那么到最后你将有更多的选择来做决定
你的架构设计,你的代码的高层目录结构,这些高层次的决策都可以推迟了
别告诉我,你的应用程序的架构是一堆框架
“你们应用程序的架构是什么?我们使用的SQL服务器和MVVM和等等等框架”
你没有告诉我任何事情
你只是告诉我工具而已
这不是你的应用程序的架构
你的应用程序的架构是那些用例
而你并不希望用例依赖这些工具
你想把工具的使用推迟的越晚越好
你应该让整个应用程序在没有数据库没有Web的情况也可以运行
也许你会搭建一个简单的小型的Web,然后你可以使用个一两天
那样,你不需要搭建巨大的框架就可以看到一些网页
也许你搭建了一些简陋的类似数据库的东西,来让持久化的工作开始运行
这样你就不需要Oracle的许可来运行持久化的工作了。
下次你再编写应用程序的时候,想一想什么是可以推迟的事情
系统中的应用程序应该使用插件架构,系统中的架构应该是插件架构
UI,数据库,框架的细节都以插件的形式接入用例
哪些才是应用程序的核心?
当然现在的客户希望看到网页
好吧,你依然可以构建一个插件架构,然后让他们看见网页在运行
你不需要向框架承诺太多
你不需要向Web框架承诺太多
你可以先使用一些简单的东西来代替
或者如果你真的想使用一个真正的框架,请吧,但请保持插件架构
那么在某个时候,你可以轻易的卸载它,并使用其他的来代替
这可能就是我最后要谈论的东西了
我们先前已经讨论过这个问题(TDD)
所以非常感谢大家,有什么问题吗?
有点看不清楚,那么我要站过来一点
哦,这一点用也没有
好吧,有人有什么问题吗?
你不得不喜欢空洞。因为我无法看到你的手。
没错。
(有人问一个问题)
那么我猜测Oracle和关系数据库会灭亡。那么我建议用了什么来将取代他们?
多么有趣的一个问题
那必定是RAM了,还有什么可以取代他妈?
如果你要组织数据在RAM中,如果RAM是持久性的,你还需要什么呢?
哦,但让我们说你需要的东西。
好吧什么可能是什么样子的?
嘛,谁听说过CQRS的?
噢,你们几个。
CQRS,多么有趣的想法?
如果我们有高速内存无限量。高速RAM。
或者,也许它甚至磁盘,但谁在乎。
我们为什么要存储什么状态。
为什么不我们只是简单地存储交易?
而不是存储银行账户的,为什么不我们存储使我们创造了银行账户的交易。