帮调一个奇怪的jsp显示数据的bug

struts2项目中,同事这样描述了一个bug:

在后台action中执行了一段逻辑A,再调用函数B,该函数为Action中的对象C赋值。在Action中打印C的各字段值正常,jsp页面中,使用el表达式显示C各字段的值,其中字段1有值,字段2无值。

另外一段Action函数中,无逻辑A,后续调用函数B等部分完全一致,返回同一个jsp页面,在前端可以正确显示所有字段的值。

经过大量调试无果后,我介入。过程如下:

  • 将页面上的字段值作各种替换,如输出字段1的部分改为输出字段2,或相反。此步骤是为了排除那种由于视线盲点死活都无法发现的拼写错误。无果。
  • 去掉逻辑A,运行,可以正常显示。恢复逻辑A,又变成异常情况。

至此基本确定错误范围是逻辑A,但逻辑A只是简单的新建变量、赋值等操作,看上去并不像会导致莫名其妙异常的那种代码。

又仔细看了看前端代码,发现其使用方式是用一个struts的iterator标签嵌套了一堆el表达式,el表达式使用的是struts iterator标签中定义的循环变量。再查后发现,该循环变量与逻辑A中的操作的某个变量重名了。所以页面上显示的是逻辑A中操作变量的值。

窗户纸捅破了,其实也没什么太高的技术含量。但调试代码中暴露的问题确实也挺让人头疼。

分而治之的思路如果掌握了,知道先把无关代码都注释了再调能减少很多猜测分支,调bug的思路会大大清晰。

所谓的相同逻辑在两段函数中运行的结果一个正确一个不正确,实际上这两种情况下jsp页面中根本就是访问了两组变量,但debug一下午,测试数据都是完全相同的那一种情况,姓名全叫张三……

不知道给变量规律化起名字的意义,起码循环变量都加个temp前缀,单数复数一个加s一个不加。变量名的起名规则就是,在定义变量的代码处向上数10行,找一个眼熟的名字,这……

一篇充满怨念的记录,项目规模上去之后,事事掌控的模式已经不可行了,分工之后,满眼都是这种无聊的问题。团队建设,看来还任重道远。

===

最近总是精神焦虑,无法集中精力想问题,效率有了很大的降低。生活中的杂事很多,还是要努力克服。黎明不远,加油!

反思——原型界面搭建

大约一年半之前的原型界面搭建过程,挑选了ligerui作为搭建工具,当时的想法是够重型,所有的控件都提供好了,所以可以实现快速开发。

但还是花费了大量的时间在处理一些技术细节上,印象最深的是左侧菜单的组织形式,是先按照用户级别分,再按照功能模块分,还是反过来。实际上,在后期需求渐渐明确后,当时的很多考虑都是不合时宜的,大量的时间就被浪费了。

需求获取过程,还是要尽快的接触用户,至于原型界面搭建方式,ligerui在技术层面已经很完善了,但仍然不如拿纸笔画草图来得快和方便。

以其昏昏,使人昭昭

标题语出《孟子》。

整理出一封安排工作的邮件。

背景

安排人总结与上级系统对接中出现的问题,其中之一是由于数据模型设计的不一致,某张表的对接工作完全没有开始,需要我拿具体方案。

我的re大意:

放弃之前数据模型设计的xx原则,表结构的改动包括xx,字段约束变更为xx。在此新方案下,代表用例xx。其余细节你补充,有需要的话找我讨论。

其实相比之前,这次还算有挺大的进步,起码说明了要让对方的职责范围(其余细节你补充),但细想仍然不算是一个良好的工作安排,至少缺乏以下方面的内容:

  • 要让对方具体做什么事,如“开发完成xx功能和xx功能”或“整理完成方案细节”
  • 完成过程中的关键节点,如“补充方案细节后,整理邮件并讨论,无意见后继续”
  • 要求的完成时间,如“两日内完成”
  • 完成标准,如“xx功能开发完成,测试用例完成,达到xx发布标准”

另外,不管是通过邮件也好,任务管理平台也好,之前工作的一个重大欠缺是,只有零散的任务安排,没有项目完成路线图。完成这个任务之后,项目整体进展前进了多少,又有什么任务可以开始进行了;如果这个任务没有按时完成,应该怎样调整,项目是否会延期,这些都应该是项目经理想清楚的事。

开发项目的特点就是工作任务及其繁杂,而且无法保证所有任务分解都在同一个层次上,所以日常工作安排会非常混乱,甚至无法找到一个足够完善的范式去表现项目进展过程。至今找到的比较好的模式包括:功能点清单、用例、依照用例的测试记录、零散的专题性说明。

技术出身的项目经理还要避免不断尝试新工具的癖好,牢记没有可以让你一劳永逸的银弹,工具的重要性远比不上日常不断的整理和调整。

 

 

收和放

从最开始工作的时候就有个朴素的愿望,我要做的不是赚钞票,而是造印钞机。构建一个工作系统,观察运转过程,不断调整,看着它不停的产出。但其实很长时间以来我都忽略了一个问题,如果你的最终目标的副作用之一是节省你的体力,那你在日常工作中就一定要特别克制你的懒惰。

之前定过几条规则,所谓的业务层应该怎么写,放下去让人执行,在一段时期内运转良好。但总归没有银弹,不可能有什么工作规范、最佳实践之类的东西能一劳永逸的解决所有问题,初期越是顺利,越容易导致意识上的麻痹。有推而广之作用的工作规范中,存在的任何瑕疵都会被数倍的放大,最终遵守墨菲定律,可能会出问题的地方,就一定会出问题。今天翻了翻别人写的代码,发现超过100行的代码就已经很难驾驭了。这也怪不得别人,放下去的东西,总要有个收的过程,才能发现不足,调整之后,才能再次的放出去。有了决策就要跟进,要总结反馈,切记。

 

项目组J2ee程序员的标志,你中招没 转载+评论

原文在此

校园级别的程序员的标志:

 

代码中最多的是嵌套if(null == xxx),还要告诉你,null必须写在前面,我靠。

防止把==写成=,c语言时代常犯的错误。由于null不能做左值,在写=的时候出现编译错误。一般来讲,在java中,由于boolean和其他类型不会作隐式转换,因此这么写没有意义。

写着写着突然想起来这么个代码:

Boolean b = true;
               
                if(b=null)
                {
                       
                }

 

顺利编译通过,也许把null写在==的左侧还是有意义的。

 

后台满是system.out.println(“——–程序应该会运行到此处的。。。userId:”)。

调试程序过程中,如果想在控制台中打印什么东西,最好用log工具,如已经在多少年前就俗到家了的log4j。好处是:打印日志的语句和控制是否打印日志、控制怎样打印日志的语句是解耦的,可以在程序中随便写打印log的语句,然后在正式上线后,通过某个选项,令其全部失效。

当年流行的组合是log4j+apache commons logging,在程序中引用commons logging的api,build path中放一个log4j的jar包然后再写个log4j的配置文件并且初始化一下,实际生效的就是log4j了。这样做的好处是,想换日志实现类的时候,不用修改程序代码。

今年的流行款是logback+slf4j,对应上面那两个东西。logback的实现据说效率高了多少倍,不过除了非常关键的模块外,这点开销基本可以忽略不计。
html页面总是对不起一两个div的线,老用firefox去框框显示那个div。

搞前端的都是神,我到现在也对不齐那堆div。另提一句,bootstrap是良心作,好人一生平安。
IO异常处理那个就是叠罗汉啊。

异常处理是个技术活,我当年的思路是,根本不知道有非受控异常这件事,出现受控异常未处理的编译错误时,点开eclipse的自动处理选项,然后按照心情选一个。

一点经验:

数据库异常、io异常就直接上抛,如果框架非得搞成checked的话(譬如ibatis2.x),发现了就给封一层RuntimeException,一直抛到顶层让这个事务挂了就好了。然后客户会明确的知道这个程序sb了,怒不可遏的给维护打电话,然后维护远程ssh,重启数据库了事。如果项目经理稍稍良心一点的话,针对这种错误可以做的包括:1、打异常log,2、给客户一个明确的提示“系统挂掉了,请联系系统维护人员电话是13xxxxxxxxx”而不是显示一堆异常堆栈然后再让客户翻电话本。想写段代码自动处理这些异常的想法不是不能实现,但对于业务定制类的系统来说,代价太大。

nullpointerexception、各种illegelxxxexception,其它各种开发人员懒得去学的异常,这些基本上都是程序的bug,开发测试阶段出现了就调整,打各种补丁,直至所有的测试流程都走通。实际运行阶段再出的话,类比上一条。

在业务基本走通,正常流程都没问题了,而项目组又恰好有足够的时间投入在异常架构上,可以做下面的事:分析业务,找出需要处理的业务异常,如根据身份证号查出了两个完全不同的人等,定义处理这些异常的逻辑,定义项目级别的异常基类api,之后就可以从底层一层层的加各种if判断,抛出异常,再向上找到该处理异常的地方,写catch代码。最重要的就是在抛异常的时候,把所有有意义的信息都记录下来,比如上面说的身份证号的异常,起码要记录身份证号是什么、找出的两个人的主键,另外还可以记录操作时间、操作人等信息。只要在异常抛出的时候做到这一点,随便你决定在哪一层catch,哪怕只做个log,都会让维护人员、后续开发人员感谢你的良心。

一般级别的程序员标志:
会struts+spring+hibernate|mybatis,面试神器。

曾经的观点:

怎样用这些东西:找个文档读一点,都能学会。

为什么要用这些东西:体现真正水平的问题。

现在的观点:

怎样用这些东西:做到随便给给技术,读读文档就能用上的,都是水平已经不错了的人。

为什么要用这些东西:网上答案一搜一大把,需要分辨是直接拿的结论,还是真被某些雷炸过然后很良心的告诉你,struts2真操蛋。

struts1、2、spring mvc这一层,用的并不多。由于没做过什么访问量特别高的项目,因此对struts2的效率并没有太多吐槽。现在的选择标准:1、是否提供了足够的语法糖让一般水平的人也能够快速开发 2、是否没有提供不恰当的语法糖,从而大幅度的增加维护难度。annotation、零配置这些东西,个人觉得最好用于元属性设置,而不要用于流程控制。曾经有个同事发现前台传进来的参数莫名其妙的会丢一个,后来发现在引用的某个jar包中有一个annotation方式定义的filter。尽管实际上的问题是架构组没有写完善的文档,没有做培训,但是经过那件事之后我也同意,这种东西放在一个统一的配置文件里面看着会更清楚一点,控制粒度也更细一点。

当年实训初学spring就觉得这东西很蛋疼,迄今为止一直没遇到复杂度高到有大批量属性需要注入的地方。aop的应用场景倒是遇到几个,不过出于对庞大的spring以及配置文件膨胀的恐惧,我宁愿改变整个的框架,定一个抽象层然后用各种各样的strategy模式。倒是觉得有完善annotation支持的轻量级aop应该是个不错的选择。

hibernate用的也不多,我好像对主流的s2sh有本能的抗拒……一直对sql的结构化有深深的执着,因为你真的不想没事总给别人调那一堆动辄五六行变量名很奇怪大小写都有的sql语句。所以在看到hibernate做某些复杂查询必须用hql的时候就放弃了这门技术了,sql本身就不想看,再发现这sql实际上是在java里面用String拼起来的……

ibatis/Mybatis一系用的比较多的原因是,职业生涯用到的首套一站式框架的作者就用的这玩意儿,属于马屁股性质的事情。这东西的好处就是把sql和java代码分离开了,程序看起来比较干净。但是让每个模块的程序员都去决定要写哪些sql,怎样写,同样是个很可怕的事情。所以当年我定义了一套针对每张表的标准sql列表,几项最基本的CRUD操作。select操作只支持id查询和各个属性的and相等查询。这个基本上已经可以满足80%的需求了,剩下20%,定好了配置文件分割策略后,找个sql好点的人慢慢写就是了。另外,这东西的一大槽点是只支持假分页,我们的处理方式一般是忽悠客户买个内存大点的机器就得了,不具备这种忽悠机制的同行们请慎重选择,ibatis想解决这个问题需要hack jar包,mybatis也需要自己写个插件支持,大概有个半天到一天的工作量。

再后来觉得配置文件有些繁琐,所以又在apache commons dbutils基础上封装了一套,不用写配置文件,定义好列名和属性名的映射关系后,自动生成CRUD操作并作db访问操作。在封装复杂的select操作时发现了nutz这个东西,觉得思路基本一致,就懒得再继续写了。

nutz提供的dao工具实现了用比较结构化的方法拼sql语句,试了试,用着还不错。事务管理机制据说有槽点,没细看。

决定我没有实际使用的槽点:1、不支持手动配置db和java的名称映射,而我给项目组定的映射规则又比较奇葩,给每个属性都写个annotation有点蛋疼。2、貌似是用反射方式直接读写java属性,而不是用java bean规范的get、set方法,而我的很多工具类都是做的虚拟属性,只有两个无比复杂的get/set方法,没有实际的属性。当发现annotation只能加在字段上时,欲哭无泪只好放弃了。

现在项目中用着的还是mybatis,用官方提供的mybatis generator生成配置文件,单表操作支持得很完善,多表操作自己写sql解决。

能分清楚group和having的区别。

关于db另一个要说的问题:复杂的东西尽量别放sql里面。orm层提供基本操作就够了,剩下的逻辑交给java层表达。做好封装,实在有效率问题,再专门进行优化。好吧,我承认我不知道这哥俩到底有什么区别。


数据库里的字段必须只能2个长度,不能32个长度,性能问题。表名要以T开头,蛋快碎了。

长度问题没看懂要说什么。前两天遇到一个问题,在oracle中如果用char类型的,而实际内容又不正好等于char长度的时候,select出来的数据是带空格的……各种trim都感觉不太好使之后,果断varchar2了。反正这点效率差异,早就被各种奇葩的业务逻辑给抵消了,还是那句话,有问题的时候再优化。

表名问题,我觉得加前缀还是为了跟视图进行区分。当表只有几张时,什么区分也不用做,当表有一百七十张时,什么区分都不管用。所以,战略上看需求决定就行了……

一点经验:通通加T跟没加是一个效果。现在项目中的做法:数据库中大部分的表都是对应了一个业务实体,这些类直接写名字就行,在这些表上建的视图统一加一个V_前缀,也就能起到区分效果了。一般来讲,一百七十张表中至少有一百五十五张以上都是这种表。其他的表,则大多对应了某些特殊场景或算法,实际开发中一般由专门的核心人员负责,可以按照权限控制、事务控制等实际用途,加个什么前缀,谁负责哪个模块就关注哪个前缀就好了。


会用jquery.ajax获取数据,不知道ajax的同步锁。

我也不知道。对于一切锁,我的意见都是,上个最大粒度的,保证数据一致性。出现的所有问题具体分析,逐个减小锁的粒度。

一会显示的表格有数据,一会又没数据啊,太生气了。

遇到此类抱怨时:1、告诉他,工业界没有玄幻故事,2、再提同样的问题的话,辞了他。让这种人觉得自己还有混在程序员界的错觉是对他的不负责。

详细记录当时的运行环境,一般都会找到原因的。

骚年级别的程序员标志:

懂div的float,clear的含义。

1、上一套bootstrap,解决80%的问题。2、剩下20%的问题,找个跟你关系不错的前端,没事多请人家吃吃饭,然后就解决了。


数据库超过n记录表横向纵向分表。

问题在于,n等于几。高估n无所谓,反正要出现的问题肯定会出现。低估n的话,造成的进度损失会让你有自杀的冲动,造成的数据损失会让项目经理有杀了你的冲动。

知道oracle的用with,这个sql写起来看起就舒服了。

这个也不会,粗略google了一下,确实有点用途。

看到aop能说一大堆废话,又是代理又是反射,就是没写过。

你的错误在于,不知道用途就研究实现原理。

DateUtil一定写过好多次,简直太复杂了,非常多的格式定义,那个static格式变量,必须要深刻理解才能知道。

1、有句评价说的好:把一个工具包的几乎所有方法都写到标记过时,这是得有多仇视这个社会。

2、自从有了JodaDate,妈妈再也不担心我的日期处理了。当一个同事又一次熬通宵写出一个DateUtil然后我拿出了JodaDate之后……

砥柱级别的程序员标志:

会架构程序,能用extjs或者easyui写个框架frame,还能写个递归menu。

所有的知识点都很基础,但是能把这一切都完整写出来,完成debug之后让项目组用上,一段时间之后还能维护或者添加点新功能的,都是中流砥柱。说白了,这是个情商要求大于智商要求的活。业务系统定制开发,实际上都是这种类型的活。你并不需要有特别高深的技术,也不会突然面对多么巨大的困难,只会在一个个看似不起眼的bug中,把所有激情都消磨殆尽。

会用ps处理图片,还能写上几个字,XXXX系统beta版本。

会ps的都是神,不解释。

基本上util包的作者,用log或者拦截器记录日志。

并且,愿意跟一切动过你util包的人玩命。

能用fiter或者Interceptor处理权限,但是搞不懂如何处理button的权限。

在业务级别去掉button权限的需求就好了。

真正的解决方案没有实际执行过,只是一个想法:系统建模的时候,权限模型直接建到操作级,比方说每个Action处理函数对应一个操作,针对这个操作定义每个角色的权限。button在概念上同样映射到权限就可以了。至于怎么针对函数做权限控制,随便你用xml或者annotation定义一下就行。

明白了异常处理转换成RuntimeExcetion太好了,不会丢失而且好处理。

异常处理真是个技术活。当我说,我也不知道我的方案好在哪,只是觉得你们的方式不优雅时,我清楚的听到了对方心里的嗤笑声。往往我的结论都会在大概三个模块开发周期之内被确认。

page分页里代码和css样式和类class都在jsptag里,认为没法分啊,这个是典型。

前端用于提交参数,目测所说的代码是计算page、rowperpage这些属性的。随便找套js grid控件,看看他们的参数提交方式,前端不依赖任何jsp,分到那个份上我觉得就足够了。

小牛级别的程序员:

知道url资源树和menu的区别。

不明觉厉。这种概念性的东西其实挺多人都挺不重视的,曾经很反对这种不重视,但是重视了很多年还真没重视到什么收获。现在的观点就是,用到了再说。

能手写css,懂important能拿来做啥,这个好玩得很。

又是前端,上bootstrap吧

能够理解数据库必须用主外键,否则那帮家伙一定会乱写程序。

只要是实体类,必须有主键,并且一定要有物理主键,不能只依赖于逻辑主键。id这东西,找不到其他用途的话就简单的当个快速查询定位的工具就行。随着业务复杂度的增加,你会发现它的表现力越来越强。在大部分依赖于持久化的业务类系统中,可以简单的定义,有id就代表这东西存在,没id就代表不存在,顺着这条思路往下想,很多业务都会简化。

只用id做外键,不要用神马身份证号、订单编号之类的东西。然后你的程序随便怎么写都能写得下去。

会设计数据库模型,几百张表的小意思。

针对真实世界,只作抽象,不作修改,保持整个系统概念上的一致性。然后你会发现,设计的模型会恰好符合数据库设计的各种准则。这时候这个数据库结构就能用了。

如果你设计出一张自认为很有用的关系表,却起不出合适的名字来;或者数据库中有一个不是纯粹为了效率问题而设置的冗余字段,相信我,你终将遇到一个你的模型无法表现的业务需求。

注释用//只有一行,不用/**多行,因为程序即注释。

jdk标准注释都不用,那javadoc咋办?

好吧,程序即注释这东西,几个水平相当、思路相近的人,通过不定期的结对编程、互相重构代码,还是可以做到的。如果是大规模的开发,还是建议通过架构层面合理的分层解决。

知道struts模型驱动代替属性注入,方便太多事了。

又一个语法糖。有了实际需求再用,到底用不用不要争论起来没完,遵循这两点就行了。这个真心不是核心问题。

用过this做参数传递,哈好多人都没用见过。

哈真神奇!这话真有人对我说过。

技术上this就是个指向自身的引用。某些具体的场景确实用起来很有意思,高层面的意义还没太想清楚,只有一个模模糊糊的印象,大概就是做了一件把自身委托给其他对象的事,封装了某个参数传递的过程,也就是封装了自身和被委托类的关系。

se级别的程序员:

研究过struts,hibernate的源代码,ui里有颜色互补概念,看起来是要舒服点啊。

学源代码要跟写代码结合起来执行,学到了新的模式之后,多想想有什么应用场景,但是真的实际使用要慎重。譬如说看到struts2的层层wrapper模式后就用了一次,被喷了好长时间

觉得struts,hibernate,spring,要扔掉一个框架,一定是spring,这个废啊。

让我选的话,我扔hibernate。

写过mvc,知道前端拦截器,中心分发器,后置处理,bean映射。

要知道就算没有这些概念,代码层面也一定会实现mvc的全部功能。然后找到没有这些概念的代价,哪些东西就耦合了,哪些变更就应对不了了等等。最后你的水平就提高了。

会用模型驱动user.save(),代替dao。

少传一个参数,概念上优雅了一些。模型驱动太考验建模能力,一定要在一个范围内把所有问题想清楚再使用。建议把DDD那本书看个两三遍再说。

不过这东西看上去真的很吸引人。

能用metadata生成一堆乱七八杂的代码,这下爽多了。

metadata的解释是“描述数据的数据”,比方说数据库的表结构定义可能就算是一种metadata。在写代码过程中能正确的抽象出元数据之后,眼光会提高一个层次,至于是不是要搞生成代码的工具,因项目而异。

曾经用过一段时间的freemarker,写一些轻量级的代码生成工具还是挺好用的。

研究过Annotation,用Annotation写过注解,知道Annotation如何继承,太复杂搞不懂。

拿Annotation实现过一套Model工具,没有深入了解过ejb,可能有点entity bean的思路在里面把。

前面说过一部分annotation了。这东西的好处就是把元数据跟java代码放到一起了,于是好找也好改了,坏处也是放在一起所以耦合了。如果代码量大到一定程度之后,最好把所有主力都集合到一块儿商量一下,到底是xml好还是annotation好。

在代码量没大到一定程度,或者annotation配置的数据仅仅是annotation所在的类自己用的话,可以在开发效率上考虑一下这个问题。jdk提供了语言层面的annotation操作工具,使用简单,有一部分的编译期检查,写起来比xml要舒服。另外,个人认为annotation的语法不太适合定义层次太深的结构,在类前面写上四层annotation再用ide做个formatter,说实话挺愁人的。

Boss级别的程序员:

仰慕一下。。。。

 

以上经验建立在如下基础上:

我做的项目是大部分是技术要求特别简单,业务要求中等复杂,需求变更特别频繁,开发人员平均素质不足,工期不是很紧的类型,所以关注点集中在如何通过分层隔离业务复杂度,以及如何通过语法糖来降低开发复杂度。bug方面,比较关注的是影响数据一致性的bug,只要不影响数据一致性,哪怕系统直接挂了,都不是影响项目的生死因素。

在做技术方案的时候,比较倾向于:

1、通过各种设计模式封装复杂度,提供尽量简单,甚至无脑开发的接口

2、忽略一切效率问题,在业务打通之后再想优化的事

3、能在编译器做的事就不往运行期放,哪怕会影响开发的灵活性

看看我的软件作坊

总感觉自己怎么也逃不开软件作坊这个概念,即便到了今天,我的团队规模已经基本接近于一个标准流程下的软件开发团队,平均战斗力虽说还有所欠缺,但怎么说也在及格线以上,但就是在工作中的方方面面,“山寨”“不正规”这样的词汇无时不刻不在我的心头悬着。

当年初入江湖,买了本《走出软件作坊》,如获至宝,每天十一点开始读半个小时,在书上做了各种各样的,各种颜色的笔记。比方说在对新人的评价上,“不讲道理,要讲经历”几个字被我多次的花圈,“一个讲究吃穿用,好享受或者满口脏话习惯,毛病一堆,或者不孝顺父母,或者满口介词的人坚决不能要”,被我花上横线还在旁边写上“你躺枪无数”来随时提点自己。总觉得书中每一句话都是启发,但启发来启发去,该有的不踏实感还是有。

后来想明白一点了,那本书的副标题叫做“三五个人十来条枪,如何成为开发正规军”,再数数自己手里这几个人几条枪,把厨子司机看门老大爷都算上,可能也凑不够这个数目。其实自己远没有走进作坊,想着怎么走出,当然怎么想怎么纠结。

再后来,一个偶然的机会,终于在人数上达到了软件作坊的级别,小200平米的办公区横七竖八挤下了十四五个人。咱也好歹当上了高层干部,下面有中层,中层带领着基层,层次化管理初见规模。美滋滋的做了半个项目之后,一个平淡的春节假期,几经人走人留,我又被打回了原形。

七手八脚的凑合到今天,终于又有了一支还算过的去的队伍,有业务骨干,有技术熟练工,有培养对象,有还算不错的男女比例和办公气氛。好好歹歹的,我又凑成了一个软件作坊。在工作意义上和财务意义上死去活来两三轮之后,怎么说也得有点长进,时至今日,说一句我要走出软件作坊,应该还不为过吧。终于能安慰一下自己,升级了,该升点新技能点了。

12年一个绝佳的机会,让我与某大型软件公司直接过了一下招。当然了,说是过招,其实就是在我的主场很不厚道的把对方涮了一把,谁让我船小好调头呢。不过赢是赢了,过程却很让人郁闷。就我的了解,对方的项目组水平有限,历史成果很悲剧,销售人员很耍嘴,但包括我,包括我的员工,包括客户那边的最支持我的人,都相当一致的觉得,那才是个看上去能干活的公司,相比之下,我不行。

这世上有些事情,概括起来很简单,譬如说一句“软件作坊干不过软件公司”。但落实到执行层面,到底是哪些原因导致的干不过,哪一天的哪一件事,一件一件积累起来,就让我们怎么看怎么都不想干事的人,我想了一年,仍然没有清晰的答案,只有一些零散的念头。

这个项目启动之处,我就有很明确的想法,战术服从于战略,军事服从于政治。本次开发所承担的战略目标是在本行业打响品牌,政治目的就是应得包括我本人在本地区个人形象在内的公司口碑。本身这个目标不算错,但放到我这样一个新手又有些偏执的人手中,多多少少让我们吃了亏。

初到客户那边,第一件事当然是了解业务。第一轮,客户的业务很简单,并且已经有了信息化系统。这个局面让我感觉相当为难,制定了第一个战术目标:不定义项目scope,竭尽全力的吸引客户扩大需求。小作坊体制下的良好执行力使得这一绝对犯了行业忌讳的目标得到了相当大程度的贯彻。公司全员开始没日没夜的加班,小心翼翼的跟客户聊天,几乎阴阳怪气的启发客户,您一定要在信息化中干这么几件事。这一轮下来,就是小半年,结果有二,一、客户没全部听懂我们的启发,二、客户觉得我们很牛,胃口被吊得很高。

跌跌撞撞的调研了一遍需求,也算成功的在下属中培养了一个业务骨干。期间经历了与既是对手也是伙伴的某公司的分分和和,与项目总集成商的勾心斗角,项目组增员的各种坎坷。当业务在我自己心里形成了一个模糊的骨架之后,我决定进入更实质性的沟通、设计阶段。国内的项目开发者最喜闻乐见的“原型开发”、“见面驱动”方法论我多少还了解一些,于是开始做原型,准备沟通。这个决定本身也没有错,甚至可以说是做保证此类项目成功的必经之路。但由于客户的组织结构复杂,以及自己的一点懒惰心理,错误的将主要的沟通对象选为了客户的高层组织中的中层干部。他们的想法很多,角度很好,层次很高,但恰恰最缺乏对实际工作中困难的把握。业务部门搞信息化为的是什么,还不是解决实际困难,提高工作效率。所以在错误的方向指引下,开始了一遍一遍的在用户体验方面修改原型,时至今日,这项工作几近烂尾,浪费的人力物力相对于我自己的能力来说,不可胜数。

并且另一个没有考虑到的,或者说是考虑到了也只能硬着头皮上的事,作坊体制下的执行力仅仅体现在执行上,任何富有创造性的工作,在只有一个大脑,所有员工都充当四肢的组织中,其工作效率只取决于核心的工作输出——嗯,也就是我的生产率。所以当一个庞大的方案事无巨细的压在我一个人身上,并且我又极为固执的不肯削减任何既定战术目标的时候,工作时间的主要消耗,就落在了不停的工作上下文切换上。最终的结果,就是各式各样的半成品,都有用,但都不能作为最终成果报给客户,也不能作为肯定的结论指导下一阶段的开发。

期间,还充斥着各种各样的文山会海,各种各样的ppt、汇报材料,各种各样的高层沟通。每一个无关到不能再无关,细微到不能再细微的问题,累计起来,就成了压倒工作成果的最后一根稻草。

于是,在过去的一年内,工作几无进展。

好在,成功的撑了过来,在没有犯大的错误的前提下,客户没有否定我们。并且,战略目标的第一阶段基本实现,后面再不会有“吹牛”任务了。想必今年主要的事,还是踏踏实实的做设计,搞沟通,写代码。

前一段时间看了马督工的《大目标》,这位工业党激情澎湃的分析了一下工业社会相比于农业社会的进步,即在拥有“造机器的机器”的情况下,社会的生产力是可以沿着指数曲线上升,最终完胜只能接近线性上升的农业社会。对比一下,实际上作坊相比于公司,也是类似的道理。发展方向上依赖于核心,具体工作上依赖于师傅带徒弟的模式。也许短期内,可以凭着个人能力和团队的凝聚力,办成很多大公司办不到的事。但长期来看,既不能做到技术实力的良性发展,也不能通过简单的增员扩容达到提高生产力的目的。相比之下,大公司也许任何一个具体工作都干不过我们,但任何一个具体工作都能起码做到及格线以上,并且,是能比较严格的在“限定时间内”做到及格线以上,保证deadline。在it行业,一个拥有成熟工作流程、体制的团队,实际上也就掌握了“机器造机器”的奥秘,技术部门可以做到完全满足销售目标,不拖后腿。这样,在同等条件下的竞争,作坊即便亮点再多,在别人眼中,也只是作坊。

很肯定的说,再重来一遍的话,我依然不会定义项目范围,依然会让战术服从于战略。毕竟归根结底,产品质量才是我心里的生命线。不过既然走过了那一步,今年还是要把重心调整一下,保证作坊优势的同时,尽快成为一个具有成熟开发实力的团队。

天天心里念叨着,现在自己干的这行业是一片蓝海。看看在新一年能再赶上几波吧。

 

bootstrap风格框架开发说明——信息展示页面

页面效果如图:

image

除基本库以外,需要引用的文件:

  • default.css
  • bootstrap-extends.js

以上两个文件,封装了若干页面控件,通过这些控件的组合,实现原型图中的页面效果。为了保证页面风格的统一,尽量不要自己定义样式,必要的时候先定义通用样式再在页面中使用。

页面标题

<div class=”page-header”>

<h1>您好:xxx <small>当前日期:2012年8月1日星期一 农历八月十五(<strong>中秋节快乐</strong>)</small></h1>

</div>

class=page-header的div中,使用h1标签定义标题内容,使用small标签定义副标题内容,以上html代码的效果为:

image

段落

<section class=”info-section” id=”work” data-title=”工作概览”>

</section>

使用html5标签section,通过data-title属性定义段落的标题。在section标签中,可以该段落的实际内容。以上代码的效果为:

image

内容组

<div class=”span6 field-group” data-title=”今日工作”>

<p>

<span class=”btn-group”>

<button class=”btn”>按钮组1</button>

<button class=”btn”>按钮组2</button>

<button class=”btn”>按钮组3</button>

</span>

</p>

<p>文字内容(其中<span class=”label label-warning”>3名</span>必须于今日内完成) <a href=”###“>查看详情</a></p>

<p>文字内容 <a href=”###“>查看详情</a></p>

<p>文字内容 <a href=”###“>查看详情</a></p>

</div>

使用class为field-group的div包含详细内容,data-title属性指定标题。该div可以使用需要的其他属性,如包含在row内的时候,可以使用spann属性定义大小。在div内部,可以使用p标签包含具体内容,也可以使用表格、超链接等元素,与一般的html的用法相同。

由于已经定义了该div的标题样式和背景样式,因此不需要使用class=well控制背景色。

说明

示例代码可以参考已有的代码。理想情况下,页面中应该只包含业务信息和各元素的class、id等属性,即强调代码的语义含义,弱化代码的样式含义。实际中可能做不到理想情况,但要尽量减少页面中的样式信息。

具体的显示样式在公共的css和js中定义。示例页面中的边框、背景、分割线都是由公共代码自动添加的,这样做的好处是,如果想把灰色风格改变为蓝色风格,不需要改动具体页面的代码,或改动量非常小。

自编作坊程序员面试题

 

一、简述题:

任选3题,面试官指定1题作答,有1次换题机会,口述回答(5分钟准备,5分钟作答)

另外自选1题笔答。或由面试官指定一题笔答,允许上网查询资料。(15分钟以内)

l? Java&JavaWeb:

1、对面向对象的理解(提示:含义、特征、与面向过程的区别)

2、struts2或其他mvc框架与servlet的区别,优劣点如何

3、举出三个以上Java容器类,并写明应用场景

4、抽象类和接口的区别

5、redirect和forward的区别

6、使用配置文件和注解进行配置的优劣理解

7、在人人网(www.renren.com)中点击一篇日志,url为:http://blog.renren.com/share/84463276/14252290961?from=0101010202&ref=hotnewsfeed&sfet=102&fin=3&ff_id=84463276? 点击之后,页面显示了这篇日志的内容。在技术层面描述这个过程。(提示:第一步,浏览器向服务器提交了http请求,内容为:xxx)

l? Html&Js

1、对Html语义化的看法

2、对table布局和div布局优劣的看法

3、js验证和后台验证的适用场景

4、对js闭包的理解

5、对html5和css3的了解

6、id和class的适用范围

7、列举两种以上流行浏览器(同一浏览器不同版本也可以)性能和html、js解析逻辑的差别

l? 数据库:

1、列举两种以上流行的数据库,说出他们在sql语法上的任意一点差别,谈谈对其应有范围的理解

2、对Hibernate或ibatis的理解,优势和劣势各是什么

3、列举两种以上数据库中可以存储字符串的数据类型,并说出它们的差别和适用范围

4、列举两种以上Mysql数据库的存储引擎,并说出它们各自的适用范围

5、采用任意一种流行数据库,设计数据库结构满足以下需求,写出sql:

销售员工信息(姓名、性别、出生年月、入职时间),员工分为组长和普通员工两种。

每个销售项目(名称、项目开始日期、结束日期、总金额、当前进度,项目情况)由一名组长和若干名员工负责,不同的项目的有不同的项目情况,如售楼项目有楼楼盘地址、面积,工程项目有监理单位名称,招标单位名称等

l? 杂项:

1、谈谈对软件配置管理(SCM)的理解

2、软件公司有不同的软件项目,每个项目存有若干文档(500个文件左右),2~3份源代码目录(2000个文件左右)。公司成员有10人,其中5人处于同一场所,另外5人分布在天津市区、广州、新加坡。设计一套最优化的文件共享方案,使大家可以协同开发。

3、谈谈你对svn和git的优劣理解

二、业务理解题:

任选一题,笔答(10分钟以内)

1、阅读某行政审批制度,设计一套相应的电子办公系统,描述其功能

2、任选一家电子邮箱网站,为只具有计算机基础操作知识的人写一份使用说明书,从注册开始,描述如何给lzmgzyx@gmail.com发送一份简历

三、项目管理题:

笔答(10分钟以内)

某公司要开发一款员工档案管理系统,如果由你负责这个项目,你将如何安排项目的人员、进程?

四、程序设计题:

可以选择上机、手写代码或描述流程。(30分钟以内)

在html页中设置三个input,每个input输入一个数字,点击提交按钮之后,将数据提交到后台,经过计算之后,在新页面中显示这三个数的和

提高(可任选若干项实现,也可以实现):

1、验证输入必须为数字,否则不允许提交

2、如果输入的为三个相同的数字,不允许提交

3、新页面中按照数字顺序由小到大显示:【数字1】+【数字2】+【数字3】=总和

4、支持数字大于9223372036854775807的输入

5、支持形如:123,456,789带有分割符号的数字输入

6、支持前台只写一个input,用标点符号分割,后台程序效果不变,如输入1;2;3,显示6

7、在google网站(www.google.com)的搜索框中输入1+1+1,搜索结果的最上方会显示Google计算机的计算结果。考虑利用这一工具实现上述的功能

bootstrap风格框架开发说明——首页菜单

image

现共支持2级菜单,数据结构如下:

一级菜单:

  • name:显示的中文名称
  • children:数组,每个元素表示二级菜单

二级菜单:

  • name:显示的中文名称
  • url:点击之后,刷新iframe的地址
  • icon:显示的图标,使用bootstrap官网上介绍的第三方图标插件。为空时默认为”tasks”