Dubbo之父——梁飞技术博客拾遗(2)
充电计划
2008-01-27 https://www.iteye.com/blog/javatar-159809
在javaeye论坛里看到的, 发现这些和我现在的计划很相似, 转摘过来自勉一下, 鞭策自己以最短的时间达到这些目标, 相信自己, 加油!
- 沟通能力:包括语言(英语,白话),沟通技巧,思维条理性,倾听他人,人际关系处理,个人精神状态;
- 演讲水平:中英文演讲水平和技巧,准备工作,上台勇气,应变能力,台上镇静;
- 领导能力:集思广议,个人魅力,影响力,对人不对事的心态,从尽可能的高度看问题,有错自己背,有功大家分;
- 计划能力:大事小事作计划,处事从大局着手,尽可能的参考组员的意见,将事情大的分小,小的分细,细的得到组员的承诺, 预测出可能的结果,并留下buffer处理非常事件,常review和update;
- 时间管理:记下要做的的每件事,设定优先级,每天早上看一遍,晚上再看并总结,每月/半年/年度再总结和改进;
- 处理事件/矛盾能力:双赢思维,先人后已,站在他人的角度看问题,为他人着想,遵守明/潜规则;
- 解决问题/潜在问题:DMAIC / MEDIC,IDOV;
- 决策力:调查,数据说话,集思广议,风险评估,备用方案;
- 日常工作能力=>信心:自己的工作作好,别人的工作帮忙,三不管的工作抢来作,能力的提升不是靠看书学来的,而是实战中得到的(这就是我认同“吃亏就是占便宜”的原因),只有自己现在的工作作好了,才能产生信心,去见工时也对所见的职位抱可去可不去的心态,相反,如果太想得到了反倒发挥不出真才实学。
什么是项目与项目管理
2008-02-12 https://www.iteye.com/blog/javatar-161983
所谓项目,简单地说,就是在既定的资源和要求的约束下,为实现某种目的而相互联系的一次性工作任务。
什么是项目
一般来说,项目具有如下的基本特征:
- 明确的目标
- 其结果只可能是一种期望的产品,也可能是一种所希望得到的服务。
- 独特的性质
- 每一个项目都是唯一的。
- 资源成本的约束性
- 每一项目都需要运用各种资源来实施,而资源是有限的。
- 项目实施的一次性
- 项目不能重复。
- 项目的不确定性
- 在项目的具体实施中,外部和内部因素总是会发生一些变化,因此项目也会出现不确定性。
- 特定的委托人
- 它既是项目结果的需求者,也是项目实施的资金提供者。
- 结果的不可逆转性
- 不论结果如何,项目结束了,结果也就确定了。
制约项目目标成功的因素
- 委托人的评价
- 项目范围
- 项目成本
- 项目进度
什么是项目管理
所谓项目管理,就是项目的管理者,在有限的资源约束下,运用系统的观点、方法和理论,对项目涉及的全部工作进行有效地管理。即从项目的投资决策开始到项目结束的全过程进行计划、组织、指挥、协调、控制和评价,以实现项目的目标。
项目管理内容:
1. 项目范围管理 是为了实现项目的目标,对项目的工作内容进行控制的管理过程。它包括范围的界定,范围的规划,范围的调整等。
2. 项目时间管理 是为了确保项目最终的按时完成的一系列管理过程。它包括具体活动界定,活动排序,时间估计,进度安排及时间控制等项工作。
3. 项目成本管理 是为了保证完成项目的实际成本、费用不超过预算成本、费用的管理过程。它包括资源的配置,成本、费用的预算以及费用的控制等项工作。
4. 项目质量管理 是为了确保项目达到客户所规定的质量要求所实施的一系列管理过程。它包括质量规划,质量控制和质量保证等。
5. 人力资源管理 是为了保证所有项目关系人的能力和积极性都得到最有效地发挥和利用所做的一系列管理措施。它包括组织的规划、团队的建设、人员的选聘和项目的班子建设等一系列工作。
6. 项目沟通管理 是为了确保项目的信息的合理收集和传输所需要实施的一系列措施,它包括沟通规划,信息传输和进度报告等。
7. 项目风险管理 涉及项目可能遇到各种不确定因素。它包括风险识别,风险量化,制订对策和风险控制等。
8. 项目采购管理 是为了从项目实施组织之外获得所需资源或服务所采取的一系列管理措施。它包括采购计划,采购与征购,资源的选择以及合同的管理等项目工作。
9. 项目集成管理 是指为确保项目各项工作能够有机地协调和配合所展开的综合性和全局性的项目管理工作和过程。它包括项目集成计划的制定,项目集成计划的实施,项目变动的总体控制等。
时间管理十个习惯
2008-02-27 https://www.iteye.com/blog/javatar-165517
习惯1:收集 —— 全面收集
随身携带一个小笔记本(或者任何记录工具),用它来记录下任何任务、想法、专案或者任何闪入你大脑的其他信息。这个习惯与GTD的基本完全相同,但ZTD只需要一个小巧、便携、易用的工具来记录信息。你必需在忘记事情之前赶紧把信息写下来, 并且尽快地把这些信息从笔记本中清除、存入任务清单中。
习惯2:处理 —— 快速地对信息作出决定,从而避免收件箱堆积
收件箱中原料的堆积是造成耽搁的重要原因。只有及时处理信息,对原料及时做出决定和归纳成类,你才能避免原料的堆积。我建议至少每天处理一次收件箱,从上而下的,一项一项任务地处理,就像GTD所做的一样:二分钟法则、删除、指派给别人、归档、或者放在日程表上以后做。
习惯3:计划 —— 设定每天,每周的最重要的事(MIT)
每周,列下你需要完成的重大事件,把他们排进日程表。每天,列出1-3个最重要的事(MITs)。这样,你的每一天和每一周都被设定了目标,与其盲目的去完成那长长的任务清单,你总是在完成那些最重要最有用的事情!
习惯4:执行 —— 一心一意,每次只执行一件事
执行作为一切时间管理的核心,是ZTD中非常重要的一部分。你应当在不分心的情境下,一次只执行一件事。既不要多线工作,也不要让你的工作突然中断。
习惯5:信任的系统 —— 建立简单的列表,并每日查看
ZTD(简单做)建议你尽可能的维持列表简单化。不要增加复杂的系统,也不要持续尝试新工具,以免时间上的浪费。尽可能的使用简单的清单方式,因为你注重的是如何执行的任务,而非玩弄你的GTD系统或者GTD工具。
习惯6:管理 —— 一个存储所有信息的地方
把所有接收的信息都放入你的收集箱中,处理你的收集箱,执行任务,完成任务。在这个系统里,你永远都不应该有疑问自己下一步该做什么。而且也使你更能专心注重于工作,也避免的拖延的。
习惯7:回顾 —— 每周回顾你的系统和目标
每周回顾的重要意义在于它给了你一次机会,来重新整理所有的事情和检视什么是最重要的任务。GTD中的每周回顾已经非常棒了,简单做(ZTD)基本上仍延用它,不过添加了对目标回顾的重视度。每次只要集中于一个目标,并且确保它是一个你能完成的目标。
习惯8:简化 —— 减少你的任务清单,只留下最必要的
将你的任务列表简化到最少,只剩下最重要的任务,这样你就不需要那些复杂的计划体系了。由于GTD并不对任务进行的优先级划分,所有的任务都被添加到一份清单中,于是这份清单就变得越来越长,而你就不得不每天都疲倦地忙碌于任务完成之中。取而代之的,ZTD要求你不断地简化自己的任务清单,确定你的任务只是最重要的。
习惯9:常规 —— 设定每周、每日例程
设定每周、每日例程可以使你的工作和个人生活得到极大的简化。更重要的是,使你掌控自己的生活,而非让任务处在搁浅之中。没有日程,我们就不太容易对新进入的信息说不。因为我们总是被那些希望占用我们时间的人、吸引注意力的网站所拖住,这不是一件好事(除非你不想做完重要的事情),所以你需要掌控自己的生活,设定日程,并且跟着它走。
习惯10:激情 —— 做你充满梦想的事情
当你真正地想去做一件事,无论多么辛苦,你都会去努力的完成。你会付出更多的努力,抽出更多的时间,耽搁的时间也减少了。所以,培养这个习惯正是为了持续搜寻使你保持热情的事情,使你精神饱满,动力十足。
棋中心态
2008-03-05 https://www.iteye.com/blog/javatar-168043
昨晚回酒店后, 与同事连杀了好几盘象棋, 从棋中能隐隐感觉自己现在的心态,
最大的改进是能平静的做到契而不舍, 开盘不久就因不留神被误吃了车, 并陷住数子, 棋势立减, 但经过一翻抢救, 最后取胜. 以前经常在失势后就乱了阵脚, 乱下, 只想快点结束, 有时候甚至会直接投降. 这次心态比较平和.
最大的缺点是未做到三思而后行以及大局观不强, 常被误吃到棋, 并且只记得吃棋, 忘记根本目标:将军. 也可能是很久没下棋的原故.
FreeMarker准备在2.4版中加入新的指令#template
2008-03-05 https://www.iteye.com/blog/javatar-168468
FreeMarker准备在2.4版中加入新的指令#template, 用于上下文隔离包含模板. 与原有的#include相对应, #include为上下文内包含(内嵌)模板.
然而, 大家对这一新指令的命名都极不赞同.
首先template是一个名词, 不适合用于包含这样一个动作性指令名.
Attila Szegedi 回复的邮件 写道
Sorry for nitpicking, but shouldn’t such a directive rather be a verb?
I.e. #load, #render, #execute come to mind. Using a noun (#template) sounds as if you’re defining something (see: #macro, #function, etc.).
中间引出大量回复, 给出了n多方案, 如:
#subtemplate, #safeinclude, #load, #exec, #render, #do. #process, #merge, #embed
赞同较多的是: #render, #process, #embed
但render(渲染)与图形学上的概念混淆, 表意不清.
process(处理)太过泛化, 这个词感觉什么地方都可用.
embed(嵌入)是比较合理的. 但似乎应该与现有的include指令名换一个才恰当. 因为embed才表示在当前上下文执行, include表示包含内容(在不同上下文执行).
Daniel Dekany 回复的邮件 写道
Should I replace all application of #include with #embed in the 2.4 Manual? #include was one of the first few directives introduced (in the Getting Started chapter). I suppose now we should propagate #embed instead. Also I wonder if #include should be deprecated in 2.4.
最后结论还没出来, 但对CommonTemplate(http://commontemplate.org)的设计很有借鉴意义, 现在CommonTemplate采用inline(内联)表示同上下文包含, include(包含)表示上下文隔离包含, 似乎将inline改成embed会更合理些, 可能会在下一版本进行变更.
非转义字符串处理
2008-03-12 https://www.iteye.com/blog/javatar-170686
在C#中, 有一个字符串处理前导字符: @
表式非转义字符串, 通常用于输出文件地址, 如:
@”C:\xxx\yyy.txt” 等价于 “C:\xxx\yyy.txt”
当字符串以@前导时, 将不处理”"的相关转义, 原样输出.
CT也准备支持此功能, 但思考良久, 觉得加前导符并不怎么好.
暂时想出的方案是:
用反单引号表示非转义字符串.
如:
`C:\xxx\yyy.txt`(反单引号) 等价于 “C:\xxx\yyy.txt”(双引号) 或 ‘C:\xxx\yyy.txt’(单引号)
JSON标准元数据定义描述语言的思考
2008-03-17 https://www.iteye.com/blog/javatar-173192
最近在为XX速运公司做项目预研时, 为简化B/S开发, 需将Ext封装成Jsp Taglib,
网上已有多种封装方案, 如: exttld, 以及金蝶将Ext封装成JSF标签等,
公司原也有一套封装, 但文档不全且不太稳定, 所以决定重新封装,
通过三天的努力已基本稳定, 感谢所有开发人员的速度,
我们采用和exttld相似的与Ext一对一封装, 这样做学习成本较低, 灵活性较强(不会出现实现不了某功能), 文档也可以采用Ext已有的, 当然也对数据传输层进行了简化,
另外这样封装比较简单, 不易出太多BUG, 易于稳定, 也是现在快速封装的目标.
一阵忙碌后, 今天静下心来想了一下, 我们为什么封装?
Ext本身已经采用JSON配置方式进行了简化, 而我们做的只是转换.
最大的理由是TagLib在Jsp编辑时有自动提示, 以及静态错误检查.
因为没人记得清那些JSON配置, 而”ALT+/”是最好的提示方式.
不用打开浏览器查错也是Java开发人员期望的.
想到这, 那是不是JSON缺了什么, 导致这样无畏的转译工作?
是的, JSON缺标准的元数据定义. XML为什么能自动提示? 为什么能查错?
因为XML有DTD, 有XSD. 那为什么不给JSON也定义一套呢?
如果给JSON定义了描述语言, IDE会非常易结合,
JSON现在越来越流行, 其比XML更简洁, 便于传输,
C/S开发也开始采用JSON风格, 如: JavaFX等.
而标准的元数据定义有助于更统一, 更方便的使用.
不知有没有这样的标准在开始, 如果没有, 或许可以发起开源, 大家试着定义一套.
四代时间管理
2008-03-23 https://www.iteye.com/blog/javatar-175206
最近在看《时间管理: 要事第一》, 摘一点读书笔记.
第一代时间管理:备忘录型时间管理
这一代人把易忘的事记在便笺, 核对表等中, 随身携带. 完后一项划掉一项, 未完成的列入明天的列表中.
采用这一代管理法的人, 做事很灵活, 随机应变, 做自己认为当时看来最紧迫的事, 但经常有事情被遗忘, 忘记赴约, 忘记承诺, 没有目标, 不清楚当前为什么做这些.
第二代时间管理:计划与准备型时间管理
这一代人把计划与准备写入日历, 约会登记薄等中, 强调效率, 个人责认感, 确立目标, 事先做计划, 列出未来的所有活动和时间表, 如: 安排约会, 写下承诺, 确定最后期限, 记下开会地点等等.
采用这一代管理法的人, 对结果和承诺有更高的个人责任感, 能在会议,发言前做好准备, 做事更高效, 但是专注于时间表, 目标, 效率, 会使人陷入时间表至高无上的错觉, 身边的人都在不停的打断你的时间表, 你的”敌人”越来越多, 经常感到计划赶不上变化.
第三代时间管理:价值观型时间管理
这一代人制定各式各样的计划手册,时间管理手册等, 强调计划, 排序, 控制. 首先明确自己的价值观和优先考虑的重点, 经常问自己: “我想要什么?”, 并制订长期,中期和短期目标, 将每天的活动按优先级排序, 保持做最重要的事而不是紧迫的事.
采用这一代管理法的人, 通过重视做计划以及对事情进行安排, 个人生产率大幅提高, 并把价什观和目标做为首要事情. 但因思维定式, 经常忘记罗盘(方向), 错误的认为只要高效就能做的更好, 拿错了地图也一往直前, 并且错误的认为自己掌握了自己生活, 然而, 人们可以控制自己选择, 但却控制不了选择的结果, 控制的了自己, 却控制不了他人, 这一代管理法忽略了一个事实, 即我们大部分时间都在和他人打交道.
第四代时间管理:以原则为中心型时间管理
这一代人建立第二象限日程表, 强调要事第一, 目标与结果, 角色平衡, 向生活学习, 遵守自然法则. 掌握自己的罗盘, 而不是速度.
采用这一代管理法的人, 生活的比较有条理, 心情较平和, 能和偕处理生活中充当的各种角色, 胜任使命, 遵守原则.
资源利用与竞争策略
2008-04-06 https://www.iteye.com/blog/javatar-179880
今天刚看了“资源利用与竞争策略”
其强调突出差异与成本,
在竞争时, 要尽可能强调自身的差异, 并且差异要得到用户的认可.
否则当产品与别人没有区别或说不出区别时就应该最低成本.
当别人把你的产品模仿的维妙维肖, 你就没有了差异优势,
当别人能做的比你更便宜, 你就失去了成本优势.
联想到CommonTemplate(http://www.commontemplate.org),
相同的”轮子”很多, CT是否完全突显了其差异?
看来需要抽空进一步挖掘CT的不同点.
另外, 在这里, 成本包括使用成本, 也包括使用风险.
开源? 免费? 同类的产品大部都是.
使用方便? 集成方案是否够多?
学习成本低? 文档齐全?
产品稳定? 测试覆盖率高?
这些现在都有做, 但能做得更好, 这也是CT下一步工作的重点.
《七个习惯》读书笔记
2008-04-25 https://www.iteye.com/blog/javatar-186594
习惯是知识,技巧,意愿的交集,是一种思维定式.
思维定式影响态度与行为.
高效能习惯:
- 积极主动
- 以终为始
- 要事第一
- 双赢思维
- 知彼解己
- 综合综治
- 不断更新
成熟的定义:
成熟就是在表达自己的情感和信念的同时又能体谅他人的想法和感受的能力.
人的成熟度:
- 依赖期
- 独立期
- 互赖期
性格魅力基于人格魅力.
沟通技巧基于诚信.
学会聆听.
要想得到他人的理解, 首先要理解他人.
沟通中应避免的自传式回应恶习:
- 价值判断, 过早的下定论.
- 刨根问底, 侵犯的追问.
- 好为人师, 根据自己的经验给出建议.
- 自以为是, 根据自己动机分析对方的动机与行为.
关于CTE当前API无法支持从非引擎方式构建模板树
2008-04-28 https://www.iteye.com/blog/javatar-187669
因隐藏了模板树的实现, 现在CommonTemplate(http://www.commontemplate.org)必需从引擎生成模板树. 但上次在回复严荣的博客时: http://yananay.iteye.com/blog/180723 发现, 用户应该能用任意方式生成模板树才行, 也就是可以通过编程的方式,而非解析的方式构建模板树, 这样, 用户可以以其它方式存储或解析模板. 如:
1
2
3
4
List elements = new ArrayList();
elements.add(new TextImpl(“xxxxx”))
elements.add(new DirectiveImpl(“if”, expression))
Template template = new TemplateImpl(elements);
当用户想把模板保持为XML格式, 或将表达式保存成后缀表达式时, 就可以自行构建模板树. 从这一点看, 模板实体域的定义不应该放在engine包内, 而应单独列出一个language包, 包括指令与表达式的handler在内, 都应归入此包. engine包只负责core包中工厂域(服务域)的实现. 这都是因为违反了”可配置,即可编程”的设计法则, 可以将模板解析当作读取配置, 那在没有配置时也应能通过直接编程的方式实现同等功能. ——– 这是发给严荣和桂林的探讨邮件, 在这里也贴一份.
任务跟踪矩阵
2008-05-20 https://www.iteye.com/blog/javatar-194981
在做完 项目总体计划,开发计划 等之后, 开发小组内通常需要一个更细粒度的跟踪矩阵, 跟踪每个人每天在做哪些工作, 也就是短期的双周计划, 这种模板, 工具都很多, 项目组现使用自定义的EXCEL表格来做这一项工作, 自己对其稍加改进后, 如附件, 通过两个二维表, 形成对”时间”,”任务”,”成员”的三维矩阵,还算不错.
企业管理咨询与项目管理
2008-06-11 https://www.iteye.com/blog/javatar-202011
项目管理的知识一直在看, 但最近工作较忙, 搁置了较长计划,
总觉得自己在一个很小的视角里学习项目管理,
看不到全局, 不知道自己在干什么,
突然想在企业管理, 规划等方面也找找突破口, 换个角度, 同时学习.
或许是自己贪功了, 这样可能精力更分散, 不能潜心学习.
但还是想给自己一个增加兴趣的机会,
所以订购了企业管理咨询师考试的所有教材,包括实务,案例,练习册等,
也没打算去做企业管理咨询师,只是想了解下,
书到手后,先稍微过了下,好久没看过教材类的书籍,感觉还真有特色,
和PMBOK相比,教材不够精练,全是知识点与废话的堆积,有点头麻,
内容真多,包括战略咨询, 组织咨询, 人力资源管理咨询,
财务管理咨询, 市场营销咨询, 生产运营管理咨询, 质量管理咨询等等。
感觉企业管理咨询在中国还不成熟,但这方面的知识很重要,打算与项目管理混合学习。
现在的项目已开发完毕,进入性能测试阶段,虽然框架还有很多东西要改,但希望从现在到10月份上线,中间能空闲点,
读书计划如果再搁置就变空话了,当然,时间是自己挤出来的。
向高亚学习
2008-06-11 https://www.iteye.com/blog/javatar-202012
自从上次到高亚面试过, 虽然面试不怎么愉快,
但还是偶尔抽时间了解他们公司产品的发展,
感觉发展还是比较快的,产品改进不少,还有产品站点都快成学堂了.
比较赞同他们站点的展示方式, 不像其它产品在站点上列一些使用步骤,
而是列出使用场景, 让用户看到产品对客户需求的理解程度, 让客户倍感亲切,
也看了看他们老总罗叶明的个人博客, 非常值得学习,
谈到了他从贝尔实验试跳槽, 逐步向管理发展, 打破老美歧视亚洲人只适合做研发的想法, 还是很有主见的.
我现在就有点他所说的”侏儒思维”, 安于现状, 我总是以现状有利于我学习为借口, 消磨自己的斗志.
他对中国风投环境的评价也在理, 这是中国小公司的大障碍之一.
其它管理方面的知道, 他们可以说自成体系了, 已经站在较高的层次, 也是我追赶的一个目标.
亮剑: 军魂思考 (如何给团队注入灵魂)
2008-06-11 https://www.iteye.com/blog/javatar-202015
端午节刚过,趁着休假, 在家把《亮剑》给看完了,
李云龙的确是沟通高手,缓急之间游刃有余。
还有,他的现实主义思维,唯打胜仗是从,不拘于章法,也很有特色。
我比较关注他的军魂领导力,剧情中有一段李云龙与赵刚的对话,
谈到新一团,独立团为什么在李云龙的带领下,会变得如此有战斗力,
得到的结论是,李云龙为团队注入了灵魂,就算李云龙战死了,
他的团队依然所向披靡,决不会因为他的死而涣散,因为他的灵魂还在,
我想这才是一个真正的领导者应有的素质,人去魂留,与团队溶为一体。
我开始思考,什么才是凝聚团队灵魂至关重要的因素?
个人头脑风暴:
- 领导者坚定的信念
- 领导者与成员肝胆相照
- 领导者重承诺
- 领导者做事原则明确
- 领导者奖罚分明
- 领导者善于贯彻执行力
- 领导者理性的判断力与决策能力
- 领导者的良好的威信与名气
- 领导者良好的沟通能力
- 领导者善于煽动情绪(重复强调团队的信念,耳濡目染)
……
系统的决策方法
2008-06-23 https://www.iteye.com/blog/javatar-206984
决策者在决策常规方案时, 可以用以下步骤分解, 并将每一步拆分给基层或直接主管收集相应数据(如标准,备选方案等), 以保证决策者有足够的数据进行客观思考, 而不是主观臆断.
- 确定目标(必需实现的系统和战略)
- 检验约束(不可违背的, 如法律上的,财务上的,公司文化上的约束等等)
- 分解目标为具体要求
- 为每个要求列出所有可能的备选方案
- 建立选择标准
- 通过选择标准筛选及权衡最合适的方案
- 将所有要求的合适方案合成系统解决方案
外包公司组织结构思考
2008-06-23 https://www.iteye.com/blog/javatar-207044
因为我所在的公司是一家软件外包公司,对外包型公司的组织结构形态从项目管理的角度思考了一下.
首先,我们公司具有项目驱动型公司的所有特点:
- 系统性努力: 要使一个新的大型项目变成实际的合同,需要一种系统的方法,小型项目获得的力量总是与不断发展的大型项目紧密相联,并包括来自潜在的客户和执行组织中的关键人物的参与。
- 客户设计:传统的企业为不同的用户和客户提供相同的标准的产品和服务,而项目则是客户设计型的,目的是满足单个顾客的特定需求。
- 项目生命期:项目驱动型的公司有一个定义明确的开端与结束,但它并非永远存在。企业必须以一个一个的项目为基础不断发展,而不能只是依靠为标准化产品或服务创造需求。
- 市场营销阶段:一个项目在产品定义、开始和完成的各个阶段中,都存在一个很长的从设计到实际投产的时间。
- 风险:风险在所难免,尤其是大型项目的研究、设计与生产过程中,大型项目的经理不仅要在预算和进度约束下整合多个专门学科的任务和小项目,还要通过与各种偏好技术的“主角们”一同工作来管理发明和技术。
- 实施的技术能力:在成功追求和获取一个新项目中,技术能力尤其重要。
- 尽管眼前利益(如销售百分比)很小,但资本投资的回报是很诱人的。进度支付法使存货清单和应收票据的数量减少到最小,从而可使公司承担超出公司总资产数倍价值的项目。
- 一旦合同签订, 并且得到正确的管理, 那么项目给公司造成的财务风险就变得较低.这样,公司再花一点额外的销售费用,就可以在项目生命期内获得一个预期市场。
- 项目业务远见,不为眼前利润所动,项目为公司技术能力的发展提供了机会,并为未来业务的发展积累经验。
- 赢得一个大项目,常常会提供极具吸引的增长潜力,例如:(1)靠增加和变化带来项目的增长;(2)后继工作;(3)人员的储备、维持和培训;(4)在项目的下一阶段能够有效的竞争,如将一个研究项目培育成一份开发合同,并最终变成一份生产合同。
公司的大概划分是:技术部, 财务部,行政部,销售部,人力资源部等,
其中, 技术部员工数量远高于其它部门总和,
技术部又分为各技术项目团队, 以及测试部,UI设计部等,
每个技术项目团队均由一个项目经理带领,
项目经理负责项目的预算成本控制, 并对项目的成败负责,
开发人员均向项目经理负责,
可以看出,公司采用的项目型织组结构,
虽有职能型织组结构存在,但都以项目为中心, 只是有强矩阵结构的趋势。
所以公司也就存在项目型织组结构的优缺点:
优点:
- 整个项目具有完整的直线职权(也就是说,有一个很强的项目权威控制)
- 项目参与者直接为项目经理工作
- 沟通渠道通畅
- 不需要共享关键人员
- 反应时间快
- 职员对项目忠诚, 对产品形象有更强的理念
- 有一个处理公司外客户关系的中心
- 时间进度表, 成本和产品开发周期的执行都是有弹性的
- 随着单位规模的缩小, 人际管理变得更为容易
- 上层主管留有更多的自由时间用于行政决策
缺点:
- 由于工作、设备、人员的重复设置以及低效使用,使得在一个产品多元化的公司里维持这样的组织形式要花费很高的成本
- 容易造成职员任务完成后仍被束缚在项目里的倾向,上层主管必须在项目开始和逐步结束时平衡工作量
- 没有强大的职能群体, 技术支持困难, 因而阴碍了公司在新项目中的能力的提高(也就是说,没有稳定的技术基础)
- 对职能专家(或组织中的专家)的管理需要高层协调
- 不同的项目之间缺乏技术交流的机会
- 项目人员缺少稳定的职位和工作机会,导致人员流动较大
现在, 资源利效率低、项目间缺乏知识信息交流, 变成公司有目共睹的问题, 是否有更好的方式解决?
首先,是资源利效率低,现在公司通过项目组间借调人员实现资源共享,防止闲置,
但也出现项目人员流动过快,很多人都在打游击战,一个功能没开发玩就被派到其它项目组了,溶合成本增加,开发效率低。
那从员工的角度思考, 效率的原因在哪? 头脑风暴:
- 员工激励措施不够,导致消积怠工的员工不少。
- 项目的成功度依赖于项目经理的个人魅力和对员工的关系。
- 员工感觉不到成长机会,没有明确的职业规化,对未来很迷茫,周而复始的等着项目开始与结束。
- 员工感觉个人能力提升非常缓慢, 因为没有直线经理的指导, 全靠自己学习,对于一些自学能力不是很强的人,感觉一直原地踏步,对行业的最新动向也不甚了解。
- 交流太少,就连项目组内员工间都很少交流,更不用说项目间,项目间基本上是隔绝的,很多人都不认识。
- 私下里员工间都抱怨公司,但却没人愿意给公司提建议,因为沟通渠道不畅。
- 员工经常出现与SA或PM谈判任务的工作时间,三天还是一天?
- 公司归属感太弱,想跳槽的人太多,当然公司初期并不在意底层员工的变动,走了再招,成本也不是很高,对管理层的持续是公司的首要目标, 但人员磨合,知识沉淀也是一个漫长的过程。
- 项目管理混乱,大部分项目都很赶,都经常加班,都项目延期. 代码质量无人审查,
- 员工没有向上级主动汇报的习惯,这可以说是一种文化,所有的事情等着PM来催,如果PM忙于其它事,通常出现计划内无法完成原有的工作量,最后大家一起加班。
……
其实公司管理层估计比我想得更多以及更深,也一直在解决,这此问题解决起来不是一蹴而蹴的,
但公司总是不能将过错推给员工,因为法不责众,并且一个集体的行为是被公司文化所引导的。
其次,是项目间沟通,公司也经常将此事提上日程,如:项目组间相互培训,公司内部活动交流等方式,
但效果都不佳,因为员工并不重视,培训流于形式,无人参与,因为没有合理的组织调动,以及大部分人忙于项目,
甚至出现需要规定每个项目组必需派人来听培训的场面,培训的意义已经不大。
或许这些都只是治标不治本,其根源是组织结构形态,项目型织组结构不可避免的会有这样的问题。
然而,在项目管理体系中,认为项目型织组结构适合于小型公司, 那公司在状大后是否有可以变革成职能型织组结构或矩阵型织组结构?
向职能型织组结构转变的可能性较小, 因为以项目为中心的现状并不会改变, 除非公司向产品型或大规模生产型公司转型.
那是否可能转为矩阵型织组结构,尤其是强矩阵型织组结构?
这种可能性是存在的,当公司规模上升到一个层次,增设职能经理的可能就会加大,促使分工更明细。
但组织结构的调整通常都带有高风险,会引起公司长时间动荡,我想管理层还是趋向于稳定的项目型组织结构。
另外, 我在公司主要工作是做框架设计开发, 那公司应为研发部支出多大?
按项目管理的原理, 当公司较小时, 通常不需要专家组(研发部)存在, 因为会因为缺少分工和规模经济而耗费巨大的成本.
但公司的成长过程中,却需要一个研发部来对公司技术实力进行沉淀。
如果说销售部是公司的命脉,只有接到项目公司才能赖以生存,
那研发部就是公司的财富,可以给公司带来质的飞跃。
那是应研发部门是以全职为好,还是从各项目组抽调人员半职为宜?
我相信大家都会认为是少数全职,多数半职,这样不至于脱离项目环境,并保持与项目的纽带关系。
如果公司想沉淀自己的产品,向产品型公司转型,可能说需要设有较多全职研发人员。
跳不出自己的思维角度, 不说了.
嵌套注释语法思考
2008-06-29 https://www.iteye.com/blog/javatar-209259
主流的C/C++/Java/C#等语言,都将注释语法设计成不可嵌套的。
如: /* xxx /* yyy */ zzz */ 是非法的。
理由是注释是用于写描述性语言的,嵌套会使得可读性更差。
但实际上,注释不只是用来写注释标注,还通常用于屏蔽代码块。
所以在C/C++中,大家经常用#if(0)预编译指令进行代码块注释。
而CommonTemplate(http://www.commontemplate.org)作为一个模板语言,以方便使用为目标。
所以考虑是否应提供可嵌套的注释。
是将现有的注释方式改成可嵌套,还是增加可嵌套注释语法?
如可以考虑增加语法:
1
2
3
$-*
......
*-$
以区别于现有的:
1
2
3
$*
......
*$
不管使用哪种方案,转义符都是首先应该提供的,
如:$* xxx $* yyy \*$ zzz *$
如果允许嵌套注释则起始符也应转义,
如:$* xxx \$* yyy \*$ zzz *$
《做主管常犯的毛病》总结
2008-07-07 https://www.iteye.com/blog/javatar-212182
周未看了于世雄的《做主管常犯的毛病》,把他列出的问题顺过来总结了一下:
- 承担责任,主动承认错误,解决问题,不辩解,不在上级面前推委下属的错误,不做传话筒,不要对上级提你下属的名字,一切都是你的事。
- 启发下属,授权,不要事必躬亲,培养接班人,随时,随地,随人,随事的引导下属。
- 不只是注重结果,思想一样重要,着重朔造团队的主观意识,不要总是说:“不要一天到晚跟我讲这么多理由,我只问结果,上面要的是业绩,指标。”
- 多用“我们”,由其对客户,不要说这是某某部门或某人的事,对客户来说,公司是一个整体。
- 对下属因才适用,多了解下级的特点,不要用一个模子管理。
- 不要忘记公司命脉:利润,为公司创造利润,也就是为自己创造机会,并且贯彻这种思维。
- 不要天天只干救火的事,多思考长期战略性问题和计划。
- 不要混洧人性管理与人情管理,保持等级间的严肃性,与下属太谈哥们,只会坏了公司的规矩。
- 使每一个岗位都有标准可循,强型执行标准作业,使之成为习惯,并且考核应以明确的细化的标准为条件,而不是抽象的条件(极积性80分与70分有什么区别,谁说了算),否则考核结果主观性太强,容易沦为形式。
- 不要担心下属超越你的能力,不要纵容能力不足的人,也不要只关注明星员工。
CommonTemplate访问者设计思考
2008-09-03 https://www.iteye.com/blog/javatar-236014
经过多个版本的调整, CommonTemplate(http://www.commontemplate.org)的核心包设计逐渐稳定.
但访问者的设计一直是块心病, 并且访问者是合成模式[GoF95]树结构中比较重要的扩展点.
CommonTemplate中的访问者最开始设计:
1
2
3
4
5
6
7
8
9
public interface Visitor {
/**
* 当访问到节点时被回调
* @param node 被访问的节点
*/
void visit(Node node);
}
其中, Node是Template, Element, Expression等的抽象. 如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public interface Node {
/**
* 接收访问者, 并带领访问者遍历整个子树. (前序遍历)
* @param visitor 访问者
*/
void accept(Visitor visitor);
String getName();
......
}
Node是引擎实现的, 而Visitor是留给扩展者实现的.
大体分为:
- 模板元素树和表达式树全遍历
- 模板元素树全遍历(不访问表达式树)
- 查找某一模板元素
- 查找某一表达式元素(基于模板遍历)
如:
NodeCountVisitor (统计模板节点的个数)
TemplateDumpVisitor (导出模板结构)
DirectiveFindVisitor (查找指令)
VariableRequirementVisitor (计算模板所需的变量)
等等.
调用方式如:
1
2
Visitor visitor = new TemplateDumpVisitor(writer);
template.accept(visitor); // 带领visitor遍历整个树, 遇到节点则回调visitor的相应方法
在查找指令时通常不需要遍历指令表达式, 而访问者原始接口无法控制是否访问指令表达式.
重构:
加入访问控制值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public interface Visitor {
/**
* 继续访问下一节点
*/
public static final int NEXT = 0;
/**
* 跳过子节点
*/
public static final int SKIP = 1;
/**
* 停止访问
*/
public static final int STOP = 2;
/**
* 当访问到节点时被回调
* @param node 被访问的节点
* @return 访问控制值, NEXT, SKIP, STOP
*/
int visit(Node node);
}
这样, 可以用 if (node instanceof Expression) return SKIP; 控制不访问表达式树.
也可以通过return STOP; 停止访问.
当然, Node中的int accept(Visitor)方法也要返回和传递控制值:
1
2
3
4
5
6
7
8
9
10
public interface Node {
/**
* 接收访问者, 并带领访问者遍历整个子树. (前序遍历)
* @param visitor 访问者
* @return 访问控制值, Visitor.NEXT, Visitor.SKIP, Visitor.STOP
*/
int accept(Visitor visitor);
}
然而, Visitor接口中单一的visit()方法强迫扩展者使用if(node instanceof XXX)语句判断类型, 丧失多态性.
重构:
将visit拆分, 依赖树的具体结点.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public abstract class Visitor { // 考虑树的具体结点可能增加, 采用抽象类便于向前兼容
public int visitDirective(Directive directive){}
public int visitVariable(Variable variable){}
......
或者:
public int visit(Directive directive){}
public int visit(Variable variable){}
......
}
这样, 子类只要覆写需要的类型函数.
但过多的状态位控制流转, 也是一件不愉快的事.
并且表达式树与模板元素树两种类型没有区分.
重构:
拆分表达式树与模板元素树访问者,
并通过子类覆写的方式决定是否需要级联访问表达式树,
通过抛出StopVisitException运行时异常停止访问.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
public abstract class ExpressionVisitor {
/**
* 当访问到变量时被回调
*
* @param variable 访问到的变量
* @throws StopVisitException 当希望停止访问时抛出
*/
public void visitVariable(Variable variable) throws StopVisitException {}
/**
* 当访问到常量时被回调
*
* @param constant 访问到的常量
* @throws StopVisitException 当希望停止访问时抛出
*/
public void visitConstant(Constant constant) throws StopVisitException {}
/**
* 当访问到二元操作符时被回调
*
* @param binaryOperator 访问到的二元操作符
* @throws StopVisitException 当希望停止访问时抛出
*/
public void visitBinaryOperator(BinaryOperator binaryOperator) throws StopVisitException {}
/**
* 当访问到一元操作符时被回调
*
* @param unaryOperator 访问到的一元操作符
* @throws StopVisitException 当希望停止访问时抛出
*/
public void visitUnaryOperator(UnaryOperator unaryOperator) throws StopVisitException {}
}
public abstract class TemplateVisitor extends ExpressionVisitor {
/**
* 当访问到模板时被回调
*
* @param template 访问到的模板
* @throws StopVisitException 当希望停止访问时抛出
*/
public void visitTemplate(Template template) throws StopVisitException {}
/**
* 模板访问结束时被回调
*
* @param template 结束的模板
* @throws StopVisitException 当希望停止访问时抛出
*/
public void endTemplate(Template template) throws StopVisitException {}
/**
* 当访问到文本块或不解析块时被回调
*
* @param text 访问到的文本块或不解析块
* @throws StopVisitException 当希望停止访问时抛出
*/
public void visitText(Text text) throws StopVisitException {}
/**
* 当访问到行注释或块注释时被回调
*
* @param comment 访问到的行注释或块注释
* @throws StopVisitException 当希望停止访问时抛出
*/
public void visitComment(Comment comment) throws StopVisitException {}
/**
* 当访问到行指令时被回调.<br>
* 注:缺省实现为继续访问指令表达式。<br>
* 如果不需要访问指令表达式,请覆写此函数并留空。<br>
* 也可以在访问指令表达式前后作相关处理:<br>
* <pre>
* public void visitDirective(Directive directive) {
* // 在表达式访问之前处理...
* super.visitDirective(directive);
* // 在表达式访问之后处理...
* }
* </pre>
* @param directive 访问到的行指令
* @throws StopVisitException 当希望停止访问时抛出
*/
public void visitDirective(Directive directive) throws StopVisitException {
if (directive.getExpression() != null)
directive.getExpression().accept(this);
}
/**
* 当访问到块指令时被回调.<br>
* 注:缺省实现为继续访问指令表达式。<br>
* 如果不需要访问指令表达式,请覆写此函数并留空。<br>
* 也可以在访问指令表达式前后作相关处理:<br>
* <pre>
* public void visitBlockDirective(BlockDirective blockDirective) {
* // 在表达式访问之前处理...
* super.visitBlockDirective(blockDirective);
* // 在表达式访问之后处理...
* }
* </pre>
* @param blockDirective 访问到的块指令
* @throws StopVisitException 当希望停止访问时抛出
*/
public void visitBlockDirective(BlockDirective blockDirective) throws StopVisitException {
if (blockDirective.getExpression() != null)
blockDirective.getExpression().accept(this);
}
/**
* 块指令访问结束时被回调
*
* @param blockDirective 结束的块指令
* @throws StopVisitException 当希望停止访问时抛出
*/
public void endBlockDirective(BlockDirective blockDirective) throws StopVisitException {}
}
节点的accept也作相应处理:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public abstract class Node {
/**
* 接收访问者, 并带领访问者遍历整个子树. (前序遍历)
* @param visitor 访问者
*/
void accept(Visitor visitor) {
accept(visitor, true);
}
/**
* 状态传入访问者接收接口, 通常直接使用accept(Visitor visitor)
* @param visitor 访问者
* @param isEnter 是否为入口, 在入口处忽略StopVisitException
*/
void accept(Visitor visitor, boolean isEnter);
}
RCP数据传输模型回顾
2008-10-26 https://www.iteye.com/blog/javatar-258066
最近在做的项目,是一个C/S和B/S混合的项目,我主要负责设计开发框架部分,
最开始设计时,因时间仓促,没有细想,就草草上阵了,
现在项目快结束了,回过头来想想,还是有很多地方可以完善,这里说一下数据传输这一块。
因项目中B/S使用的是Struts2,所以C/S也通过Struts2提供的拦截器和Result扩展点进行了适配,
使得C/S数据传输序列化与反序列化对于业务逻辑透明化,目的是要让服务器端B/S和C/S写法一致。(客户端使用HttpClient实现)
Struts2整体设计还行,但确越来越臃肿,而且对RCP支持很不友好。
其实,C/S主流设计思路中,都是在Service层留出接口,并将接口部署到客户端,
中间通过RMI, Hessian, Burlap, WebService, HttpInvoker等任意方式生客户端Stub,
Stub实现中所有接口函数都远程代理服务器端相应Service实现,也就是客户端与服务器端对等体,
这样就可以通过接口“直接”调用服务器端函数,从而进行透明化数据传输。
B/S中的DWR也使用了这种方式。
这种设计的主要好处就是全部透明化,但将接口部署到客户端不是很方便,
而且服务器上的函数调用起来太方便,如果交互函数粒度较小,会使得业务逻辑向客户端倾斜,
保留Action门面,似乎还是很有必要的,这样可以保证客户端与服务器端交互粒度足够大,
但Action应该以数据为中心,而不是以控制为中心,
在RCP应用中,视图控制基本转移到客户端了,Action不应再对“跳转/切换”之类的过多关注,
WEB应用中的MVC框架,其返回值大多用来做控制,这也是它们不太适宜兼容RCP的问题所在。
按这个思路的设计如下:
客户端与服务器端共享:
Action接口:(在Action门面层实现透明化对等体)
1
2
3
4
5
public interface Action {
Serializable execute(Serializable object);
}
服务器端: 实现Action接口:
public class XxxAction implements Action {
private XxxService xxxService;
public void setXxxService(XxxService xxxService) {
this.xxxService = xxxService;
}
public Serializable execute(Serializable object) {
// ...
}
}
在spring的beans.xml中注册:
<bean id="xxxAction" class="com.xxx.action.XxxAction">
<property name="xxxService" ref="xxxService"/>
</bean>
RCP应用客户端: (使用Swing/SWT做视图,序列化对象作传输) 在Java代码中,使用如:
1
2
3
4
// 返回的是代理,但看起来像拿到了服务器端的Action
Action xxxAction = ActionFacade.getAction("xxxAction");
// result和params为任意可序列化对象
Object result = xxxAction.execute(params);
WEB应用客户端: (使用ExtJS做视图,JSON作传输) 在JSP页面中,使用如:
<!-- name属性为action在beans.xml中注册的id号 -->
<ext:action var="xxxAction" name="xxxAction" />
<ext:script>
<!-- result和params为json对象 -->
var result = xxxAction.execute(params);
</ext:script>
当然,服务器端拦截器的设计是必不可少的,
这种天然的截面,比AOP的自动代理用起来方便很多。
包括安全,检验,转换,控制都可以使用该截面统一实现。
拦截接口:
1
2
3
4
5
public interface ActionInterceptor {
Serializable intercept(Action action, Serializable object);
}
另外,ThreadLocal的ActionContext也是必要的,
用于封装交互过程的附属信息等。
1
2
ActionContext.getContext().getRequest();
ActionContext.getContext().getSession();
服务器端分包结构回顾
2008-10-26 https://www.iteye.com/blog/javatar-258179
现在很多的Java应用都采用Eric在《DDD》中提出的域分层结构,
所以大部分项目看起来像下面这个样子分包:
action
service
dao
domain
exception
util
最近做的这个项目也采用了类似的结构,
其中service和dao的关系是一个老生常谈的问题,
dao只对数据访问进行隔离,比如:Hibernate过时了,我们需要按一套全新的持久化方案,只需把Dao的实现类替换掉就行了。
service包括所有的业务逻辑,使用dao存取数据,并向Action功能提供服务。
然而,大部分企业应用中,业务逻辑就是对数据库的操作,
所以就出现了大量的service变成了dao的代理,
为此,有人提出,如果只是简单数据操作,action可以直接调用dao,因为同样保持着单向依赖。
但是,允许这样做后,dao函数的粒度较小,action变相的成了业务逻辑处理中心。
还有一个问题是,复杂的SQL语句,是业务还是数据操作?该放在dao,还是service?
其实放在dao或service, 都能说得通,
但我觉得应该放在service, SQL语句本身是业务逻辑,只是执行它的应该是数据操作接口,
如果dao只是作为数据操作接口,在现在数据自动映射处理框架的面前,是否有必要存在?
我比较赞同统一dao接口为一个特殊的服务, 如:PersistentService
持久化服务接口:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public interface PersistentService extends Service {
void save(Entity entity);
void batchSave(Collection<Entity> entities);
void update(Entity entity);
void batchUpdate(Collection<Entity> entities);
void saveOrUpdate(Entity entity);
void batchSaveOrUpdate(Collection<Entity> entities);
void remove(Entity entity);
void batchRemove(Collection<Entity> entities);
void remove(Class<?> entityClass, Long id);
void batchRemove(Class<?> entityClass, Collection<Long> entityIds);
Entity get(Entity entity);
Entity get(Class<?> entityClass, Long id);
Entity get(Class<?> entityClass, String property, Serializable value);
Collection<Entity> find(Entity entity);
Collection<Entity> find(Class<?> entityClass, String property, Serializable value);
Collection<Entity> find(String query);
Page<Entity> findPage(Entity entity);
Page<Entity> findPage(Class<?> entityClass, String property, Serializable value);
Page<Entity> findPage(String query);
......
}
然后,实现不同ORM框架的映射,如:
1
2
3
4
5
public class HibernatePersistentService implements PersistentService {
......
}
或者SQL映射框架,如:
1
2
3
4
5
public class IbatisPersistentService implements PersistentService {
......
}
或者非数据库持久化,如:
1
2
3
4
5
public class XmlPersistentService implements PersistentService {
......
}
然后,在其它业务类服务基类中缺省由框架自动注入持久化服务:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public abstract class AbstractService implements Service {
/**
* 日志输出接口
*/
protected final Logger logger = LoggerFactory.getLogger(getClass());
/**
* 持久化服务
*/
protected PersistentService persistentService;
// IoC注入接口
public void setPersistentService(PersistentService persistentService) {
this.persistentService = persistentService;
}
}
业务类服务中使用如:
1
2
3
4
5
6
7
8
9
public class UserServiceImpl extends AbstractService implements UserService {
public User login(String username, String password) {
// 直接使用持久化服务接口
User user = persistentService.get(User.class, "username" username);
....
}
}
这样统一后,
service表示无状态的服务模型,服务可以再依赖服务,并且像邮件发送等也应该成为服务,而不是util工具。
action表示有状态的功能模型,代表一个用户可具体操作的功能。
模块间服务模型共享,并定义好依赖关系。
模块间功能模型使用名称空间相互区隔,互不干扰。
如:
雇员管理服务:包括雇员增删改查接口,数据一致性检查等。
雇员管理功能:包括新增雇员的界面,界面控制,数据传输等。
提成管理功能,也可依赖雇员管理服务,通过服务获取提成雇员的信息。
但提成管理功能却不会依赖雇员管理功能,因为它不关心雇员信息是怎么维护的。
如果雇员信息是从HR系统同步过来的,那样就只需要雇员管理服务,而不需要雇员管理功能,或者同步过程就是雇员管理功能。
所以服务模型和功能模型应该分别打成jar包,便于部署。
关于Java泛型违反Liskov原则
2008-11-10 https://www.iteye.com/blog/javatar-265151
Java5 增加的泛型语法,使类型模板的应用得到了提升,但它的运行期擦拭的做法(为向前兼容),令人诟病,
使得一个Map集合,通过反射拿到的集合元素的泛型类型,不是实际使用类型,而是K和V(字节码编译期保留)。
另一个有争议的地方是:
泛型违反了里氏代换原则(Liskov’s Substitution Principle),即:子类应该在任何地方都能替换父类。
假设一个函数:
1
void xxx(List<Object> list);
调用:
1
2
List<String> list = ...
xxx(list); // 编译出错
当然,你可以使用下面的变通方式就不会出错:
1
void xxx(List<? extends Object> list);
主要的问题在于:List
我觉得应该是,至少“人”认为是,面象对象的主要目的是什么?就是让人理解程序,而不是机器。
而官方给出的答案却是:List
Java泛型规格说明书 写道
让我们测试一下我们对泛型的理解。下面的代码片断合法么?
List
ls = new ArrayList (); //1 List
第1行当然合法,但是这个问题的狡猾之处在于第2行。
这产生一个问题:
一个String的List是一个Object的List么?大多数人的直觉是回答:“当然!”。
好,在看下面的几行:
lo.add(new Object()); // 3
String s = ls.get(0); // 4: 试图把Object赋值给String
这里,我们使用lo指向ls。我们通过lo来访问ls,一个String的list。我们可以插入任意对象进去。结果是ls中保存的不再是String。当我们试图从中取出元素的时候,会得到意外的结果。
java编译器当然会阻止这种情况的发生。第2行会导致一个编译错误。
总之,如果Foo是Bar的一个子类型(子类或者子接口),而G是某种泛型声明,那么G
是G 的子类型并不成立!! 这可能是你学习泛型中最难理解的部分,因为它和你的直觉相反。
这种直觉的问题在于它假定这个集合不改变。我们的直觉认为这些东西都不可改变。
举例来说,如果一个交通部(DMV)提供一个驾驶员里表给人口普查局,这似乎很合理。我们想,一个List
是一个List ,假定Driver是Person的子类型。实际上,我们传递的是一个驾驶员注册的拷贝。然而,人口普查局可能往驾驶员list中加入其他人,这破坏了交通部的记录。 为了处理这种情况,考虑一些更灵活的泛型类型很有用。到现在为止我们看到的规则限制比较大。
上面所描述的语义限制根本没有意义,如果想限制用户在List
因为想做这个语义上的限制,而牺牲直观的理解非常不值,加一个”?”问号作为替代方案,只会使泛型更复杂,使用也不方便。
用户必须在”?”问号与”Object”间绕来绕去,烦也不烦,或许可以问:”?”问号等于”Object”吗?呵呵,maybe.
平台开发基础原则制定
2008-11-11 https://www.iteye.com/blog/javatar-265358
最近在构想一个新的内部使用平台,发现首先要确立一些的根本性的原则,作为设计指导,使各模块设计人员都能保持一致的方向,只有先确定了这些基础原则,在开发决策时,大家才不会争论不休,包括:
- 强类型,还是弱类型?Bean对象,还是Map集合?
- Map的好处在于:可以统一数据模型,并作为上下文或数据总线处理,可以不用生成代码,就能对CRUD等基本功能,作运行时封装,适合于快速开发。
- Bean的好处在于:强类型,明确的契约接口,调用者与被调用者都能很明确的知道需要什么,符合领域驱动设计的思想,便于后期维护,适合于长期产品。
- 零代码,还是零配置?还是全图形?
- 像OFBiz等框架,提倡零代码开发,也就是全配置,
通过一个XML,配置一下实体字段,搜索条件,显示列,菜单,工作流等,就能完成大部分资源管理类功能,
在特殊功能时,通过配置回调Java接口,来调用部分Java代码逻辑,
好处就是所谓的简单,不需要懂Java也能开发。
坏处也显而易见,灵活性差,性能差,IDE支持差,重构能力差(需全文搜索),开发不方便(不能调试),不能使用继承,多态等面象对象复用功能,程序员不愿意天天写配置,离职率高。
- 而现在流行的开源项目,都开始提倡零配置开发,通过注解等,尽可能在代码中集中处理,
好处是:IDE支持好,易于重构,易于开发,不需要在配置与代码之间来回工作。
坏处是:与注解框架强耦合,背离IoC/DI的无侵入原则,修改关联时,需重新编译。
- 像EOS等平台和一些基于UML的MDA设计器,提倡全图形开发,
通常由图形化的业务逻辑,页面功能逻辑,流程逻辑拼装而成,通过生成代码,或者使用一个引擎运行时解析图形配置。
好处是:给人一种绚丽高档的感觉,更易忽攸客户,在简单的增删改查逻辑下,开发方便。
坏处是:与特定的IDE捆绑,成熟的产品不多,通常不稳定,开发繁琐,维护困难,性能差,复用能力差,不能使用多态,继承等,逻辑稍复杂时,看图形蜘蛛网,比看代码更痛苦,程序员抵触,离职率高。
- 从领域实体生成数据库,还是从数据库导出领域实体? 这里主要是考虑设计人员,是先做领域UML建模,还是E-R建模。
- 从领域实体生成数据库,可以使领域模型设计更合理,包括组合关系,聚合关系,继承关系等,这样软件的设计也会更合理。
- 而从数据库导出领域实体,可以使表结构设计更合理,很多人说,数据比程序的生命周期更长,程序不用了,可能数据还在继续使用。 当然,手工映射可以做得更好,但工作量会翻倍。
- 快速? 高效? 灵活? 稳定? 扩展? 重用? 易于实施? 如果能全部做到,当然最好,但有些特性通常是互斥的, 在平台开发初期就应该确定优先顺序,孰轻孰重。
当然还有其它一些如:开发方式,封装重点,控制粒度,特性权衡,组件选型原则等等,待整理。
模块划分方式回顾
2008-11-13 https://www.iteye.com/blog/javatar-266848
模块的划分,一直是争议比较大的地方,各种方案相去甚远, 模块定义,范围,大小,分包,装配各不相同。 根据不同的产品,项目,可能都会有不同的设计。 如果一个公司自用的快速开发平台,它的模块应该如何设计? 简单确立一下设计目标:
- 低耦合高内聚
- 模块复用度高
- 模块可扩展性强
- 模块自描述,自包含
- 模块自发现,自装配
- 模块以业务为中心
- 模块易于开发测试
- 模块易于集成部署
- …..
初步设想需要解决:
- 模块的粒度多大
- 是否区分功能模块与服务模块
- 模块如何检测和加载
- 如何描述模块间的依赖关系,并保证依赖关系稳定
- 模块如何区隔上下文或名称空间
- 模块如何统一处理全局风格整体置换
- 模块间如何以对等的方式互相”侵入”
- 模块如何统一暴露服务API
- 模块如何识别SPI策略实现
- 模块扩展点如何设计
- 模块如何注册与发布事件
- 模块如何处理截面,拦截器
- 模块元数据如何定义,方便开发,也方便检测
- 模块如何控制版本
- 模块如何简化部署和分发
- ……
在刚做完的项目中,系统按主用户群使用范围,划分为运单管理,结算管理,巴枪管理,基础数据管理等子系统, 再按业务功能划分为几十个功能模块,按理论,每个功能模块都能部署到任意子系统中, 并且每个模块就是一个jar包,直接扔到lib目录下,即可使用, 框架自动发现模块,自动装配,自动释放访问资源,自动加载配置, 因为是以项目为中心搭建的框架,所以大量采用了命名约定方式,来处理装配过程,尽量减少配置, 但在开发过程中,因为开发人员较多,培训不够,各开发小组协调差,时间仓促等原因, 出现了命名冲突,循环依赖,开发环境搭建难,集成测试不过,等诸多问题, 最后框架为了应付各种情况,做了很多通容的处理,整体都有些变形, 这是设计之初写的blog文章: http://javatar.iteye.com/blog/182149 当时和leadyu讨论,也觉得有些风险,但还是用上了。 现在想想,虽然不太完美,但在近半年的优化调整后,以及开发人员的磨合,也算比较通畅, 对下一步开发还是很有帮助的,也希望在此基础上作进一步思考。
RCP数据模型验证框架
2008-11-26 https://www.iteye.com/blog/javatar-280371
Struts(for)RCP(http://struts4rcp.googlecode.com)发布了0.1版本,但还缺少一个重要元素,那就是数据模型验证框架,MVC框架总是少不了它。
验证框架需要实现哪些功能?
- 对Action执行过程中的数据进行透明化检验,Action只需声明验证规则,而不参与验证过程。
- 可以服务器端验证,也以可客户端验证,或者数据模型自验证。
- 验证规则捆绑方便,可以使用注解,也可以使用XML配置,以及直接编码捆绑。
- 验证规则可自定义,并且内置规则丰富。
- 验证出错信息国际化。
现成的验证框架已经不少,像Struts, WebWork, Hibernate, JSF等都提供了验证框架,是否可以重用?
由于B/S开发的盛行,大多数已有验证框架都向B/S结构倾斜,虽然它们也能验证C/S结构应用。
而且验证框架众多,不易选择大众口味,所以还是由框架本身提供,然后适配到其它验证框架。
如果重新定义验证框架,它应该属于哪个包?
它并不是MVC控制器框架必需的,而且它需要在服务器端和客户端同时使用,
甚至给其它第三方包复用,所以,它应该放在util包内,与序列化器相似。
客户端设计回顾
2008-11-29 https://www.iteye.com/blog/javatar-283038
接前面几篇回顾性文章,再说说刚做完项目中客户端框架的设计,
客户端在项目初期就选择了EclipseRCP,当时给的理由是Swing太慢,
现在项目做完了,没人再说这句话了,
因为EclipseRCP更慢,尤其是表格控件,折腾了几个月,
客户端的设计不是由我主导的,只是后期我也加入修复问题,
因客户端的设计人员频繁更换,并且时间伧促,加上会EclipseRCP的开发人员又少,
最后得到的结果是不怎么理想的,而且文档更新不同步,感觉有点面目全非。
客户端整体框图如下:
- client.libraries 包含所有第三方库(如:httpclient.jar等)以及domain,exception等实体或值对象。
- client.common 是框架的主要实现部分,包括封装的控件,传输组件,同步,缓存,权限等等。
- bar.main, exp.main 是各子系统的主工程,其它模块插件都部署到它的内部运行。
- client.launcher 是一个使用Swing写的WebStart适配,负责分发整个应用到客户端,并作版本检查。
另外的,就是模块插件了,由业务组开发。
几个大问题:
- client.libraries 不应该放domain,exception等实体或值对象, 他们应该属于各业务模块,如果强制把序列化对象全放到框架中, 在开发过程中使得libraries经常变动,而且可能冲突, 另外,这使得框架反向依赖于业务模块, 开始的原因是,Eclipse各插件之间ClassLoader隔离,经常出现类找不到,所以就全放到底层去了。 后来找到办法解决,但业务组已经基于这种方案在开发,协调比较困难,就只能用下去了。
- bar.main和exp.main不应该存在, 不知道为什么会为每一个子系统建一个工程,让架构组来维护,有点莫名其妙,
如果再加几个子系统,难道架构组需要继续加工程?
这两个工程里就是些EclipseRCP启动事件类(如:ApplicationWorkbenchAdvisor等),一模一样,
完全可以放到client.common工程中,让client.common作为启动工程。
而现在却是在client.common工程中放了一堆抽象层(如:AbstractApplicationWindowAdvisor),
然后让bar.main和exp.main一对一去继承,这个隔离层没有多大意义,
如果说为了各子系统可能有不同的需求,完成可以通过特殊的模块插件实现。 - client.common中定义的国际化组件,在模块中居然用不了, 这个国际化组件只读取了client.common自身的properties文件, 模块中就只好每个人都照抄这个国际化组件,搞得Messages类到处都是。
- 还有类的分包,我没看出个所以然,如:登录功能就在5个包下有类,实在摸不透。 另外,小问题也有不少,冗余类也不少,到后期都是能不改就不改,稳定第一。
要整理客户端框架,工作量可不少。
《卓有成效的管理者》
2009-04-10 https://www.iteye.com/blog/javatar-364761
《卓有成效的管理者》和《管理的实践》一样,是管理学的基础书籍,德鲁克的经典书籍之一,上段时间有同事要买管理书籍,就推荐了这本,其实我自己也不太记得具体内容了,抽空再翻了翻,都是些实用的高效方法,摘个大纲:
- 记录时间,并分析时间用处比例,将时间整块使用。
- 注重贡献,不仅重视方法,也重视目标与结果。
- 发挥自己,下属,同事,以及上司的长处,没有成功的上司就不会有成功的下属。
- 要事优先,不要被紧迫而不重要的事蒙蔽,这个看柯维的《时间管理/要事第一》可能讲得更多。
- 有效的决策,区分例行与例外,从见解出发,而非“事实”假象,综合反面意见,权衡利益与风险。
类似的书还有《高效能人士的七个习惯》,它提倡的积极主动,以终为始,要事第一,双赢思维,知彼解己,统合综效,不断更新等都是不错的习惯。
《激进营销》
2009-04-11 https://www.iteye.com/blog/javatar-365766
今天看了会儿《激进营销》,让我想起软件工程中的《敏捷开发和管理》,都是以传统的经典管理方式为基础,结合实践经验,以实用为宗旨,总结成一些准则,某些地方也会采用“矫枉必过正”的思想,给人警醒的感觉。
《激进营销》
- The CEO must own the marketing function (首席执行官必须掌握营销功能)
- Make sure the marketing department starts small and flat and stays small and flat (必须保证营销部门扁平化和人数少, 并持之以恒)
- Get out of the office and face-to-face with the people that matter most (与那些和顾客直接相关的人面对面地接触)
- Use market research cautiously (认真仔细地利用市场调查)
- Hire only passionate missionaries (只雇用热情的”传道士”)
- Love and respect your customers (爱护和尊敬你的顾客)
- Create a community of customers (创造一个消费者社区)
- Rethink the marketing mix (重新思考营销组合)
- Celebrate uncommon sense (尊重公众感觉)
- Be true to the brand (相信品牌)
《敏捷宣言》
价值观:
- 个体与交互 重于 过程和工具
- 可用的软件 重于 完备的文档
- 客户协作 重于 合同谈判
- 响应变化 重于 遵循计划
准则:
- 我们的最高目标是,通过尽早和持续地交付有价值的软件来满足客户。
- 欢迎对需求提出变更——即使是在项目开发后期。要善于利用需求变更,帮助客户获得竞争优势。
- 要不断交付可用的软件,周期从几周到几个月不等,且越短越好。
- 项目过程中,业务人员与开发人员必须在一起工作。
- 要善于激励项目人员,给他们以所需要的环境和支持,并相信他们能够完成任务。
- 无论是团队内还是团队间,最有效的沟通方法是面对面的交谈。
- 可用的软件是衡量进度的主要指标。
- 敏捷过程提倡可持续的开发。项目方、开发人员和用户应该能够保持恒久稳定的进展速度。
- 对技术的精益求精以及对设计的不断完善将提升敏捷性。
- 要做到简洁,即尽最大可能减少不必要的工作。这是一门艺术。
- 最佳的架构、需求和设计出自于自组织的团队。
- 团队要定期反省如何能够做到更有效,并相应地调整团队的行为。
批评和赞美
2009-04-19 https://www.iteye.com/blog/javatar-370791
处世的基本原则:不要批评别人,真诚的赞美别人。
看起来很简单的一件事,但要形成潜意识,还真需要点时间。
反省:
回邮件列表时,总喜欢提反面意见,要改。
上次在艺龙订酒店的事,带有主观批评意识,所以搞砸。
最近我都赞美谁了?好像没有。。。
填石头
2009-04-28 https://www.iteye.com/blog/javatar-376387
在网上看到一篇时间管理的故事,好像以前在哪看过,翻出来一对比,同样的故事,得出的结论居然不一样,
故事很简单,一个讲时间管理的老师用石头把瓶子填满了,问同学们是否满了,然后再用小石子,沙子,水进一步填满。
第一种结论:时间总是可以挤出来的,看似满了,其实还是有空隙的,我们浪费的时间其实可以做很多事。
惯性思维都会得到这样的结论,这是高效做事自我鞭策的方法之一,可以提醒自己别浪费时间。
另一种想法是:为什么我们能再往里填沙子和水?那是因为我们先填入了石头,如果先填入沙子和水会怎么样?能再填石头吗?
所以它的结论是:只有在我们的计划中先填入最重要的事(石头),才能往中间插入更多紧急琐碎的事(沙子),如果我们的计划先被紧急琐碎的事填满了,你将无法再插入重要的事,简单的在计划中安排更多的事,只会使计划越来越不可执行。
很多时候过于强调高效,反而不高效,陷入紧急事务中,给人一种过的很充实的感觉,天天忙得不可开交,慢慢形成“嗜急成瘾”,迷失了方向,在错误的方向高效,只会错的越远,只有紧记“要事第一”,才能保持正确的前进方向,时间管理的方法是次要的,把握好心中的罗盘才是重要的。
轻量级MVC标准
2009-05-07 https://www.iteye.com/blog/javatar-381709
看到标题,估计有人就开始想吐了,没关系,你可以先吐完再看,现在MVC框架多如牛毛,没必要再重复发明轮子了,要声明的是,这里不是想要发明轮子,也没那个闲工夫去发明轮子,而是看到这么多MVC框架模样都差不多,想统一接口,减少迁移成本,Java世界里,最喜欢的就是定标准,然后就是一大堆的实现,估且这里也当一个标准来搞,纯属娱乐的标准。
注:下面的定义都是狭义的,用于限定本次要解决的问题域,你也可以定义你自己标准,这不是啥业界标准。
轻量级MVC定义:
- 框架对应用无侵入,不依赖任何接口类
- 框架零配置,零注解
- 简单易用,易于理解,暂且不搞RESTful,免得复杂
轻量级MVC接口:
- Controller采用setter注入请求参数,并支持层级注入,如:book.title.
- Controller采用getter供给数据给View,在View中可直接取到相应属性值,如:${property}.
- Controller采用任意非setter和getter函数处理请求。
- Controller采用函数返回值控制跳转,只允许跳转到另一Controller,不允许一个Controller对应两个View.
- Controller对Model的依赖采用setter自动装配,包括Model之间的依赖.
- Session参数,如:loginUserId,也通过setter注入到Controller,如果有请求参数注入了loginUserId,也会被Session参数给覆盖.
- View与Controller一对一,通过名称映射,并支持各种View模板类型扩展,比如:JSP, Velocity, FreeMarker, CommonTemplate等.
- 没有Controller时,View也能执行,相当于隐式Controller。
- 框架应提供COC接口,基于规则约定某个包名是model,某个包名是controller,某个目录是view,比如:com.company.module.controller,自动发现module,并以单例模式加载model,以原型模式加载controller。
总而言之,接口除了setter和getter,以及自动映射规则,什么都没有.
轻量级MVC访问:
http://主机名[:端口][/应用名]/模块名/控制器名/函数名.html[?参数名=参数值]
注:方括号代表可省
轻量级MVC实现:
符合以上接口的实现均可。
轻量级MVC优势:
业务逻辑不依赖任何框架,可以适配到任意框架而不影响业务代码,当旧的框架被淘汰,无人维护时,可以以最快的方式迁移到新的更稳定的框架.
理想是美好的,现实是残酷的,上面纯属个人想法,现实中困难多了,怀着美好愿景总是好的。
每次设计,你都会从什么问题想起?
2009-05-25 https://www.iteye.com/blog/javatar-394883
最近加入一个新的平台项目,看过基本用例后,在YY设计方案时,头脑中第一反应回答的问题:
- 中心领域模型是什么?
- 微核心是什么?
- 给用户的API是什么?
- 给扩展者的SPI是什么?
- 扩展者可否基于微核心替换任意位置上的实现?
- 服务域,实体域,会话域各是什么?
- 客户端,服务器端各自关心什么?
- 所有涉众都考虑周全了?
- 有哪些需要特殊化处理?是否可以抽象到一起?
- 设计有没有防碍非功能性需求的优化?
先行者特质
2009-06-09 https://www.iteye.com/blog/javatar-405488
约翰·科特先行者特质:
- 绝对诚实;
- 善于学习;
- 公正;
- 反教条精神;
- 勇于展现自己和发现他人最好的一面;
- 具有幽默感;
- 既能高瞻远瞩,又能脚踏实地;
- 自律;
- 自我平衡;
不管什么先行者理论,这些也算是做人的优点,摘抄下来自勉。
看好UCWEB
2009-06-09 https://www.iteye.com/blog/javatar-405513
关注UCWEB很久了,怎么也在广州待了几年,虽然现在不在广州了,
在Javaeye里认识的广州的Wuhua也去了UCWEB,
他Blog里全是广告软文,呵呵,我这个也算一篇软文,
最近阿里要和UCWEB合作,开发手机网上购物,
UCWEB的盈利点开始显现,其它的B2C电子商务网站估计也有合作的可能,
在3G大环境稳定后,相信UCWEB将会有突破性的发展,
浏览器一向造就明星企业的产品,就像雷军一直强调的UCWEB有可能做成下一个Google,
虽有吹嘘成份,但可以作为UCWEB的美好愿景,支撑企业的长远发展,
雷军为了UCWEB,也越来越高调,有点学马云,通过分享自己的见解,
来提高品牌的知名度,以提升用户量和覆盖率,这也是UCWEB的核心价值所在,
或许真的是掌握了入口,就掌握钱脉,呵呵,看好。
服务化
2009-11-01 https://www.iteye.com/blog/javatar-508080
最近忙于服务化改造的一些工作, 目标很简单,就是把一些核心业务服务化,做一些基本的SOA治理, 一般公司业务多了都有这个想法, 但开始治理时,通常业务已经积重难返, 说起简单的一件事,做起来却不那么容易, 我们的改造计划都排到2011年了, 服务框架的实现本来基于OSGi容器, UAT时感觉太冒进,改为做适配可同时运行到Servlet容器, 第一个改造的是比较稳定的用户信息模型, 花了五个月分析业务模型,两个月实现,现在进入了漫长的实施阶段, 再说说我现在正在解决的问题, 服务化后,肯定需要一个类似于UDDI的注册中心, 来协助服务消费者发现服务提供者, 功能性需求很简单,但非功能性需求远远大于功能性需求, 包括注册中心的性能,伸缩性,稳定性,可靠性,去中心化,状态一致,远程事件推送,断线删除等等, 最开始考虑使用SLP(Service Location Protocol), 但因没有可靠的Java实现,并且JSR140进展缓慢, 而且不能实现事件推送,断线删除等,所以只好自行实现, 开始看起来和平台现有的另一个配置中心项目的功能相似, 只需要把注册信息看做配置信息,直接存入配置中心, 谁知道这样一来把原本简单的配置中心,搞得很复杂, 现在终于决定把注册中心从配置中心拆分出来, 拆分工作最近刚做完,代码测试覆盖率也保持在95%以上, 就等测试部门回归测试和性能测试,希望一切顺利。
《第五项修炼》
2009-11-01 https://www.iteye.com/blog/javatar-508092
就像书里开篇说的,我们从小就被教导如果拆分问题,拆分世界,使任务和命题看起来更简单,慢慢的忽视了系统的看问题,忽视了整体的影响。
在第一节举的啤酒供应链案例,每个人都在做自己角色上正确的事,最后的结果却是错误的,而且当任何理性人在这个角色都会这么做时,表示问题不是出在人身上,而是系统上,有时候组织行为决定了个人行为。
书中主要以建设学习型组织为中心,从理论到实践,包括心灵转变,自我超越,心智模式,共同愿景,团队学习,战略和策略,领导的新工作,系统的公民等等。
很不错的书,推荐看。
治理与管理的区别
2009-11-15 https://www.iteye.com/blog/javatar-517767
通常来说,治理意味着建立和执行工作组为了一起工作而一致同意的工作指南。
具体来说,治理包括以下方面:
- 建立授权的责任链。
- 度量评估的有效性。
- 指导组织建立满足其目标的策略。
- 控制机制以确保遵从性。
- 进行沟通以使所有相关方都获得通知。
- 治理确定谁负责制定决策,需要制定什么决策,以及使决策制定保持一致的决策。
治理不同于管理。
治理规划需要制定什么决策,而管理是制定和实施决策的过程。
治理重在建立决策,而管理重在贯彻执行决策。
服务化基础设施
2009-11-15 https://www.iteye.com/blog/javatar-517793
服务化,也可以叫SOA,但在我们还是尽量避免用这个词,
因为它被炒得太热,一味的套SOA的概念,容易迷失原有的方向。
要向服务化推进,当然就需要搭建一些基础设施,来协助这个过程的实现,
那都有哪个方面的工作要做呢,这里把我暂时想到的列一列。
- 服务的定义 服务提供者要怎么暴露一个服务?服务消费者要怎么引用一个服务?
肯定需要一个声明式服务定义框架,可以用注解,描述文件,DSL等,
这个要不要用标准,要看这个服务化应用范围,
如果只是公司内部用用,就没多少必要,
哪样声明方便,对开发人员要求最低,对系统侵入性最少就行。 - 服务的调用 服务间的调用通常是远程的,
使各服务保持相对的独立,以及数据共享性,
整个调用过程的性能,可能是最关键的。 - 服务的交互模型 交互模型也就提供者与消息者的协议,
可以是强类型,也可以是弱类型,
可以是文本,也可以是二进制。 - 服务的生命周期 需要对服务的生命周期进行统一的,容器式的管理方式,
可以用现有的OSGi, IoC等容器。 - 服务的版本化 服务肯定是要升级的,
而在多系统以及大量集群环境下,
升级肯定是分步骤分区域进行的,
这样就需要版本化的支持,
通过新老版本交错的方式,达到平滑升级,
当然,新老版本是否兼容,
是否会引起脏数据等都是要考虑的问题。 - 服务的演化 服务的版本化,并不能全部解决服务的发展,
再好的治理结构,也不能避免混乱,
就像敏捷开发的“拥抱变化”一样,我们应该“拥抱混乱”,
当服务混乱不堪时,我们就需要重构,
这时,服务的合并,拆分再所难免,
版本化很难处理这种演进式改变,
那我们就需要一种机制保证演进过程的顺利进行,
比如标识某个服务过期,只允许旧的调用者使用,不允许新的调用者使用等等。 - 服务安全 安全是永恒的话题,
包括服务的可调用的范围,认证授权,隔离性等,
还有数据的保密性、完整性等。 - 服务注册 需要一个注册中心,
协助服务消息者发现服务提供者,
这样可以保证动态的增加提供者,
使整个服务集群保持活性。 - 服务仓库 服务多了以后估计会像我们的开发库一样错综复杂,
最后可能需要一个类似于Maven的系统进行集中式管理,
这样我们就需要一个服务仓库,
从服务仓库中我们可以知道哪个服务依赖了哪些服务,
并且可能在定义服务的时候需要声明这些依赖关系。 - 服务监控 通过Logger埋点,
监控服务的调用频率,调用时间,
可用性,节点数等,
以及报警提醒等。 - 服务自动化测试 服务的变更,升级,将影响大量的调用者,
需要一套完善的自动化测试框架保证服务的正确性和健状性。 - 服务开发过程 服务的开发,测试,部署,发布,下线等,
都是服务必然存在的过程,
框架对开发人员,测试人员,配管人员,运营人员的支持工作必不可少。 - 服务归属 当服务被多个应用调用或被多个部门使用后,
谁来维护这个服务,服务间职责的划分都将成为问题。
/20260119103922277.png)
/20260119103922307.png)