(演讲从 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。 或者,也许它甚至磁盘,但谁在乎。 我们为什么要存储什么状态。 为什么不我们只是简单地存储交易? 而不是存储银行账户的,为什么不我们存储使我们创造了银行账户的交易。