程序员心中最佳的框架组合

在过去对框架的设计中,我收到过的最有用的建议是:“不要一开始就根据现有的技术去整合和改进。而是先搞清楚你以为最理想的框架应该是怎样的,再根据如今的技术去评估,的确实现不了时再妥协。这样才能作出真正有意义的框架。”
在这篇文章里,就让咱们按照这样一条建议来探索一下如今的 web 框架最终能够进化成的样子,你绝对会被惊艳到。前端

前端,仍是从前端提及。前端目前的现状是,随着早期的 Backbone,近期的 Angular、React 等框架的兴起,前端在 模块化、组件化 两个方向上已经造成了必定的行业共识。在此基础上,React 的 FLUX、Relay 则是进一步的对前端应用架构的探索。这些技术在目前国内的大公司、大团队内部实际上都落地得很是好,由于很容易和公司内部已有的后端技术栈结合。并且这些纯前端框架的配套技术方案通常比较成熟,例如在支付宝肯定使用 React,其实有一部分缘由是它兼容 IE8,而且有服务器端渲染方案来加速首屏。java

相比之下,像 Meteor 这类从前到后包办的框架就较难落地。虽然能极大地提升开发效率,总体架构很是先进,但架构的每个层级每每不容易达到行业内的顶尖标准。特别是在服务器端,对大公司来讲,一般都有适合本身业务的服务器集群、数据库方案,而且经受过考验。所以当一个团队一上手就要作面向十万级、甚至百万级用户的产品时,是不太愿意冒风险去尝试的。反而是我的开发者、创业型的团队会愿意去用,由于确实能在短期内高效地开发出可用的产品出来。包括像 Leancloud 提出的这类型的服务,也是很是受欢迎的。node

这种现状,就是理想和现实的一个争论。Meteor 的方式能知足我对开发效率的理想,而团队已有的技术方案能保障稳定。可否整合其中的优点,不妨让咱们进一步来细化一下对框架的但愿:python

- 有强大的先后端一致的数据模型层
- 代码能够能够复用。例如我有一个 User 模型,当我建立一个新的 user 时,user 上的字段验证等方法是先后端通用的,由框架自动帮我区别先后端环境。
- 数据模型和前端框架没有耦合,但能够轻松结合。这样在前端渲染型的框架进一步升级时,不影响个人业务逻辑代码。
- 由数据模型层提供自动的数据更新机制。例如我在前端要获取 id 为 1 的用户,而且若是服务器端数据有更新的话,就自动帮我更新,不须要我本身去实现轮询。我但愿的代码写法是:react

 user =  User({id:1});
user.pull();
user.watch();

实际上,Meteor已经能实现绝大部分上述功能。但这不是软文。我要强调两点我不但愿的:程序员

- 我不但愿这个数据模型层去包含业务逻辑,也就是我建立的user对象,我不但愿它提供 login、logout 等 api。
- 我也不但愿数据模型层自动和任何ORM框架绑定,提供任何 SQL 或 NoSQL 的数据支持。

看到这两点你可能心中大打问号,这两点不正是高效的精髓吗?先后端逻辑复用,屏蔽数据库细节。别急,让咱们从新用“理想的方式”来思考一下“逻辑”和“数据持久化”这两件事。web

数据与逻辑

咱们以这样一个问题开头:任何一个应用,咱们的代码最少能少到什么程度?docker

这算半个哲学问题。任何人想想都会获得同一个答案:最少也就少到和应用自己的描述一一对应而已了。什么是应用描述?或者说什么是应用?咱们会这样描述一个博客:“用户能够登陆、退出。用户登陆后能够发表文章。发表文章时能够添加相应的标签。”数据库

抽象一下描述,答案很简单:数据,和逻辑。编程

若是你在一个流程要求严格的公司,应用描述就是prd或系分文档。应用的数据就是数据字典,应用的逻辑就是流程图的总和:

 

 

 

流程图

 

 

那么代码最少能怎么写呢?数据很简单,参照数据字典,咱们来用一种即便是产品经理都能掌握的伪码来写:

User : {
name : string
}

Post : {
title : string,
content : text
}

Tag : {
name : string
}


User -[created]-> Post
Post -[has]-> Tag

这里为了进一步帮助读者从已有的技术思惟中跳出来,我想指出这段伪码和数据库字段描述有一个很大的区别,那就是:我不关心 User 和 Post 中间的关联关系究竟是在二者的字段中都建立一个字段来保存对方的id,仍是创建一个中间表。我只关心我描述它时的逻辑就够了。数据描述的代码,最简也就简单到这个程度了。

那么逻辑呢?咱们先用按常规方式试试?

class User{
    createPost( content, tags= post =  Post({content:content})    
        post.setTags( tags.map(tagName=>{ return  Tag(tagName)} ) )
        return post    
    }
}        

好像还不错,若是今天产品经理说咱们增长一个 @ 功能,若是文章里 @ 某个用户,那么咱们就发个站内信给他。

class User{
    createPost( content, tags= post =  Post({content:content})    
        post.setTags( tags.map(tagName=>{ return  Tag(tagName)} ) )

        ( at.scan(content) ){
            at.getUser(content).forEach( atUser =>{
                system.mail( atUser )
            })
        }

        return post    
    }
}

你应该意识到我要说什么了,像互联网这种能够快到一天一个迭代的开发速度,若是没有一个好的模式,可能用不了多久,新加的功能就把你的 createPost 搞成了800行。固然,我也并非要讲设计模式。代码中的设计模式,彻底依赖于程序员本人,咱们要思考的是从框架层面提供最简单的写法。

让咱们再回到哲学角度去分析一下业务逻辑。
咱们所谓的逻辑,其实就是对一个 具体过程的描述 。在上面这个例子里,过程无非就是添加标签,全文扫描。描述一个过程,有两个必备点:

  - 干什么
  - 顺序

顺序为何是必备的?某天上面发了文件说标题里带 XXX 的文章都不能发,因而你不得不在函数一开始时就进行检测,这时就必须指定顺序。

若是咱们用左右表示会互相影响的顺序,从上下表示互不相干的顺序,把上面的最初的流程图重画一下:

 

 

 

这是一棵树。若是咱们再加个功能,添加的标签若是是某个热门标签,那么咱们就把这篇文章放到网站的热门推荐里。这棵树会变成什么样子呢:

 

 

是的,事实上人类思惟中的任何过程,均可以画成一棵树。有条件的循环能够拆解成递归,最终也是一棵树。但重点并非树自己,重点是上面这个例子演化的过程,从一开始最简单的需求,到加上一点新功能,再到加上一些恶心的特殊状况,这偏偏就是真实世界中 web 开发的缩影。真实世界中的变化更加频繁可怕。其中最可怕的是,不少时候咱们的程序结构、用到的设计模式,都是适用于当前的业务模型的。而某天业务模型变化了,代码质量又不够好的话,就可能遇到牵一发动全身,大厦将倾的噩梦。几乎每一个大公司都有一个“运行时间长,维护的工程师换了一批又一批”的项目。Amazon曾经有个工程师描述维护这种项目的感受:“climb the shit mountain”。

回到以前的话题,在逻辑处理上,咱们的理想是写出的代码即短,又具备极高的可维护性和可扩展性。

更具体一点,可维护性,就是代码和代码结构,能最大程度地反映业务逻辑。最好个人代码结构在某种程度上看来和咱们流程图中的树同样。这样我读代码,就几乎能理解业务逻辑。而可扩展性,就是当出现变化时,我能在完成变化时,能尽可能少地去修改以前的代码。一样的,若是咱们能保障代码和代码结构能和流程图尽可能一致,那么在修改时,图上怎么改,咱们代码就怎么改。这也就是理论上能达到的最小修改度了。综上,咱们用什么样的系统模型能把代码变得像树形结构同样?

很简单,事件系统就能够作到。咱们把都一个业务逻辑当作事件来触发,而具体须要执行的操做单作监听器,那么上面的代码就能够写成:

 emitter 是事件中心

emitter.on("post.create", function savePost(){...})

emitter.on("post.create", function createTags(){...}, {before:"savePost"})

emitter.on("post.create", function scanSensitiveWords( post ){

    ( system.scanSensitiveWords( post ) ){
        return  Error("you have sensitive words in post.")
    }

}, {block:all})

emitter.on("post.create", function scanPopTags(){...})
执行建立文章操做
emitter.fire("post.create", {...args})

这样看来,每一个操做的代码变得职责单一,总体结构也很是工整。值得注意的是,在这段伪码里,咱们用了 `{before:"savePost"}` 这样的参数来表示操做的顺序,看起来也和逻辑自己的描述一致。

让咱们回到可维护性和可扩展性来检查这种写法。首先在可维护性上,代码职责变得很清晰,而且与流程描述一致。不过也有一个问题,就是操做的执行顺序已经没法给人宏观上的印象,必须把每一个监听器的顺序参数拼起来,才能获得总体的顺序。

在可扩展性上,无路是新增仍是删除操做,对应到代码上都是删除或新增相应的一段,不会影响到其余操做代码。咱们甚至能够把这些代码拆分到不一样的文件中,当作不一样的模块。这样在增减功能时,就能经过增删文件来实现,这也为实现一个文件级的模块管理器提供了基础技术。

至此,除了没法在执行顺序上有一个宏观印象这个问题,彷佛咱们获得了理想的描述逻辑的方式。那咱们如今来攻克这最后一个问题。拿目前的这段伪码和以前的比较,不难发现,以前代码须要被执行一遍才能较好地获得其中函数的执行顺序,才能拿到一个调用栈。而如今的这段代码,我只要实现一个简单的 emitter,将代码执行一遍,就已经能获得全部的监听器信息了。这样我就能经过简单的工具来获得这个宏观的执行顺序,甚至以图形化的方式展示出来。获得的这张图,不就是咱们如出一辙的流程图吗?!

不知道你有没有意识到,咱们已经打开了一扇以前不能打开的门!在以前的代码中,咱们是经过函数间的调用来组织逻辑的,这和咱们如今的方式有一个很大的区别,那就是:用来封装业务逻辑的函数,和系统自己提供的其余函数,没有任何能够很好利用的区别,即便咱们能获得函数的调用栈,这个调用栈用图形化的方式打印出来也没有意义,由于其中会参杂太多的无用函数信息,特别是当咱们还用了一些第三方类库时。打印的结果多是这样:

 

 

 

而如今,咱们用来表述业务的某个逻辑,就是事件。而相应的操做,就是监听器。监听器不管是触发仍是注册,都是经过 emitter 提供的函数,那么咱们只须要利用 emitter,就能打印出只有监听器的调用栈。而监听器的调用栈,就是咱们的流程图。

 

 

 

代码结构可图形化,而且是有意义的可图形化,这扇大门一旦打开,门后的财富是取之不尽的。咱们从 开发、测试、监控 三个方面来看咱们能从中得到什么。

在开发阶段,咱们能够经过调用栈生成图,那经过图来生成代码还会难吗?对于任何一份流程图,咱们都能轻易地直接生成代码。而后填空就够了。在调试时、咱们能够制做工具实时地打印出调用栈,甚至能够将调用时保存的传入传出值拿出来直接查看。这样一旦出现问题,你就能够直接根据当前保存的调用栈信息排查问题,而再无需去重现它。同理,繁琐的断点,四处打印的日志均可以告别了。

测试阶段,既然能生成代码,再自动生成测试用例也很是容易。咱们能够经过工具直接检测调用栈是否正确,也能够更细致地给定输入值,而后检测各个监听器的传入传出值是否正确。

一样很容想到监控,咱们能够默认将调用栈的数据建构做为日志保留,再用系统的工具去扫描、对边,就能自动实现对业务逻辑自己的监控。

总结一下上述,用事件系统去描述逻辑、流程,使得咱们代码结构和逻辑,能达到一个很是理想的对应程度。这个对应程度使得代码里的调用栈信息就能表述逻辑。而这个调用栈所能产生的巨大价值,一方面在于可图形化,另外一方面则在于能实现测试、监控等一系列工程领域的自动化。

到这里,咱们已经获得了两种理想的表达方式来分别表述数据和逻辑。下面真正激动人心的时刻到了,咱们来关注现实中的技术,看是否真的可以作出一个框架,让咱们能用一种革命性的方式来写应用?

理想到现实

首先来看数据描述语言和和数据持久化。你可能早已一眼看出 `User -[create]-> Post` 这样的伪码是来自图数据库 Neo4j 的查询语言 cypher 。在这里我对不熟悉的读者科普一下。Neo4j 是用 java 写的开源图数据库。图数据自己是以图的方式去存储数据。

例如一样对于 User 这样一个模型,在 关系型数据库中就是一张表,每一行是一个 user 的数据。在图数据库中就是一堆节点,每一个节点是一个 user。当咱们又有了 Post 这个模型时,若是要表示用户建立了 Post 这样一个关系的话,在关系型数据库里一般会创建一个中间表,存上相应 user 和 post 的 id。也或者直接在 user 或 post 表里增长一个字段,存上相应的id。不一样的方案适用于不一样的场景。而 在图数据库中要表达 user 和 post 的关系,就只有一种方式,那就是建立一个 user 到 post 的名为 CREATED 的 关系。这个关系还能够有属性,好比 {createdAt:2016,client:"web"} 等。

你能够看出图数据和关系型数据库在使用上最大的区别是,它让你彻底根据真实的逻辑去关联两个数据。而关系型数据库则一般在使用时就已经要根据使用场景、性能等因素作出不一样的选择。

咱们再看查询语言,在 SQL 中,咱们是以`SELECT ... FROM` 这样一种命令式地方式告诉数据怎样给我我要的数据。语句的内容和存数据的表结构是耦合的。例如我要找出某个 user 建立的全部 post。表结构设计得不一样,那么查询语句就不一样。而在 Neo4js 的查询语句 cypher 中,是以 `(User) -[CREATED] ->(Post)` 这样的 模式匹配 的语句来进行查询的。这意味着,只要你能以人类语言描述本身想要的数据,你就能本身翻译成 cypher 进行查询。

除此以外,图数据固然还有不少高级特性。但对开发者来讲,模式匹配式的查询语句,才是真正革命性的技术。熟悉数据库的读者确定有这样的疑问:

其实不少 ORM 就能实现 cypher 如今这样的表达形式,但在不少大公司里,你会发现研发团队仍然坚持手写 SQL 语句,而坚定不用 ORM。理由是,手写 SQL 不管在排查问题仍是优化性能时,都是最快速的。特别是对于大产品来讲,一个 SQL 就有可能节约或者损失巨额资产。因此宁愿用 “多人力、低效率” 去换 “性能和稳定”,也不考虑 ORM。那么 cypher 如何面对这个问题?

确实,cypher 能够在某种程度上理解成数据库自带的 ORM。它很难经过优化查询语句来提高性能,但能够经过其余方式。例如对耗时长的大查询作数据缓存。或者把存储分层,图数据库变成最底层,中间针对某些应用场景来使用其余的数据库作中间层。对有实力的团队来讲,这个中间层甚至能够用相似于智能数据库的方式来对线上查询自动分析,自动实现中间层。事实上,这些中间技术早就已经成熟,结合上图数据库和cypher,是能够把传统的“人力密集型开发”转变为“技术密集型开发”的。

扯得略远了,咱们从新回到模式匹配型的查询语句上,为何说它是革命性的,由于它恰好知足了咱们以前对数据描述的需求。任何一个开发者,只要把数据字典作出来。关于数据的工做就已经完成了。或者换个角度来讲,在任何一个已有数据的系统中,只要我能在前端或者移动端中描述我想要的数据,就能开发出应用,再也不须要写任何服务器端数据接口。Facebook 在 React Conf 上放出的前端 Relay 框架和 GraphQL 几乎就已是这样的实现。

再来看逻辑部分,不管在浏览器端仍是服务器端,用什么语言,实现一个事件系统都再简单不过。这里咱们却是能够进一步探索,除了以前所说的图形界面调试,测试、监控自动化,咱们还能作什么?对前端来讲,若是先后端事件系统能够直接打通,而且出错时经过图形化的调试工具能无需回滚直接排查,那就最好了。
例如:在建立 post 的前端组件中

触发前端的 post.create 事件
 post = {title: "test", content: "test"emitter.fire("post.create").then(function(){
    alert("建立成功"catch(function(){
    alert("建立失败"

在处理逻辑的文件中:

能够增长前端专属的逻辑
emitter.on("post.create", function checkTest(post){
    ( post.title === "test"){
        console.log("this is a test blog."经过 server: 这样的命名空间来触发服务器端的事件
emitter.on("post.create", function communicateWithServer(post){
    console.log("communicating with server"return emitter.fire("server:post.create", post)
})

获得的事件栈

 

 

 

在浏览器端能够打通和服务器端的事件系统,那么在服务器端呢?刚刚提到咱们咱们其实能够用任何本身熟悉的语言去实现事件系统,那是否是也意味着,只要事件调用栈的数据格式一致,咱们就能够作一个跨语言的架构?

例如咱们能够用nodejs的web框架做为服务器端入口,而后用python,用go去写子系统。只要约定好系统间通讯机制,以及事件调用栈的数据格式,那么就能实现跨语言的事件系统融合。这意味你将来看到的调用栈图多是:

 

 

 

跨语言的实现,自己也是一笔巨大财富。例如当咱们将来想要找人一块儿协同完成某一个web应用时,不再必局限于某一种语言的实现。甚至利用docker等容器技术,执行环境也再也不是限制。再例如,当系统负载增大,逐渐出现瓶颈时。咱们能够轻松地使用更高效的语言或者执行环境去替换掉某个业务逻辑的监听器实现。

更多的例子,举再多也举不完。当你真正本身想清楚这套架构以后,你会发现将来已经在你眼前。

到这里,对“理想”的想象和对实现技术的思考终于能够划上句号了。对熟悉架构的人来讲,其实已经圆满了。但我也不想放弃来“求干货”的观众们。下面演示的,就是在框架原型下开发的简单应用。这是一个多人的todo应用。

 

 

 

前端基于react,后端基于koa。

目录结构

 

 

 

前端数据(todo 列表) /public/data/todos.js

 

 

 

前端逻辑(todo 基本逻辑) /public/events/todo.js

 

 

 

 

前端逻辑(输入@时展现用户列表) /public/events/mention.js

 

 

后端逻辑(通知被@用户) /modules/mention.js

 

 

 

经过调试工具获得的建立时的调用栈和输入@符号时的调用栈

 

 

 

这只是一个引子,目的是为了让你宏观的感觉将应用拆解为“数据+逻辑”之后能有多简单。目前这套框架已完成 50% ,实现了数据部分的设计、先后端事件融合,还有跨语言等方案正在开发中。将来将开源,期待读者关注。

终于写完了。框架只是架构的实现。这套架构几乎孕育了近两年,这其中已经开发出一款实现了部分功能,基于nodejs的服务器端原型框架。完整的框架开发目前也已经四个月了。虽然从它落地的这些前端技术、数据技术看起来,它实际上是有技术基础的,应该是积累的产物。但实际上,最先的关于数据和逻辑的思路,倒是在我读研时对一个“很虚”的问题的思考:什么样的系统是最灵活的系统?在很长一段时间内,对各类架构的学习中我都没有找到想要的答案,直到后来在学认知心理学和神经学的时候,我想到了人。人是目前能够理解的最具有适应性,最灵活的系统。人是怎么运做的?生理基础是什么?

认知心理学里提到曾经有一个学派认为人的任何行为都不过是对某种刺激的反射,这种刺激能够是来自内部也能够是外部。来自内部的刺激有两个重要来源,一是生理上,例如饥饿,疲惫。二则是记忆。例如,你天天起床要去工做,是由于你的过去的记忆告诉你你须要钱,或者你喜欢工做的内容。这对人来讲也是一种刺激,因此你产生了去工做的动机。外部刺激就更简单,例如生理上的被火烫了,心理上被嘲讽、被表扬等等。而人的反应,就是对这些刺激而产生的多种反射的集合。例如早上起床,你的一部分反射是产生上班的动机,可是若是你生病了,你的身体和记忆就会刺激你去休息。最终你会在这两种刺激下达到一个平衡,作出反应。值得注意的是,大部分时候,人在不一样时间面临相同的刺激,却作出不一样的反应。并非由于后来某些反射被删除了,而是由于后来造成了更强的反射区压制住了以前的反射。它的生理基础就是神经学中的神经递质能够互相压制。

若是咱们把要打造的系统看作一个有机体,把迭代看作生长,把用户的使用看作不断的刺激。那咱们是否是就能模拟人的反射过程来打造系统,从而期待系统获得像人同样的适应力?而偏偏你会发现科幻做品中的人工智能产品一般都以人的形态出现。由于咱们但愿咱们所使用的产品,就像人同样通情达理,具备人同样的领悟能力。而要达到这样的效果,或许就是不断给给他添加人对刺激的反射规则。

思考到这一步的时候,我对应用架构的设计哲学已经基本定型。后来验证出来的,这样的系统可以极大地提升研发效率,都只是这段哲学的附加价值。其实提升研发效率的原理很简单,不管系统的需求再怎么扩展、再怎么变动,它也是遵循人自己的思惟逻辑的。所以,你始终可使用自己就模拟人类认知的系统去适应它。而且,它怎么变化,你就怎么变化。

架构这种东西,最终仍然关注在使用者身上的。因此与其和我讨论肯定的技术问题,不如讨论这些更有意义。对思考架构的人来讲,我认为眼界和哲学高度,最重要。

尤小右:感受其实就是 flux 啊,可是 string-based global event bus 规模大了仍是会有点坑爹的。一个事件触发的后果遍布全栈,很差 track。

答:和flux的区别在于flux的数据对象自己和对数据的操做是合在store里的。事件系统规模的问题经过两个方式控制:一是命名空间。二是事件只应用在业务逻辑个程度就够了,像“存入数据库”这种操做就不要再用事件触发。这样系统就不会乱掉,由于它只反映业务逻辑。

玉伯也叫黑侠:认识心理学那段颇有趣。很关注如何让业务代码随着时间流逝不会腐化而会趋良?好比事件fire点,怎么才能可控又够用,而不会随着业务复杂而爆发式增加?(简单如seajs, 随着插件的多样化事件点都常常不够用)。还有如何让事件间彼此解耦?常常一个需求要添加多个监听,作得很差还可能影响其余功能点。

答:用事件去反映业务逻辑,而不是技术实现的逻辑”不仅是这套架构对于防止事件滥用的一个建议,更是它的哲学理论的重要部分。遵照它,这套框架就能把高可扩展性和高可维护性发挥到极致。咱们用一个常见的例子来讲明这一点。有时候面临需求变动,咱们会以为难搞,会对产品经理说:“你这个变动影响很大,由于个人代码中xxx不是这样设计的”。而产品经理有可能不理解,由于对他来讲,变动的需求可能只是一个很简单的逻辑,加上一点特殊状况而已。产生这种矛盾的关键就在于,没有找到一种能准确描述业务逻辑的方式去组织代码。若是组织代码的方式和描述业务逻辑的方式一致,那么业务逻辑上以为改动点很简单,代码上就也会很简单。这套架构中的事件系统、包括事件拥有的顺序控制等特性,都是为了提供一种尽量合适的方式去描述业务逻辑。只有这样,才能实现代码最少、最可读、最可扩展。它自己是为描述业务逻辑而不是技术实现逻辑而生。因此只有遵照这个规则,才能获得它带来的财富。

玉伯也叫黑侠:嗯,看明白了。感受是将代码阶段的复杂性,前移到了业务系分阶段,若是系分阶段作得好,那么代码就会很优雅。反之,则很难说。进一步提一个无耻要求:怎么保证系分阶段的良好性呢?很多时候,写代码的过程,就是梳理业务逻辑的过程,写完后,才明白某个需求真正该怎么实现。

答:不太认同写代码的过程是梳理业务逻辑的过程。能够说写代码的过程是梳理具体技术实现的过程。若是一开始写代码的人连业务逻辑都不清楚,再好的技术和框架也没法防止他写出烂代码。基于事件的架构其实不是对系分的要求提升了,反而是下降了。由于只要求你理清楚逻辑,具体的实现写得再烂,以后均可以依赖事件系统架构自己的灵活性去完善的。就例如“发表文章后给全部被@的人发站内信”这样的逻辑,你可能一开始没有考虑发站内信的时候最好用个队列,防止请求被卡住。但只要你作到了最基础的把“发送站内”这个监听器注册到“发表文章”的事件上。将来就能在不影响任何其余代码的状况下去优化。实际上没有任何框架能帮你写好代码,即便DDD社区也是强调不断重构,只可能“下降让你写好代码的门槛”。这套架构就是屏蔽不少技术上的概念,用事件的方式让你只关注逻辑。

玉伯也叫黑侠:有没有一种让代码趋良的架构?可能刚开始写得乱糟糟,但随着作的需求越多,写的代码越多,总体可维护性反而会变得越好?好比先后端分层,让后端专一业务模型,通常来讲,业务模型会逐步趋于完善和稳定,前端代码也会逐步变好。用一些约束,推进代码的良性循环。这些约束,是否就是理想应用架构的精髓?这些约束是什么?多是某种要求好比测试覆盖率,也多是某种强制约束好比必须经过数据改动来更新界面。roof的约束是用事件去反映业务逻辑,但这个约束更可能是「道德」层面,而不是「法律」,好比如何防止「大事件」(一个事件里,一坨技术实现的逻辑代码)?如何让人羞于去写出糟糕的代码?

答:即便先后端分离,业务模型趋于稳定,也是靠开发者自身不断重构去实现的,要否则怎么会“趋于”稳定呢。架构只可能让人站到更好地平台上,用更好地方式去写好代码,不可能主动帮人把代码变好。文中架构就是经过屏蔽技术细节,让你关注业务逻辑的方式,让代码易理解,也让你能不影响业务地去升级技术。这套架构由于有一个清晰的事件调用栈数据结构,因此能很容易地作出相应的测试、监控工具保障代码质量。但要实现“法律”是不可能的。即便是Java、即便是领域驱动编程,也能够在它好的架构下写出各类糟糕的代码。毕竟编程仍然是一件须要创造力的工做。这就像硬币的两面,若是要实现法律,那工做自己必须是无需创造,彻底能够按照流程由机器人生产。若是要创造力,就必然会有因人而异的品质差别。

 

全能程序员交流QQ群290551701,群内程序员都是来自,百度、阿里、京东、小米、去哪儿、饿了吗、蓝港等高级程序员 ,拥有丰富的经验。加入咱们,直线沟通技术大牛,最佳的学习环境,了解业内的一手的资讯。若是你想结实大牛,那 就加入进来,让大牛带你超神!

相关文章
相关标签/搜索