早前发文说要分享,马上进入了财务系统的开发,拖到现在,见笑了。
我在月初离职了,所以到处跑,找工作,想想南京、苏州、无锡(去玩的)、杭州(路过)、上海、珠海、深圳、广州。觉得找工作也差不多尾声了,就留点时间把这篇发出来吧。
总体来说,就是我在毕业三个月后来到这里,然后从零开始造*造了一个还算健全但不算完整的OA系统。
做了不少系统/模块,有很多都能写好多篇文章。毕业后这两年太神奇了,简直是在刷.NET,从一开始WPF,然后WCF、WF、MVC、EF、前端越刷越多。刷多了也有缺点,深入不足吧,总得有得失。
流水账是个好方式,那就流水吧,这里是我最后一份工作,23个月的事情。
初出茅庐
作为一个应届毕业生,我不知道公司会给到什么资源,会有什么话语权,会有什么安排,一开始到来必定是战战兢兢的。虽然我知道招聘的时候说明就是做OA,公司标榜*平等开放,开始也会无所适从。我以为会分派具体任务,不过协助了一个即将发布的项目后,马上就开始了OA的旅程。那种精确具体的节奏到发散的节奏,从一家外企跳过来,还是无所适从。
不过,我很大胆,或者说,哪怕在上家公司那么严谨,技术上的看法我从不掩饰。我只是个程序员,没有比不能坚持和直述自己技术意见更糟糕的了吧。
我当然会跟感谢上司对于我的信任和公司提供的机会,换个地方或许我被炒好多次了。
蓝图,大系统变成“小系统s”
这是我和上司和老员工们的第一个争吵点。
我和一些同事交流,了解过公司的“快”文化,也了解了项目寿命不长的问题。作为创业公司,拿到最后一轮融资到上市不过一下子,并没有暴利支撑着公司可以持续地“输”,但创业时期的“快”方式根深蒂固,很多项目为了快速完成,要么外包,要么是实习生或者快速搭建快速失败的。公司的主业务尚好,可以有持续投入,但OA显然不是主业务。虽不至于有“上了贼船”的感觉,但是我非常清楚地感觉到,我们只有一颗子弹,打中了才会发给你下一颗。
我会去开这一枪吗?没有,这不是会不会的问题。如果规则本身有问题,我就直说,然后解决它。所以我提出了,将系统设计为业务分布式的系统。这也促成了OA的第一个子系统——Message Center的诞生。MC就是这个整个OA的消息中间件,也是至今Bug最少的系统,因为它的功能很简单,就是一个发布/订阅模式的消息中转系统。
我的想法就是把OA拆成多个功能独立的子系统,不仅功能独立,运行也独立,仅仅通过MC进行服务的发布和订阅来通信、协作,也就是一种SOA概念的实现。为了实现单一原则,基本上,连系统调用自身的功能,都要通过中转调用服务。
敢这么做的另一个原因是我预计公司封顶也就1000个员工,那么这些系统都不是高负载型的,业务的变化率才是系统的性能瓶颈。
技术人员的天真我也有,你以为你的想法很容易,但是要别人接受却不容易。伙伴的想法原本是一个大型的系统,而且以往开发的做法和大家对OA原本的设想也是如此。实际上如果出一个需求做一个,最后形成的结果估计是一堆系统共用一个数据库,然后业务复杂度和数据库复杂度都在膨胀。甚至我觉得这不叫B/S,干脆就是B/D,不过就是堆砌的事务脚本。这给我感觉就是前人挖坑后人填坑再挖坑。
好在我有耐性,大家也都有耐性,愿意为实现花时间讨论的团队其实挺幸福的。我不记得多少次从下班跟大家争论到9、10、11点,多少次长时间地说服、争论、设计、重构、妥协。是的,还有妥协。
我的做法当然彻底,每个系统既然独立,那么该独立数据库、用EF而且允许UI层LINQ读操作而限制写操作、纯面向对象去除表存储概念、所有通信只通过消息中转、仅用Nuget同步子系统间的代码。为这个,大家开过会,我介绍了EF,说明过很多细节为什么要这么做。这个过程是很锻炼人的,因为要说服别人首先要说服自己,而说服自己的唯一方法是了解更多。特别是当双方“斗争”白热化的时候,双方思想都会迸发出最灿烂的火花,我从他们那里拿到的技术经验、业务经验、想法,对于项目成功必不可少。
这样,就有了第一个系统,作为中心的MC。如上所说,是个发布/订阅模式的消息中转,它不作任何状态保留,只转发消息,基于WCF实现,提供了一个Nuget上的Client。现在,它还有了同步/并发转发的功能,同时是一个可平行部署的系统。按照原本打算,二期的话应该具备日志、消息失败处理、异步消息、缓存的能力、.NET外平台客户端API。或许应该单独写一篇再分享吧。
这是半年之前的图,如今,基本上OA就是在这基础上扩充的:
认证系统,从这里进去,从这里到任何地方去
我的想法并不能完全实施,认证系统(Authorization)就是一部分。认证系统和考勤依然并在了一起,通过账户权限让它“看起来”是独立的数据库而已。不过这无伤大雅,对于一个连蛋都还不算的系统,在实现里该有一定妥协,时间会校验它的。
认证系统是同MC相差不远,我要做的是一个对整个OA单点登录和权限的支撑。
登录方面,它的主要问题是因为拆分系统产生的跨子域问题。我测试然后实现了跨域登录的问题,非共同公共域授权登录的问题,然后花了一段时间去解释登录失败的原理和跨域的原理。权限的话是一个权限-角色-用户的模型,想必许多权限系统也类似。前文下面也有权限管理界面的配图,顺带说一下我选择了使用Metro的扁平化风格,毕竟连设计师都没有,UI和交互得自己想。
在上个星期,我又为权限添加了一个基于语法分析的动态授权模块,以解决业务授权太多管理膨胀的问题,还有业务规则变动太大的问题。这个模块的功能,就是把动态写的授权表达式如“Accounts(1).Groups("IT部门").Accounts(Role="经理")”,解析成“账户1在IT部的经理”,来进行或者确定业务的授权对象。由于是写了一套简单的语法设置、语义分析、表达式计算的功能,所以能支持更多的语法,也会陆续添加更多语法。算法自己还不是很满意,希望有做过编译器或者比较了解的朋友能提供点帮助或者交流下。
工作中心,从这出发
工作中心(Work Station)就是传统意义上的Portal,是整个OA登录后的默认入口,同时还包含了考勤系统。考勤系统是我和同事以及外包同事共同开发的,是个业务类别系统,包含了考勤统计和审批的功能。
在前文里可以看到WS的界面是平铺着各个系统的条目的,这不是设计原意,原意是留给一个用户订阅的主页,根据订阅获取到相关信息。不过看到这里你们也知道,这个系统还什么都没有,所以只能用连接填充。
即时通信引擎,就是现在
可能在公司的设想中,我这是不务正业。在我看来,我们需要一个即时通信的系统,能够将系统消息第一时间推送给用户,这比定更多的业务规定有效得多,重要的是即时通信、即时解决。
它完成在我不知道有SignalR之前,所以手写长轮询实现了。三周时间,我将它实现了,并挂上了Azure的试用账号做公开测试。它并不完美,因为我发现流量占用太大,所以不得不重写很多代码,把原来的全量获取值全部改成了增量算法。虽然不幸工作量突然大增,但成果让人满意,也走进了Callback Hell,至今还没解决。
总体来说,它实现了即时添加好友、多人即时通信、系统消息、用户系统互相通信的功能。十分感谢当天参与测试的朋友。
后来,同事做了微信的服务端后,这个系统也成功通过消息中转给微信用户推信息了。
前端框架,用jQuery造的*
这是个大胆的做法,因为我抗拒了BootStrap。BootStrap很快,很全面,大家也都在用。网上社区里红红火火的,大家都会跟风说这个多好怎么好。
但是,这不是我想要的。一方面,在前端我不相信有一个包含样式的框架能成为一套长久的标准,何况还是一种大众化的事物;另一方面,我不想将整个交互模式交予第三方之手,长久来说这将会有后遗症。我恐惧一种情形,就是在BootStrap的大框架前提下,整合了各种插件,最后为了一个又一个无聊的Bug打一个又一个连自己都不大理解不大能维护的补丁。
所以我写了自己的一套简单的前端框架,命名很简单,就叫OA Style。
OA Style为了实现一套扁平风格的样式,类似Metro,将主体集中在信息上,不作各种圆角什么的多余的样式,仅仅为了看起来简单、用起来简单。它的设计理念是兼容、原生、简单和易用。这套样式尽可能地兼容着原生的HTML控件样式,重写的成本一个控件套一个控件加一堆样式的方式让我心生厌倦。在此之上,我再继续开发着按钮、翻页表格、拖柜式弹出框、重写Alert、多重度色彩。它依然很轻,因为它依然在开发状态中。
我从前认为这些简单的样式实现也简单,但当做起来的时候发现十分不一样。我不得不去“学习”审美,学习配色、对比、对齐、布局方式,才能满足最基础的视觉心理。
这个学习的过程在项目中变化,大概可以让大家看到:
工作流引擎,赶上变化
当然,是没办法做到网页工作流编辑器的了,这样就不是按月为单位算得工作能实现得了的。实现方式是在Windows Workflow上加皮,而且数据隔离开,因为未来可能会自写底层,现在先解决能用的问题吧。
我实现的引擎,是实现了多个关于自有流程、审批等的Activity,再用VS设计器设计工作流,将XAML上传到工作流后台并提供该流程服务的引擎,所以我只叫它引擎。
与它配合的,还有一套在财务系统中实现的动态申请单模块,动态的申请单加上动态的工作流,支撑了业务变动十分大的系统。当然,还有之前说的,动态分析授权的模块。
财务,最痛然后再站起来
这是最痛的地方,因为它失败了一次。失败的版本由于计算正确性无法达到要求,所以我提出重做。
我参与了一半需求的会议,不过中途就转回了上面系统的开发。在开发中途加入到了上一个版本的财务系统,当时是和外包同事协作。从看到项目起我已经产生了抗拒感,如果我是处女座,我已经被逼死了。反正,这个项目我有参与,但是它失败了,然后我提出重做,然后今年就由我来重做。
但是到了今年,就没有外包的资源了,要求却定会比上一个高。这是财务预算控制的部分,也差不多是财务工作的一个大头,从定制预算到预算使用的审批。
我从来都不怕尝试新鲜事物,所以我引入了DDD的方式。这是第一次这么做,是一直以来一个直觉,虽然到现在我都还没深入理解过DDD。
首先是撰写了一份文档,这份文档定义了系统设计到得知识和我抽象“创造”的知识,比如货币、汇率、预算、周期预算。这份文档说明了对于这些知识的定义,对它们的操作方式,规则。你可以视为这是一份需求分析,但我更倾向于当做一份基于需求分析产生的共有知识体系。因为用这份文档,我做得更彻底。
首先如上面所说,我用EF彻底“剔除了”数据存储的概念,纯粹地把领域对象用面向对象实现;然后,把代码,用文档“生成”。是的,文档将知识和层级分为了四部分,那么领域层就有四部分;文档定义了实体的关系如何,我在EF设计器中就如何设计模型;文档定义了怎么操作,我就怎么定义工作单元;虽然不用中文方法名和属性名,但是命名都是按照自然语言语义化的。
这么彻底,仅仅为了统一整个知识体系。虽然我没有细读DDD,但是在我看到的、感觉到的和我想要的,就是这个样子。整个项目只有一个知识体系,没有什么表、关联、增删查改、读取插入、存储同步,只有创建、添加、更新、调整、转账、记录。
后面工作越来越不在状态了,有公司的事,也有自己的事,慢慢放慢了节奏。
现在离职了,项目是交接了,不知道成败如何。
微信,这是个惊喜
微信的服务端是同事实现的,这是个最大的惊喜。
我们的微信客户端有打卡、考勤、投诉、查阅、简单办公的功能,而且在很短时间久实现了。这是同事的功劳,也是对我架构设计的最大肯定。
一切功能,除了在微信实现,在底层,不过是接入了MC。上面所说,我们所有的功能都通过MC发布了,只需调用即可。我相信这样的设计不仅仅会对微信,还会对将来的移动客户端有着同样地推进效果。
OA还有更多
要知道,我们是个共五人、正职二人的团队,所以同事还有其他方面的实现,主要是业务方面,他的经验阅历都更为老道,各有所长各尽其职吧。
基于上面基础,同事完成了HR得人员管理系统、薪酬管理、传阅功能。同时,OA还支持着一个CRM。在计划中,公司原本游离在外的各自独立的系统会逐步统一账户体系接入OA,最后把从内到外的系统统一在一个SOA体系下。
在计划中,我打算为MC加入上面所说的功能。MC集中了所有内容后,一切围绕它展开就变得轻松和理所当然了。你监控它就可以监控真个系统的运作,因为所有独立的系统必定要通过MC来跟其他支撑系统合作才能完成业务。所以你在MC可以监控、日志、缓存来让整个系统变得高效可靠,这也是我想去实现的。
上面的系统,或者仅仅成为模块,都有很大的创造空间能做得更好。比如账户我想更丰富内容,我想做个社交化的办公环境,我想通过提供有限组件做个简单可靠的工作流设计器,......
我还应该做一个文件系统,当然考虑的就是权限、吞吐量、存储的这些问题了,自当去学习便是。
我还有更多
说真的,今年在公司过得确实不算开心。去年公司业绩不好,没有年终,...,好吧,有一个热水壶......
在这之后,公司进入了一个紧张的状态,各种丑态“原形毕露”来形容不为过。然后IT部门一片一片地走,一开时是移动集体逃脱,然后前端群去了网y,接着Java的一片w品h,各自飞散,难得0离职的.NET团队抽调正在做iOS了。在薪酬的敏感问题上处理不当,更是让人不爽。
我cc过全部门*过总监的安排、投诉过饭堂、和CEO直接谈过,这样还是符合个人性格的。我就是个程序员,有话最好直说,免得太别扭。
公司也不差,给了我一个梦幻级的工作环境,至少秒杀大部分公司吧。今年拼命的机会少了,毕竟没那么好心情了,反而世界大了。跑步断断续续跑个二十几圈还可以,入门了钢琴,旅游了两次。人在广州啊,吃了不少东西,各种各样,挺不错的。
下一份工作不知道会是什么样的,期待一下也不错。