${title}
Posted in #for(postedIn in postedInList) ${postedIn} #end
#bodyContent ${commentCount} comments MoreWelcome To The Block!
The Block is a free website template from Tooplate. Credit goes to Free Photos for photos used in this template.
Aliquam et augue et odio luctus posuere sit amet et nisi. Maecenas convallis, est sit amet convallis consectetur, elementum lacus, ut fermentum elit sem. Duis eu elit tortor, sed condimentum nulla. Phasellus varius posuere adipiscing. Mauris sodales dictum ullamcorper. Validate XHTML and CSS.
#@box220()pharetra id turpisLorem Ipsum Dolor
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus porta adi Piscing libero, eget elem ntum lectus varius sed.
more #end #@box220()semper nisl ac nibhDonec Tincidunt Varius
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum eu mauris id neque porttitor.
第 10 章 Web界面快速开发实践 | 67 more #end #@box220("rmb")consect adipiscing elitEtiam Gravida Sagittis
Cras eu egestas sem. Aenean mollis feugiat massa, eget pharetra nunc interdum non. Etiam euismod sem ac sem tincidunt adipiscin.
more #end #end 由于这个里面的数据是具体写的,因此就没有再进行抽象,如果这些数据是从数据库来的,那可以再进行一下抽 象,就可以用for循环直接搞定了。 关于: #pageTitle("About" "About") #@tooplateMiddleSub()About Our Company
Sed tempus nunc dolor, sit amet aliquet ligula. Ut euismod lectus vel ligula euismod id porttitor tortor placerat. Aenean tincidunt magna sit amet turpis auctor sagittis. Phasellus aliquet augue nec elit lacinia et faucibus massa scelerisque.
#end #@tooplateContent()Our Company Objectives
Morbi congue lorem sit amet odio iaculis tincidunt. Donec nibh, molestie nec pellentesque non, in diam. Class aptent taciti sociosqu ad litora torquent per conubia nostra.
Aliquam et augue et odio luctus posuere sit amet et nisi. Maecenas, est sit amet convallis consectetur, lacus ligula elementum lacus, ut fermentum elit sem et nisi. Duis eu elit tortor, sed condimentum nulla. Phasellus varius posuere adipiscing. Mauris sodales ullamcorper. Validate XHTML and CSS.
#@box330("float_l")what our customers sayTestimonial
more #end #@box330("float_r")Fusce nec felis id lacus sollicitudin vulputate. Sed vitae elit at diam vestibulum ullamcorper et nec quam. Aenean eit ut luctus sit amet, elementum quis enim. Proin tincidunt, arcu id pellentesque accumsan, neque dolor imperdiet ligula, quis viverra tellus nulla a odio. Curabitur vitae enim risus, at placerat turpis. Mauris feugiat suscipit tempus fringilla, felis in velit.
Harry - Senior Webmaster
what we doServices
Lorem ipsum dolor sit amet, consectetur adipiscing elit eget elementum lectus varius sed.
- Morbi quis lorem risus
- Suspendisse cursus
- Donec at viverra
- Proin eget purus ante 第 10 章 Web界面快速开发实践 | 69
Our Blog Posts
Vestibulum eleifend consequat laoreet. Pellentesque vel orci sapien. Duis lacus ipsum, pretium ut accumsan in, tempor nec mauris. Aenean accumsan placerat elit, sit amet faucibus ante commodo a. In et neque nibh, ac tristique dui.
#end #@tooplateContent() #@postBos("20" "Lorem ipsum dolor sit amet" "/images/tooplate_image_02.jpg" "Image 02" ["Templates","Freebie"] "148")Vestibulum adipiscing tempus elit eu condimentum. Fusce at mi felis. Etiam sed velit nibh. Nunc bibendum justo elementum auctor. Donec at magna eu neque. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia.
#end 第 10 章 Web界面快速开发实践 | 70 #@postBos("17" "Etiam gravida sagittis lacus" "/images/tooplate_image_03.jpg" "Image 03" ["CSS Templates","Web Design"] "128")Ellentesque vitae velit eu lectus rhoncus tincidunt. Phasellus dictum dignissim sapien et dapibus. Sed egestas consequat mauris, orci tincidunt sit amet. Donec pharetra porta ultrices. Sed sit amet lectus libero, at porttitor odio. Validate XHTML and CSS.
#end #@postBos("10" "Aenean vitae velit eget" "/images/tooplate_image_04.jpg" "Image 04" ["Illustrations","Graphics"] "208")Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Proin gravida ornare mauris ac lobortis. Praesent elit neque, lacinia eget interdum eu. Phasellus posuere nisl et odio egestas ac tristique justo ultrices.
#end #end 画廊: #pageTitle("Gallery" "Gallery") #@tooplateMiddleSub()Our Gallery
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus porta adipiscing libero, eget elementum lectus varius sed. Aliquam metus urna, dignissim quis posuere at, posuere eget mauris. Vestibulum laoreet sodales tellus 第 10 章 Web界面快速开发实践 | 71 nec mollis. Validate XHTML and CSS.
#end #@tooplateContent() #@gallery() #galleryBox("/images/gallery/image_01_l.jpg" "/images/gallery/image_01_s.jpg" "Nunc et tellus id risus ultrices" "Image 01" "Nunc et tellus id risus ultrices") #galleryBox("/images/gallery/image_02_l.jpg" "/images/gallery/image_02_s.jpg" "Nunc et tellus id risus ultrices" "Image 02" "Nunc et tellus id risus ultrices") #galleryBox("/images/gallery/image_03_l.jpg" "/images/gallery/image_03_s.jpg" "Nunc et tellus id risus ultrices" "Image 03" "Nunc et tellus id risus ultrices" "gb_rmb") #galleryBox("/images/gallery/image_04_l.jpg" "/images/gallery/image_04_s.jpg" "Nunc et tellus id risus ultrices" "Image 04" "Nunc et tellus id risus ultrices") #galleryBox("/images/gallery/image_05_l.jpg" "/images/gallery/image_05_s.jpg" "Nunc et tellus id risus ultrices" "Image 05" "Nunc et tellus id risus ultrices") #galleryBox("/images/gallery/image_06_l.jpg" "/images/gallery/image_06_s.jpg" "Nunc et tellus id risus ultrices" "Image 06" "Nunc et tellus id risus ultrices" "gb_rmb") #end #end 三、运行三、运行 首页 关于 第 10 章 Web界面快速开发实践 | 72 日志 第 10 章 Web界面快速开发实践 | 73 第 10 章 Web界面快速开发实践 | 74 画廊 联系我们 第 10 章 Web界面快速开发实践 | 75 四、总结四、总结 上面的完整示例展现了采用Tiny框架开发页面的完整过程,下面总结一下需要说明的一些内容: 第 10 章 Web界面快速开发实践 | 76 • 上面展示采用的模板引擎是TinyTemplate,当然也支持Velocity,但是推荐使用TinyTemplate,因为执行 速度更快、功能更强、更容易使用 • 布局支持多重嵌套,上面的示例中有两层布局,根上的解决js、css引入,标题,网站图标等部分的内容,/p age/目录中的解决网站的整体结构部分的内容,随着网站的复杂,可以做更多层的布局,使得很多页面共用 的部分都放在布局文件中 • xxx.ui.xml定义了UI组件包的内容及其依赖关系,UI引擎会自动根据ui组件包的定义对js及css进行引入、整 合、压缩。 • 整个页面只引入一个css和一个js文件,避免引入文件数太多导致的性能下降,同时提供了压缩,提升网络传 输效率(这个例子中的文件都已压缩,因此压缩率不高)。 • page文件是用来编写展示内容的页面,在显示.page文件时,有两种方式,一种是.pagelet方式,一种是.p age方式,区别在于用.page方式访问时,会渲染布局,而pagelet方式不会渲染布局,适合于Ajax方式使 用。 • 整个网站在重构完成之后,没有一段内容是重复的,真正做到Tiny框架所说的DRY原则。 • 所有对上层布局文件的修改都会对所有下层页面产生影响,真正做到Tiny框架所说的下级服从上级原则。 • 越到底层的开发人员接触的越少,真正的页面编写文件,只需要从控制层转过来的数据再利用宏去显示内容 即可,可以避免接触js,css,html等相关内容。(这一点在示例中还没有做到,毕竟示例是一个静态网站),真 正做到Tiny框架所说的减法原则,越到下面会的技能越少。 • 实际上框架也支持某个页面不服从上层布局的限制,但是我们不推荐这么做,因此这里没有展示这种用法。 采用Tiny框架制作前台,需要考虑好如下角色的协作: • 美工:用于进行界面设计,页面切分 • UI组件包开发工程师:根据功能特性,把具有不同功能特性的js,css,image等放在一个jar包中 ,并编写对应 的xxx.ui.xml文件,并设定好依赖关系,如果需要还需要编写公共的宏文件,用于方便别人使用,并隔离功 能与具体的实现,使得后续的开发工程师尽量少的接触css,js。 • 业务组件开发工程师:根据功能特性,把页面中的一些比较业务化的,封装成业务组件,最终暴露的接口是 一个名字及一些数据的输入,使得最终的界面开发工程师尽可能少的接触原生的html。 • 界面开发工程师:不关心界面展现的具体技术,利用UI组件包及业务组件开发工程师开发的组件,再加上控 制层传过来的数据来编写最终的展现页面。 通过上面的分工,使得不同的开发人员关注于不同的技术细节,从而最大化的提升最终界面开发工程师的开发效 率,同时因为有了一定的封装性,可以使得底层的变化不致于影响上层开发人员的工作成果。 第 10 章 Web界面快速开发实践 | 77 1111 软件开发杂谈软件开发杂谈 杂谈之一:技术只是成功的一点点基础条件,真正还是得靠做人杂谈之一:技术只是成功的一点点基础条件,真正还是得靠做人 话说,有位lianzi同学,水平不错,思想超前,签约阿里现在在百度实习,以前因为喷我的贴又没有啥理由,因此 告诉他离我远一点,但是最近他又回到我群里了,一直伸个大拇指,我说啥他都是大拇指,觉得怪怪的,总不是 那么个感觉,终于憋了一段时间,又恢复了正常的沟通方式,聊天实录: 【传说】杭州-悠然 18:31:13 lianzi本色终于出来了。 【传说】杭州-悠然 18:31:30 我学得这样才是你自己,你天天伸个大拇指,我都觉得不像你了。 【活跃】lianzi(756215798) 18:32:17 哈哈哈,还好,还好 【传说】杭州-悠然 18:32:52 活个本性挺好的,有时碰一下大家也理解的。 碰完了继续哥儿俩好不就可以了。 【活跃】lianzi(756215798) 18:37:22 是的 杂谈之二:让谁“爽”的问题杂谈之二:让谁“爽”的问题 看产品经理的ppt,里面有下面的一段话: 做“产品”,不外乎“要想自己爽,先让别人爽”。 永远站在用户的角度考虑问题。 细节、细节、还是细节。 根据实际情况排定优先级比确定功能更重要。 深以为然,在做Tiny框架中,框架组做Eclipse插件的同学其中做一个功能是执行器,他的方案是:开个首选 项,然后由开发人员在里面配置啥种类型的文件由哪个类去执行。于是我问,如果有好多个执行器,开发人员不 就配死了?于是他做了个功能扩展,增加一个批量导入功能,可以批量导致了。于是我问如果有100个项目,100 个开发人员,有100种 执行器,不同的项目需要的执行器又不一样,是不是就得配100次配置文件,然后花大量的 成本去分发这个配置文件,还得让程序员花大量的时间去导入这个配置文件??关键是随着项目的不断变化,用 的执行器是可变的,那么上面的这个过程就得不断进行,还涉及到一个版本维护的问题,比如有的人导入了新 的,而有的人还是旧的。这样综合起来得投多少人力物力和管理成本? 我给的方案是:在开发执行器时配置一个 执行器xml定义文件,然后工程去扫描当前项目中的执行器xml定义文件,于是工具开发人员只开发一次,每个执 行器开发人员只配置一次,真正的使用者,啥也不用管,随时都是最新可用,0工作量。 两个方案对比,工具开发者工作量小了,执行器开者工作量大了可以忽略的一点点,最终使用者,节省了大量的 工作量,关键是不会让他们觉得使用麻烦,且不会出错。 第 11 章 软件开发杂谈 | 79 杂谈之三:让程序抛错还是让程序“正确”执行?杂谈之三:让程序抛错还是让程序“正确”执行? 龙振东同学,一直在使用TinyDbRouter,也发现了里面的一些BUG,也提了许多的改进建议。由于他是把代码 拉到本地在本地改的,我建议他直接fork我们的代码,并在修改之后pull request给我们,这样,对两方都有好 处。 其中涉及到一个问题,他在QQ上问我如何处置:有些非标准SQL,SQL解析器不支持,他建议(实际上他 前期就是这么做的)在出现不支持的SQL异常的时候,改由读写分离方式去执行。 由于当时在开车,是在电话里 和他沟通的,因此就没有聊天实录了,我直接敲字敲上来吧。 悠然:由于出现了SQL解析异常,说明这个时候SQL是不标准的,有可能是适用于读写分离,有可能适用于分库分表,你不管采用哪一种方式进行处理,总有一种情况是用“错误”的方式去执行的,这样就会导致出现非用户期望的结果--而且这个时候,用户得到了看起来正常的结果--因为没有异常和错误发生,但是实际上结果是不正确的。这种处理结果比抛异常直接告诉他不支持这个功能严重得多得多,会直接害死你、害死你的老板、害死你的客户。 所以,请直接抛异常,而不是改成前面的处置方式。如果这个SQL对你非常重要,那唯一正确的办法是扩展SQL解析器,使之支持。你觉得怎么样? 龙振东:然。 他很快就完成并提交给我,下面是沟通实录: 【传说】杭州-悠然 20:10:03 以后就直接在我们工程上改吧。 这样就可以一起共享了。 今天我给你电话里讲的原则,在工作中一定注意了。 否则你给捅大搂子的要:) 【话唠】龙振东(593038106) 20:11:37 一些有争议的地方我都会先提出来讨论 【传说】杭州-悠然 20:11:54 嗯嗯,我给你讲个故事吧。 我们这边有个非常牛X的人。 看到另外一个人写的程序有个问题:就直接反编译然后改了就弄上去了,结果问题确实没有了。 他也不和别人说这个事儿,结果后来升级的时候一搞,这个修改丢失了。 结果出了非常大的乱子。 又有一次,他又和另外一个程序做对接,结果他想获得人家内部的数据。 【冒泡】杭州-cwl(150326161) 20:14:07 我感觉说的是我。。。 【传说】杭州-悠然 20:14:16 人家里面的数据是private的,他改改访问控制,然后就访问到了人家的private数据。 然后他得意的爽得不行。 【话唠】龙振东(593038106) 20:14:51 后来呢 【传说】杭州-悠然 20:14:55 结果过了一段时间,又他妈的出大问题了,原来人家把private的对象改名了。 还有一次,他又是修改访问设置,访问了人家的私有方法,这次啥也没改,结果又他妈的不行了。 死活无法跑,结果这牛叉人物到现场,跑北京搞了好几天,终于查清了,原来是在Oracle JDK可以突破安全访问私有方法,但是在AIX下的IBM JDK突破不了了。 第 11 章 软件开发杂谈 | 80 所以:千万不要耍小聪明,会吃大亏的。 在计算机领域一定要严谨,要按常规的正常途径来解决问题。 杂谈之四:再论缓冲相关代码的演变杂谈之四:再论缓冲相关代码的演变 本人写过一篇关于缓冲方面的文章,可以通过点击上面的链接去查阅。有许多人回复,有些人觉得不错,有的人 觉得不好,各说各有理。 其实计算机领域当中,解决一个问题,可以有N种方案,有时他们的差别非常小,这个 时候就需要仔细斟酌了。 这不,周末大家又问了: 【活跃】lianzi(756215798) 10:03:18 早,现在不知道看什么技术文章啦,昨晚睡觉前看了篇悠然和hasor的博客 就是那篇缓存重构调优的 逻辑是很清楚的,至于最优解,鬼知道 【传说】杭州-悠然 10:05:45 下面不是被喷了么:) 【活跃】lianzi(756215798) 10:07:19 好吧,那最后的优化方案是什么呢?实际效果如何呢? 【传说】杭州-悠然 10:07:40 实际,我们用得感觉还不错。 maven插件? 【传说】杭州-悠然 10:07:58 关键是避免程序员参与缓冲方面的事情。 由于通过Maven插件动态嵌入代码,因此性能方面也非常有保障。 【活跃】lianzi(756215798) 10:08:52 这个说法,我觉得,要看场景 如果小弟不怎么给力是好事,但是程序员在调试代码的时候怎么办?至少内置个http server 有个缓存的dashboard 你觉得呢? 【传说】杭州-悠然 10:09:46 其实你可以理解成一种AOP处理。 程序调试代码,就是全部从真实数据库取数据呀。 又没有任何影响,用Maven命令处理过,只是通过缓冲加速了而已。 【活跃】lianzi(756215798) 10:10:57 我的意思是这样子的,缓存应不应该对程序员透明 【传说】杭州-悠然 10:11:28 我们的选择是透明。 【活跃】lianzi(756215798) 10:11:39 认同 【传说】杭州-悠然 10:11:48 文章中说了诸多好处,尤其是一种缓冲方案换成另外一种缓冲方案的时候。 关键是避免程序员参与缓冲方面的事情。 【活跃】lianzi(756215798) 10:12:02 是,逻辑清晰 【传说】杭州-悠然 10:12:07 选择透明的方式,只要架构师或高程完成就好了,原有代码不用做修改。 第 11 章 软件开发杂谈 | 81 【活跃】lianzi(756215798) 10:12:19 我们老大也经常骂我,说要把故事讲完整 【传说】杭州-悠然 10:12:25 上次我们从MC->Redis,那代码改得,都吐血了。 【活跃】lianzi(756215798) 10:12:53 没做抽象层? 【传说】杭州-悠然 10:13:01 如果再从Redis->另外的方案,不是又要吐血了? 【潜水】上海-云卷江南(25269626) 10:13:08 改个实现类不就行了 【传说】杭州-悠然 10:13:31 如果你做了抽象层,使用的就一定是KV的。 如果要深层次使用,就麻烦了,有的支持有的不支持。 但是技术肯定是双刃剑,有好处也有坏处。 【活跃】lianzi(756215798) 10:14:53 这个我理解 【传说】杭州-悠然 10:15:06 如何发挥好处,避免坏处了。 即使是搞了抽象层,我在文中也写了,到处是处理缓冲逻辑的代码,也是不好的。 【潜水】上海-云卷江南(25269626) 10:15:43 简单用 【传说】杭州-悠然 10:15:53 所以,比较好的办法就是采用面向切面的方式进行处理。 【活跃】lianzi(756215798) 10:17:25 这个我认可,一开始设计的就有问题 这里,又是我经常说的一个话,好软件是“品”出来的,当一个问题有N种解决方案的时候,就要把各种方案仔 细品味。 杂谈之五:新人心态的问题杂谈之五:新人心态的问题 【活跃】lianzi(756215798) 10:20:14 每每看到oscer说刚毕业的学生会什么的时候,我都在思考,应该多向前辈学习,但心里总有点不爽 哈哈,也许是初生牛犊不怕虎吧 【传说】杭州-悠然 10:23:25 不知我的故事,有没有给你讲过。 我刚毕业的时候,第一个网名起的是叫高手来着。 【活跃】lianzi(756215798) 10:23:48 没呢,然后呢 【传说】杭州-悠然 10:24:03 当时心态估计和你差不多,总觉得你毕业多几年有个啥用,我照样比你强。 后来过了一段时间,默默改成:学习中的高手 又过了一段时间,默默改成:学习中的低手 到现在,哥已经不敢说哪一块是NB的了,觉得啥也了解不够深入。 第 11 章 软件开发杂谈 | 82 【潜水】上海-云卷江南(25269626) 10:25:15 我也毕业不久 【活跃】lianzi(756215798) 10:25:23 悠然,我觉得我还算虚心好学 【传说】杭州-悠然 10:25:43 嗯嗯,不错的苗子。 【潜水】上海-云卷江南(25269626) 10:25:44 事实就是很多人经验根本和能力没什么正相关 【传说】杭州-悠然 10:26:18 你要知道,在战场中打得猛的,打得准的,都已经死掉了。 【潜水】上海-云卷江南(25269626) 10:26:34 越来越谦虚是因为自己无知,而不是队友强大 【传说】杭州-悠然 10:26:57 偶尔有几个活下来的,那就英雄了。 活下来的,都已经不再标榜自己打得准,躲得好,只是说:运气好一点而已。 所以,年轻人么,适当藏一下锋芒是有益于发展的。 【活跃】lianzi(756215798) 10:28:48 悠然说的很对啊 【传说】杭州-悠然 10:29:23 你看看所有获奖感言当中,没有哪一个说:因为我NB所以,我才... 而感谢这个,感谢那个,感谢边边角角的人物。 【活跃】lianzi(756215798) 10:29:39 浸染了奋斗的泪泉,腮边了牺牲的血雨 【传说】杭州-悠然 10:30:04 一个用来展示自己的感恩之心,二来是因为这些人的成功不一定主要是边边角角人的功劳。 但是如果让他们不爽了,他们一个小小的“失误”就可以废了你的大好前程。 你再NB,做的东西,也不可能一点瑕疵也没有。 【潜水】上海-云卷江南(25269626) 10:31:18 好高深的样子 【传说】杭州-悠然 10:31:19 当你有一点瑕疵,就会被人攻击致死。 【活跃】lianzi(756215798) 10:31:22 山水有相逢,悠然的却是管理者的心态,悠然悠然啊 【传说】杭州-悠然 10:31:32 我再给你讲一个例子。 有一个以前阿里的架构师,水平,那是一个高。 用他的话来说:除了看我感觉顺眼点,其他没有一个他会看在眼里的。 【活跃】lianzi(756215798) 10:32:55 很高的评价,这个人有问题,我觉得 【传说】杭州-悠然 10:33:06 但是因为锋芒太盛,被剥得人无一个,枪无一条,完了还让人家说他水平太差。 所以,别标榜自己水平多好,能力多强,扎扎实实做事,老老实实做人才是正点。 第 11 章 软件开发杂谈 | 83 杂谈之六:工作年限与水平的关系杂谈之六:工作年限与水平的关系 【活跃】lianzi(756215798) 10:37:47 这个我觉得和经验关系更大 【吐槽】上海 浩子(120195645) 10:38:49 什么事情,都应该与实际进行权衡 【传说】杭州-悠然 10:39:02 所以比较拽的架构师,可以把工作并行起来。 就是说大家各做做的,到时可以组到一起来,又不费什么工作量。 【活跃】lianzi(756215798) 10:39:29 为什么呢?因为踩过的坑比较多是吧双击查看原图 【传说】杭州-悠然 10:39:36 当然,这个层次就有点高了。 【活跃】lianzi(756215798) 10:43:05 这个我认,现在还是学习阶段,多踩坑吧 【传说】杭州-悠然 10:43:49 当然,这里的经验,不等同于工作年限。 但是同样努力用心的两个人,工作三年和工作一年,差别还是非常大的。 【活跃】长沙-Sept() 10:45:13 体系是自底向上构建出来是 最终的表现 始终受到基础影响 基础构造决定啦 最终的极限与瓶颈 【活跃】lianzi(756215798) 10:46:12 恩恩,说得好 【传说】杭州-悠然 10:46:16 所以,我有个说法,就是工作3,5年说做一个多么先进的框架还是为时尚早的,当然试验性的没有问题。 【活跃】长沙-Sept() 10:46:22 @lianzi 基础构造的限制 可以说已经决定 结果最高极限 了 【传说】杭州-悠然 10:47:11 因为,你局部的实践能力和技术的应用能力应该是有的,但是整体宏观视野肯定是有不足的。 这个你去看人家的框架,也只是看得外部,内在的一些因果关系,根本不清楚的,有一定理解也是不完备的。 用Sept的话来说,你的起点决定了你的终点。 你期望说后面再去补充,这个成本是非常高的。 就好象你想盖个大楼,前面没太想好,就直接上手盖,期望中间进行不断修正就可以盖出大楼来。 但是到最后的时候,发现根本没有办法进行调整好让它转向正确的方向。 细细品味! 第 11 章 软件开发杂谈 | 84 1212 框架2.0的设计梳理框架2.0的设计梳理 前面从各个角度,讲了大概11篇了。言归正传,这里讲解一个完整的框架设计实例。这里不是一个空白的描前面从各个角度,讲了大概11篇了。言归正传,这里讲解一个完整的框架设计实例。这里不是一个空白的描 述,而是基于V1.0之后的建构。因此,整个设计过程,也会尽量少走一些弯路。一起来看看吧!述,而是基于V1.0之后的建构。因此,整个设计过程,也会尽量少走一些弯路。一起来看看吧! 方法论方法论 方法论决定了可以达到的高度 方法论,就是人们认识世界、改造世界的根本方法。 它是人们用什么样的方式、方法来观察事物和处理问题。概括地说,世界观主要解决世界“是什么”的问题,方 法论主要解决“怎么办”的问题。 方法论是一种以解决问题为目标的体系或系统,通常涉及对问题阶段、任务、工具、方法技巧的论述。方法论会 对一系列具体的方法进行分析研究、系统总结并最终提出较为一般性的原则。 方法论也是一个哲学概念。人们关于“世界是什么、怎么样”的根本观点是世界观。用这种观点作指导去认识世 界和改造世界,就成了方法论。 方法论是普遍适用于各门具体社会科学并起指导作用的范畴、原则、理论、方法 和手段的总和。 Tiny框架有着完整的方法论基础,在方法论的基础上构建了完整的框架构建、扩展、利用体系。 设计理念设计理念 设计理念决定了设计的目标 使用灵活:可以整个使用它,也可以只用它的一个或几个部分。Tiny构建者认为,一个完整的框架可能需要有许 许多多个部分组成,但是对于实际应用的用户来说,它可能只需要其中的一部分功能。构架一定要有这种能 力,可以由使用者进行点菜式,使用,避免只要用一点点功能,就要引入许许多多的内容。 学习成本低、上手容易:框架的学习成本必须非常低,这样才可以让使用者更容易上手,避免由于学习难度大而导 致的学习曲线太陡、太长。 保持核心的稳定性:Tiny框架是立足于在需要稳定、安全要求非常高的应用环境中使用的,因此其稳定性就是框架 构建者首要思考目标,核心部分只使用经过充验证及广泛应用的第三方包。 资产的可积累性:只有易于知识积累,才可以真正做到越用越强。 设计原则设计原则 设计原则解决目标冲突时的解决策略 第 12 章 框架2.0的设计梳理 | 86 约定优于配置原则-COC 不要重复你自己原则-DRY 减法原则 :减法原则是我们自己提出的,意思就是给程序员做减法。 模块化原则 :模块化对于软件开发过程中开 发、高度、集成、发布、维护过程中所起的作用及节省或花费的巨大成本。因此提出了Business Unit的概 念,使得与模块相关的所有内容都可以放在一起。 自动组装原则 :在整个Tiny框架的构建过程中,都非常注重集成过程的自动组装,要求做到扔进去不用管,由框架 自动集成。 下级服从上级原则 :Tiny框架则从框架层级做了限制,使得下级必须服务上级。 单一原则 :通过单一原则进行强制性的约束,使得一个模块只解决单一模块应该解决的问题,从而避免不同的问题 放在一起解决所导致的胡子眉毛缕不清的问题,同时也避免了不恰当的依赖及模板引用。 集中配置原则 :在Tiny 框架我们对配置做了大量的工作,一个是COC方式,如果不配,则采用系统默认的值;一个是集中原则:把需要 人工需要配置的内容都集中起来统一配置;一个是对于不需要人工干预的配置,那就集成在Jar包中,作为发布者 发布项的一部分。 生态圈生态圈 生态圈决定了是否可以持续性发展 只有形成完整的开源生态圈,开源才能生存、发展。 只有输出没有输入的模式不可能得到持续发展。 Tiny开源生态圈,包含了Tiny框架、Tiny开源组件、Tiny商业组件、Tiny技术支持、Tiny咨询、Tiny培训等,具 有较强市场竞争力和可持续发展的体系,展现了一种新的软件产业发展模式。 不管您处在生态圈的哪个位置,您都会有所付出有所收获,这正是生态圈的意义及可持续发展的动力所在。 模块化模块化 模块化能力决定了业务模块治理的优劣 Tiny框架在模块化方面进行了深入的研究和实践。 Tiny业务开发过程中的任何内容都可以放入Jar包当中去,包含Java类,静态资源,JSP等等,所以一个业务模 块是不是被工程引用,只要引入对应的Jar包,就可以引入此业务模块;只要把某个业务模块的Jar包移除就可以 彻底移除此业务模块。 Tiny框架的业务单元具有非常好的独立性、替换性和通用性。 第 12 章 框架2.0的设计梳理 | 87 热部署热部署 热部署可有效帮助提升系统的可用性 所谓热部署,就是在应用正在运行的时候软件升级,却不需要重新启动应 用。 常见的热部署方案有OSGI等框架,但是这些方案具有侵入性大,开发调试困难,使用方式固定等弊端。 Tiny框架的Bundle与普通的Jar工程没有本质区别,仅多了一个配置文件。所以,它即可以作为普通的Jar包使用 也可以作为热部署的Bundle来进行使用。 流程引擎流程引擎 流程引擎提供了非编程性开发的能力 所谓流程引擎,就是对通过流程化的方式来进行业务、页面、工作流程的编 排支持的开发框架。 Tiny框架提供了业务流、页面流、工作流(正在实现中)等三种流程编排引擎,可以方便的进行业务流、页面 流、工作流领域的开发。 强大的可视化流程设计工具,可以便捷的进行流程设计。 第 12 章 框架2.0的设计梳理 | 88 WEB展现WEB展现 WEB展现是互联网应用中重中之重 Web应用开发是J2EE领域的重要问题领域 Tiny框架提供了强大的WEB层的扩展和UI组件支持,对于WEB静态资源放入Jar包,CSS合并压缩、JS合并压缩 等方面都有良好支持。对于不同角色的开发者之也可以进行良好角色划分,使得开发过程更加高效有序。 领先的模板引擎提供的一些独特特性使得可以更便捷的进行展现层开发。 第 12 章 框架2.0的设计梳理 | 89 组件库组件库 面向组件的开发是效率与质量的保证 组件化编程的关键目的是为了将程序模块化,使各个模块之间可以单独开 发,单独测试。组件的提取、管理与利用是面向组件开发的关键。 Tiny框架中,组件无处不在,有些组件框架中已经默认嵌入,有些组件就需要自己手工纳入。当然,一些愿分享 组件的同学也可以发布自己的组件让别人使用。 组件化有助于推动企业资产的积累与高水平开发人员工作成果的复用,这个在现在这个讲究协作的竞争体系中尤 为重要。 1 ├── org.tinygroup.jquery必须使用的jquery包 2 ├── org.tinygroup.publicComponentTinyUi特有资源(基础-必须依赖基于bootstrap) 3 ├── /webapp/compatibility(特殊)compatibility针对各浏览器兼容性特有资源 4 ├── org.tinygroup.bootstrap使用bootstrap最新v3.3.4 5 ├── org.tinygroup.gridSystems栅格系统(布局) 6 ├── org.tinygroup.compose排版(一般都能用到) 7 ├── org.tinygroup.code代码 8 ├── org.tinygroup.table表格 9 ├── org.tinygroup.form表单 10 ├── org.tinygroup.button按钮 11 ├── org.tinygroup.picture图片 12 ├── org.tinygroup.icon图标 13 ├── org.tinygroup.animation动画 第 12 章 框架2.0的设计梳理 | 90 14 ├── org.tinygroup.buttonGroup按钮组 15 ├── org.tinygroup.navigation导航 16 ├── org.tinygroup.dropDown下拉菜单 17 ├── org.tinygroup.unslider幻灯片 18 ├── org.tinygroup.tab选项卡 19 ├── org.tinygroup.labelBadge便签与标号 20 ├── org.tinygroup.thumbnails缩略图 21 ├── org.tinygroup.alert警告 22 ├── org.tinygroup.progress进度条 23 ├── org.tinygroup.modal弹出框 24 ├── org.tinygroup.customerService客服 25 ├── org.tinygroup.toTop返回顶部 26 ├── org.tinygroup.example案例 27 ├── org.tinygroup.rolling滚动 28 ├── org.tinygroup.search搜索 29 ├── org.tinygroup.ad广告 30 ├── org.tinygroup.tags标签 31 ├── org.tinygroup.fold折叠 32 ├── org.tinygroup.maskBar遮罩 33 ├── org.tinygroup.comment评论列表 34 ├── org.tinygroup.syntaxhighlighter代码高亮 35 ├── org.tinygroup.dataTablesDataTables数据表格 36 ├── org.tinygroup.mmGridmmGrid数据表格 37 ├── org.tinygroup.superBoxsuperBox图片列表 38 ├── org.tinygroup.zoomPiczoomPic图片列表 39 ├── org.tinygroup.Smart-navigation导航集合 40 ├── org.tinygroup.Smart-treeview树形菜单 41 ├── org.tinygroup.highChartshighCharts图表 42 ├── org.tinygroup.voteCharts投票图表 43 ├── org.tinygroup.pieCharts饼状图比例分布图 44 ├── org.tinygroup.bootstrapDate日期控件 45 ├── org.tinygroup.uedTipsUED提示 46 ├── org.tinygroup.loginRegistered登录注册 47 ├── org.tinygroup.trumbowygTrumbowyg编辑器 48 ├── org.tinygroup.UEditorUEditor编辑器 49 ├── org.tinygroup.fullCalendarfullCalendar日程表 50 ├── org.tinygroup.emailTemplate邮件模版 51 ├── org.tinygroup.error404错误404 52 ├── org.tinygroup.error500错误500 53 ├── org.tinygroup.searchPage搜索页 54 ├── org.tinygroup.interfaceElements界面元素 55 ├── org.tinygroup.forum论坛页 56 ├── org.tinygroup.timeline时间轴 57 ├── org.tinygroup.iconTab图标控制选项卡 58 ├── org.tinygroup.userComment用户评论 第 12 章 框架2.0的设计梳理 | 91 59 ├── org.tinygroup.tabShowTabs展示 60 ├── org.tinygroup.viewsControl视图控制 开发工具开发工具 开发工具是软件工程方法的延伸 不用Tiny开发工具你可以完成所有基于Tiny框架的开发工作。 用了Tiny开发工具你可以更快的完成基于Tiny框架的开发工作,效率提升5倍不是想象。 这,就是开发工具的意义。 模板语言编辑器 流程编辑器 第 12 章 框架2.0的设计梳理 | 92 可视化界面编辑器 还有许多不再一一贴图。 第 12 章 框架2.0的设计梳理 | 93 1313 开源与中小型软件公司的未来趋势开源与中小型软件公司的未来趋势 在我的周边朋友身边就发生过这样的事情: 故事1:故事1: A君在北京从事Java开发好多年了,萌发了创业的念头,想组建了一个开发团队想大干一场。但是慢慢发现,构 建一个有战斗力的团队真不容易。后来技术团队的组建初步有了起色,但是技术路线却非常难成一致意见。折腾 来折腾去,把有点上道的技术人员都折腾得跳槽了。费了巨高的成本搞了一个架构师,就是利用SSH框架搭建了 一个开发环境,数据量小,业务初期还是不错的,但是当业务快速增长的时候,运行速度就无法满足需要了。是 重新来过还是在SSH的基础上继续折腾,非常难以抉择! 故事2:故事2: Jenny从英国回青岛大半年了,很喜欢青岛这座海滨城市,空气很好,周围的一草一木也很亲切,这也是当初为 什么回来的原因之一。不过,Jenny一直在为产品管理的事情焦头烂额。除了开发成本高,软件层次一直比较 低。产品团队管理之外,还要考虑技能水平、分工、角色岗位、薪酬、性格特点等等,各方面都耗费了大量的时 间。由于缺乏大规模的压力测试,花了大量时间做出来的产品,却不能适应海量数据下的大并发访问。想找一些 高手吧,在软件业本来就不发达的二线城市又不太现实;离开二级城市转到一级城市发展吧,又承担不起高额的 运营成本与人力资源成本,路在何方真的是个问题! 故事3:故事3: 经过大半年的筹备,阿灿的技术团队终于组建起来了。不过,人员流动始终是个挥之不去的话题。换了人,技术 方案就要换,随之而来的维护问题也是让人焦头烂额!阿灿沮丧了,他怎么也想不明白,为什么新来的人就不愿 意继续在老人留下来的系统上进行维护和再开发呢?如果才能建得起来铁大的营盘? 类似的故事,不胜枚举。总结一下问题出在如下几个方面: 1. 人员培养速度缓慢1. 人员培养速度缓慢 从人力资源团队的角度来讲,更多考虑人员的职业道德是否符合企业文化和价值观。而软件开发项目经理更多考 虑的是,新成员是否能够为软件开发项目做出贡献,并符合项目文化和价值观。如果你的软件开发团队都不是自 己亲手组建起来的,你又如何能够保证软件开发团队能够按你期望的模式运作?应聘人员通过各种认证,仅仅代 表具备了基本的知识体系和理论基础。但任何认证都无法真正体现出每个人的学习能力和应用知识的能力,而这 两点恰恰是软件开发项目最关心的技能。尤其是,要成为一个优秀的软件架构师,往往需要具备10年以上的软件 开发经验,入门的门槛是相当高的,尤其是在互联网产品愈发重要的当下,一个软件架构师往往需要掌握多项技 能,他所需要的知识面会很广,需要过程更需要时间的学习和磨练。 第 13 章 开源与中小型软件公司的未来趋势 | 95 2. 人员开发效率低下2. 人员开发效率低下 一个产品往往需要多个部门的合作,各部门沟通的有效性直接会影响到产品的质量和产品的进度。如果技术开发 人员没有良好的交流沟通能力,可能会严重阻碍项目的推动。尤其是小型的团队开发中,缺乏沟通往往会导致成 员对任务内容、要求和职责理解有误,导致开发效率低下,甚至引发成员间的矛盾。开发人员如果不能清楚地表 达工作计划、遇到的困难、需要什么支持,会导致项目负责人无法及时掌握项目进展情况,并进行合理分配资 源。在工作中时常会发生别人(通常是上级)征询意见时不知如何表达,但被分配具体工作后又觉得自己未被尊 重,从而产生挫折感。技术开人员大多思维能力强于交流沟通能力,性格也大多趋向于内向,喜欢做事多于说 话。如何提高自身沟通交流能力是摆在很多开发人员面前的一大难题。 3. 技术架构不统一没有延续性3. 技术架构不统一没有延续性 作为设计师,需要保证产品功能的现实,产品功能的可持续性,产品的稳定性及产品的可用性等。产品的这些需 求都依赖于架构师对产品技术的规划。架构师在接到商业需求之后,最主要的工作就是将其转化为技术需求。这 个过程的完成与架构师抽象思维的能力密不可分。好比说Tiny框架这个项目,主架构师第一个闪过的念头多半就 是:这个系统必须具有长期的统一性。而负责每一个Tiny框架功能的架构师,又需要对这些部分进行进一步的抽 象化。这些往往是中小企业团队所不具备的。由于缺乏优秀的架构师,导致团队在产品的现实规划上没有自己明 确的目标和具体的可行性实施方案,缺乏统一的延续性,导致后期难以满足产品在升级、改版方面的需要。 4. 性能不能满足运营要求4. 性能不能满足运营要求 整天只知道大谈“云计算,SaaS”这些东西的团队,注定开发不出优秀的产品。这种毛病在新的开发团队非常常 见,因为这可以忽悠更多的客户。不过,新的技术虽好,程序员接受和再培训还需要时间,还要考虑到系统的兼 容性问题。因此,夸夸其谈的名词专家,往往死得更惨。尤其是出现大并发的数据考验时,做出来的产品往往会 难以满足运营要求。 5. 构建开发框架成本太高无法承受5. 构建开发框架成本太高无法承受 时下各种软件系统发展越来越复杂,尤其是框架软件,其涉及的问题以及知识面太多。当网站变大后,不可避免 的需要拆分应用进行服务化,以提高开发效率,调优性能,节省关键竞争资源等。当服务越来越多时,服务的UR L地址信息就会爆炸式增长,配置管理变得非常困难,F5硬件负载均衡器的单点压力也越来越大。当进一步发 展,服务间依赖关系变得错踪复杂,甚至分不清哪个应用要在哪个应用之前启动,架构师都不能完整的描述应用 第 13 章 开源与中小型软件公司的未来趋势 | 96 的架构关系。接着,服务的调用量越来越大,服务的容量问题就暴露出来,这个服务需要多少机器支撑?什么时 候该加机器?等等……在遇到这些问题时,开发成本往往会正比例飞速增长,甚至让中小企业团队无法支撑。 想要减少开发工作量或是缩短时间,降低成本,使用框架便是一个很好的选择。尤其是,使用质量好且有延续性 的开源框架正在成为主流! 1. 节省团队时间和精力1. 节省团队时间和精力 框架节省了我们不少的时间,并且让扩展变得更容易。由于拥有完整的生态体系,以及活跃的社区氛围,使得团 队战斗力更强!由于框架强制使用公共的约定,因此它能有效地解决一些共有的问题。框架能够让工作更连 贯,也能避免我们写一大堆自定义模块来实现某些性能,我们所需要做的,就是将这些共用模块放在框架中实 现。以Tiny框架为例,一年的开发就需要提交数千个Commits,解决了无数个疑难杂症。此外,从文档维护的角 度来看,一年900多页的文档内容,也能够帮助开发团队解决许多难题。 2. 技术支撑更有保障2. 技术支撑更有保障 优秀的开源框架,通常具有高内聚、低耦合、高质量的代码,专职的团队,可以保持项目持续不断的前进。还是 以Tiny框架为例,Tiny主工程共有621个Issues,里面有需求,和改进,有BUG。由于有良好知识积累体系,使 得使用Tiny框架的人们越用越强,越用越爽!相当于有一个强大的后援团队在为你的项目服务。这些优点,不胜 枚举。当A君在青岛的海边悠闲地喝着咖啡时,完全不用担心客户的跟踪电话了。 3. 成本更低,附加值更高3. 成本更低,附加值更高 在优秀的开源框架体系里,由于顶层设计避免了重复劳动,所有软件参与者都会避免做重复的事情。尤其是对于 个体或小型企业,很明确,光是SSH/I已经不足让你的方案看起来高大上,也不足以支持业务数据量比较大的时 候的应用场景,也不足以支撑居高不下的软件开发实施成本。在优秀的开源框架开发团队里,整个团队配置往往 更加合理,高低水平者各司其职,使得运营成本更低、附加值也更高。以Tiny为例,正在构建的Tiny生态圈,上 百个UI组件及流程组件已经足够你日常使用,还会有更多被不断加入,这些完全就是超值服务了! 总之,使用质量好有延续性的开源框架,基于开源框架做应用是未来中小型软件公司的发展趋势,你将获得更加 超值的回报! 第 13 章 开源与中小型软件公司的未来趋势 | 97 1414 教计算机程序解数学题教计算机程序解数学题 周末,看关于专家系统方面的书,其中有关于规则方面的内容,忽然就想,能不能模仿人的学习方式来提升计算 机程序的计算能力呢? 试想,一个小孩子,他一开始什么也不会,首先,你要告诉他什么是数字,然后告诉他什么是加、减;然后告诉 他什么是乘、除,还要告诉他有乘、除要先计算乘除,然后又引入了括号说,有括号永远要先计算括号。如 此,随着告诉他的技能越多,他的解题能力也就越强。 于是就想着试验一下。 第一步,教计算机学习什么是数字。第一步,教计算机学习什么是数字。 下面的正则表达式,就是告诉“孩子”,数字就是前面可能有“-”号,当然也可能没有,接下来连续的数字 0-9,组成的数字,后面可能还会有小数点开始加一堆0-9的数字,当然没有也没有关系。如此,它就算懂得认 数字了。 public final class MathNumber { private MathNumber() { } public static String numberPattern = "[-]?[0-9]+([.][0-9]*)?"; public static Pattern pattern = Pattern.compile(numberPattern); public static Matcher match(String string) { Matcher match = pattern.matcher(string); if (match.find()) { return match; } throw new RuntimeException(string + " is not a number."); } } 第二步就是告诉“孩子”,计算数学题的过程。第二步就是告诉“孩子”,计算数学题的过程。 如果两边有空格就忽略它,然后呢,看看是不是已经是一个数字了,如果已经是一个数字,那说明就算出结果 了。如果不是,就从最高优先级找起,如果找就就计算。如果找不到,说明这个式子有问题,不是一个合法的数 学式子。 public static String eval(String string) { string = string.trim(); while (!isMathNumber(string)) {// 同一优先级的哪个先找到算哪个 System.out.println("求解算式:" + string); boolean found = false; for (MathInterface math : mathList) { Matcher matcher = math.match(string); if (matcher.find()) { 第 14 章 教计算机程序解数学题 | 99 String exp = matcher.group(); String sig = ""; if (exp.charAt(0) == '-' && matcher.start() != 0) {// 如果不是第一个数字,-号只能当运算符 sig = "+"; } System.out.println("发现算式:" + exp); String evalResult = math.eval(exp); string = string.substring(0, matcher.start()) + sig + evalResult + string.substring(matcher.end()); System.out.println(exp + "计算结果为:" + evalResult + ",代回原式"); found = true; break; } } if (!found) { throw new RuntimeException(string + " 不是合法的数学表达式"); } } return string; } 从现在开始,这孩子已经会解题思路了,不过他还是啥也不懂,他还不知道啥是加,减、乘、除啥的,没有办 法,孩子笨,只要多教他了。 下面就教他如何计算,加、减、乘、除、余、括号、指数。 addMathExpression(new Add()); addMathExpression(new Subtract()); addMathExpression(new Multiply()); addMathExpression(new Devide()); addMathExpression(new Minus()); addMathExpression(new Factorial()); addMathExpression(new Remainder()); addMathExpression(new Bracket()); addMathExpression(new Power()); Collections.sort(mathList, new MathComparator()); 由于大同小异,就里就只贴出来加法和括号的实现方式。 加法实现,它的优先级是1,它是由两个数字中间加一个“+”号构成,数字和加号前面的空格没用,不用管 它。计算的时候呢,就是用加的方式把两个数字加起来,这一点计算机比人强,呵呵,告诉他怎么加永远不会错 的。而且理解起加减乘除先天有优势。 第 14 章 教计算机程序解数学题 | 100 public class Add implements MathInterface { static String plusPattern = BLANK + MathNumber.numberPattern + BLANK + "[+]{1}" + BLANK + MathNumber.numberPattern + BLANK; static Pattern pattern = Pattern.compile(plusPattern); static Pattern plus = Pattern.compile(BLANK + "\\+"); @Override public Matcher match(String string) { return pattern.matcher(string); } @Override public int priority() { return 1; } @Override public String eval(String expression) { Matcher a = MathNumber.pattern.matcher(expression); if (a.find()) { expression = expression.substring(a.end()); } Matcher p = plus.matcher(expression); if (p.find()) { expression = expression.substring(p.end()); } Matcher b = MathNumber.pattern.matcher(expression); if (b.find()) { } return new BigDecimal(a.group()).add(new BigDecimal(b.group())) .toString(); } } 接下来是括号,括号的优先级是最大啦,只要有它就应该先计算。当然,要先计算最内层的括号中的内容。括号 中的内容,计算的时候,可以先拉出来,不用管外面的内容,计算好了,放回去就可以了。 public class Bracket implements MathInterface { static String bracketPattern = BLANK + "[(]{1}[^(]*?[)]" + BLANK; static Pattern pattern = Pattern.compile(bracketPattern); @Override 第 14 章 教计算机程序解数学题 | 101 public Matcher match(String string) { return pattern.matcher(string); } @Override public int priority() { return Integer.MAX_VALUE; } @Override public String eval(String expression) { expression = expression.trim(); return MathEvaluation.eval(expression.substring(1, expression.length() - 1)); } } 到目前为止,我们的程序“宝宝”已经学会数学计算了,出个题让伊试试。 public static void main(String[] args) { String string = "1+2^(4/2)+5%2"; System.out.println("结果是 :" + MathEvaluation.eval(string)); } 程序宝宝的做题过程如下: 求解算式:1+2^(4/2)+5%2 发现算式:(4/2) 求解算式:4/2 发现算式:4/2 4/2计算结果为:2.00,代回原式 (4/2)计算结果为:2.00,代回原式 求解算式:1+2^2.00+5%2 发现算式:2^2.00 2^2.00计算结果为:4,代回原式 求解算式:1+4+5%2 发现算式:5%2 5%2计算结果为:1,代回原式 求解算式:1+4+1 发现算式:1+4 1+4计算结果为:5,代回原式 求解算式:5+1 发现算式:5+1 5+1计算结果为:6,代回原式 结果是 :6 第 14 章 教计算机程序解数学题 | 102 呵呵,程序宝宝的做题过程和人的做题过程非常一致,而且程序实现也非常简单易懂。神马编译原理,神马中缀 表达式都用不上。(执行效率与其它算法比较不一定高,仅用于验证通过规则让程序的处理能力增强,由于没有进 行深入测试,正则表达式和程序逻辑是否写得严密没有经过深入验证) 其实程序虽然很简单,但是,实际上已经是一个简单的规则引擎的雏形。 首先,他加载了许多的业务处理规则,加,减,乘,除,插号,指数,余数等等。 第二,他的业务规则是可以不断进行扩展的。 第三,只要给出事实,最后,他通过规则的不断应用,最后会导出结果,要么是正确的结果,要么说给出的事实 是错误的。 需要源码的童鞋请到GIT上直接获取代码。 git地址:http://git.oschina.net/tinyframework/mathexp.git 第 14 章 教计算机程序解数学题 | 103 1515 借船下海还是造船下海借船下海还是造船下海 1.借船与借力1.借船与借力 三国时期,曹操率大军想要征服东吴,孙权、刘备联合抗曹,“草船借箭”即来源于此,意即运用智谋,凭借他 人的人力或财力来实现自己的目标。我们来看看这个故事的几个关键环节。 为了筹集十万支箭,诸葛亮找到鲁肃。诸葛亮说:“这件事要请你帮我的忙。希望你能借给我20只船,每只船上 30个军士,船要用青布慢子遮起来,还要一千多个草把子,排在船两边。”第三天四更时候,诸葛亮邀请鲁肃一 起,把船用绳索连起来向曹操对岸开去。那天江上大雾迷漫,对面都看不见人。当船靠近曹军水寨时,诸葛亮命 船一字儿摆开,叫士兵擂鼓呐喊。曹操以为对方来进攻,又因雾大怕中埋伏,就派六千名弓箭手朝江中放箭,雨 点般的箭纷纷射在草把子上。过了一会,诸葛亮又命船掉过头来,让另一面受箭。 太阳出来了,雾要散了,诸葛亮令船赶紧往回开。这时船的两边草把子上密密麻麻地插满了箭,每只船上至少 五、六千支,总共超过了十万支。鲁肃把借箭的经过告诉周瑜时,周瑜感叹地说:“诸葛亮神机妙算,我不如 他。” 2.顺势而为2.顺势而为 “明者因时而变,知者随事而制”这个用典,出自汉代桓宽《盐铁论》卷二之枕边第十二篇。汉宣帝的中兴之 道,得益于诸多方面,根本的一条就是“明者因时而变,知者随事而制”,了解民情,把握趋势,与时俱进,开 放而谋实。同样,作为开发团队,在互联网竞争时代,也要干很多事。有些事很顺利,有些却坎坎坷坷的,有些 根本就干不成。细想一下,事情的成败原因可以归结为一个字,势,顺势而为,如水推舟,事半功倍;逆势为 之,则逆水行舟,艰难险阻,功败垂成。 势是什么,就是一种趋势,一种方向,一种潮流。顺势而为,关键在于一个“势”字,要有一双慧眼,判明大势 进退;要有一颗名亮亮的新,悟达通透。做到“顺势而为,乘势而上”。 3.框架开发的“借力”与“顺势”3.框架开发的“借力”与“顺势” 基础的框架开发并不难,但是要想做得优雅、健壮并不容易,要做出一个好的框架往往会花费大量的时间、人力 财力。衡量一个框架是否优秀,往往有这些考量因素。 • 清晰的代码库,简单易用。代码复用是把一个功能写成一个模块,以便当再次需要相同功能的时候,可以直 接使用,而不用重新开发。举个例子,假如你的网站需要验证码,你就可以把验证码这个功能单独提取出来 以便复用。通常代码复用是通过类与对象来实现的,这也是面向对象编程与面向过程编程最主要的区别之 一。以响应式网页设计为例,实现起来并不困难,但是要让它在所有的目标设备上都正常运作会有一点小棘 手。而框架可以让这一工作变得简单。利用框架,你可以花最少的力气创建响应式且符合标准的网站,一切 第 15 章 借船下海还是造船下海 | 105 都很简单并且具有一致性。还有很多好处是显而易见的,比如说简单快速,以及在不同的设备之间的一致性 等等。也就是说,框架最大的“势”就是简单易用,即使只掌握少量的Web知识,你也可以毫无障碍的使用 它们。 • 粉丝使用过程的“倒逼”,强大的框架创新体系,营造良好的社区生态环境。“倒逼”是一种被动行 为,是“迫使”、“反推”等词的升级版,该词强化了反常规、逆向促动之义。时下“倒逼”正在成为美 谈,并曾经入选年度十大流行词。各行各业的问题动辄倒逼,似乎“倒逼则灵”。在许多领域,“倒逼”的 确是这样大显身手的。作为一种开源力量,“倒逼”未尝不是一种正向力量!坚实的社区基础和积累,以及 丰富的模板系统,往往可以为框架树立良好的口碑,形成一种“引力场”。尤其是需要有大量忠实的社区粉 丝,也是框架实力的最好支持。作为社区网站,也要站在运营者角度和用户角度双方面来考虑上诸多问 题。在用户角度上完善网站产品,去满足用户的核心需求,帮助用户解决问题。 • 简单的学习曲线,与相关应用集成更加容易。学习曲线的定义为“在一定时间内获得的技能或知识的速 率”,又称练习曲线(practice curves)。人们为了知道学习进程中的现象和进步的快慢的详情,作为以后 努力的指针,应用统计图的方法作一条线,把它表示出来。它源于“二战”时期的飞机工业,当产量上升 时,生产每架飞机的劳动时间会极大地下降。随后的研究表明,在许多行业都存在这种现象。同样,在框架 应用中,我们需要的不仅仅是模板,还更想要陈述式的可重用的模板框架。尤其需要能够创建可扩展的互联 网应用。 • 文档支持与引导系统。写文档不容易同时也是需要花费一些时间的。作为潜在的用户,我们第一次接触开源 项目,很可能就是通过阅读README文件。我们需要确保它很棒并且包含了有用的信息。以Tiny框架为 例,我们始终认为文档是能为用户做的最好的事了!文档不仅能够节省用户大量的时间,也可以让用户确 信,我们的确是把他们当做上帝,而且,我们是一帮有血有肉的人,不是一个产生代码的机器。 • 向后兼容,同时把握大势,对主流技术发展有一个准确的判断。关于软件开发的一件很令人生气的事,就是 当你升级一个库但是数百个测试失败了。更让我生气的就是我还要重写我一半的基础代码,因为有人在没有 任何警告的前提下决定打破公共的API。因此,向前看齐,同时致力于维护向后兼容性,也是我们重点把握的 方向。以Tiny框架为例,我们常常会关注,使用这个项目有几个月了吗?是否觉得它还是不完整的?是否希 望API在下一个版本会彻底地修改?是否在要求最多并且很老的项目中也能稳定安全的使用?当考虑到向后兼 容时,也能有一个很好的跟踪记录。 • 可延续的技术支持。有些人可能关心许可证,但是真正使用框架或库的人很关心的是有保障的后续服务和支 持。所以真正可用的框架包含了框架的可用及有保障的支持和服务,这样才能让客户在使用过程中更加放 心。 郑和下西洋,没有人关心他使用的是什么船;诸葛亮借箭,也没有人关心他使用的是谁的船。不过,他们都很轻 松的完成了自己的目的。造船下海,还是借船下海,关键还是在于顺势而为,把握大势! 第 15 章 借船下海还是造船下海 | 106 1616 缓存相关代码的演变缓存相关代码的演变 问题引入问题引入 上次我参与某个大型项目的优化工作,由于系统要求有比较高的TPS,因此就免不了要使用缓冲。 该项目中用的缓冲比较多,有MemCache,有Redis,有的还需要提供二级缓冲,也就是说应用服务器这层也可 以设置一些缓冲。 当然去看相关实现代代码的时候,大致是下面的样子。 public void saveSomeObject(SomeObject someObject){ MemCacheUtil.put("SomeObject",someObject.getId(),someObject); //下面是真实保存对象的代码 } public SomeObject getSomeObject(String id){ SomeObject someObject = MemCacheUtil.get("SomeObject",id); if(someObject!=null){ someObject=//真实的获取对象 MemCacheUtil.put("SomeObject",someObject.getId(),someObject); } return someObject; } 很明显与缓冲相关的代码全部是耦合到原来的业务代码当中去的。 后来由于MemCache表现不够稳定,而且MemCache的功能,也可以由Redis完全进行实现,于是就决定从系 统中取消MemCache,换成Redis的实现方案,于是就改成如下的样子: public void saveSomeObject(SomeObject someObject){ RedisUtil.put("SomeObject",someObject.getId(),someObject); 第 16 章 缓存相关代码的演变 | 108 //下面是真实保存对象的代码 } public SomeObject getSomeObject(String id){ SomeObject someObject = RedisUtil.get("SomeObject",id); if(someObject!=null){ someObject=//真实的获取对象 RedisUtil.put("SomeObject",someObject.getId(),someObject); } return someObject; } 这一通改下来,开发人员已经晕头晕脑的了,后来感觉性能还是不够高,这个时候,要把一些数据增加二级缓 冲,也就是说,本地缓冲有就取本地,本地没有就取远程缓冲 于是,上面的代码又是一通改,变成下面这个样子: public void saveSomeObject(SomeObject someObject){ LocalCacheUtil.put("SomeObject",someObject.getId(),someObject); RedisUtil.put("SomeObject",someObject.getId(),someObject); //下面是真实保存对象的代码 } public SomeObject getSomeObject(String id){ SomeObject someObject = LocalCacheUtil.get("SomeObject",id); if(someObject!=null){ return someObject; 第 16 章 缓存相关代码的演变 | 109 } someObject = RedisUtil.get("SomeObject",id); if(someObject!=null){ someObject=//真实的获取对象 RedisUtil.put("SomeObject",someObject.getId(),someObject); } return someObject; } 但是这个时候就出现一个问题: 由于在某一时刻修改值的只能是某一台计算机,这个时候,其它的计算机的本地缓冲实际上与远程及数据库中的 数据会不一致,这个时候,可以有两种办法实现,一种是利用Redis的请阅发布机制进行数据同步,这种方 式,会保证数据能够被及时同步。 另外一种方法就是设置本地缓冲的有效时间比较短,这样,允许在比较短的时间段内出现数据不一致的情况。 不管怎么样,功能是实现了,程序员小伙伴这个时候已经改得眼睛发黑,手指发麻,几乎接近崩溃了。 很明显这种实现方式是不好的,于是项目组又提出了改进意见,能否采用注解方式进行标注,让程序员只要声明 就可以?Good idea,于是,又变成了下面的样子: @Cache(type="SomeObject",parameter="someObject",key="${someObject.id}") public void saveSomeObject(SomeObject someObject){ //下面是真实保存对象的代码 } @Cache("SomeObject",key="${id}") public SomeObject getSomeObject(String id){ SomeObject someObject=//真实的获取 第 16 章 缓存相关代码的演变 | 110 return someObject; } 这个时候,程序员们的代码已经非常清爽了,里面不再有与缓冲相关的部分内容,但是引入一个新的问题,就是 处理注解的代码怎么写?需要引入容器,比如:Spring,这些Bean必须被容器所托管,如果直接new一个实 例,就没有办法用缓冲了。还有一个问题是:程序员的工作量虽然有所节省,但是还是要对程序代码有侵入 性,需要引入这些注解,如果要增加超越现有注解的功能,还是需要重新写过这些类,引入其它的注解,修改现 有的注解。 所以,上面是个可以接受的方案,但明显还不是很好的方案。 假如有一个程序员火大了,他发出下面的抱怨:“我只管做我的业务,放不放缓冲和我有1毛钱关系么?总因为缓 冲的事情让我改来改去,程序改得乱七八糟不说,我的时间,我的工作进度都影响了谁来管?以后和缓冲相关的 事情别他妈的来烦我!”,作为架构师的你,你怎么看?最起码,我觉得他是说得非常有道理的。我们再返过头 来看看最原始的代码: public void saveSomeObject(SomeObject someObject){ //下面是真实保存对象的代码 } public SomeObject getSomeObject(String id){ SomeObject someObject=//真实的获取 return someObject; } 这里是干干净净的业务代码,和缓冲没有一点关系。后来由于性能方面的要求,需要做缓冲,OK,这一点是事 实,但是用什么缓冲或怎么缓冲,与程序员确实是没有什么关系的,因此,是不是可以不让程序员参与,就可以 优雅的做到添加缓冲功能呢?答案当然是肯定的。 需求整理需求整理 代码当中,不要体现与缓冲相关的内容,也就是说做不做缓冲及怎么做缓冲不要影响到业务代码 不管是从容器中 取实例还是new实例,都可以同样的起作用,也就是说可以不必依赖具体的容器 第 16 章 缓存相关代码的演变 | 111 解决思路:解决思路: 放不放缓冲、怎么放缓冲、缓冲有效时间等等,这些内容是在运行期发现存在性能瓶颈,然后提交给程序员来进 行优化的。为此,我们设计了一个配置来描述这些缓冲相关的声明。 当然,这个配置文件的结构,可以根据自己所采用的缓冲框架来进行相应的定义。 比如: