锁定老帖子 主题:从毕业到2010的Java程序员生涯(二)
精华帖 (0) :: 良好帖 (0) :: 灌水帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2010-02-01
最后修改:2010-02-09
年纪大了就喜欢回忆从前? 不。 人生又走到了未知的分岔路口,停下脚步回眸过去的路,正是为坚定向前跋涉的心。
过去通宵达旦努力研究的技术在现在回头看看都初级了点,但一个人处理问题的方式和态度不会过时。我心血来潮,花了不少时间来翻看工作日记和旧项目,力图总结一下工作5年的得失。殷鉴不远,可以前知也。 (二).混沌年代:JSP开发前面讲到我是在地税组,除此外开发中心还有国税组和项目组,一二十个开发人员。我在地税组做了2年多,后来公司成立技术组,我脱离地税组成为技术经理。 地税组多的时候6、7人,少时2、3人,负责地税申报网站和一些相关项目的开发和维护,经常跑地税局。招我的时候,开发中心十几个程序员基本都是做php和delphi的,实话实说精通JAVA的一个也没有。从历史来看,以前3、4年一直用php做网站,用delphi做客户端,只是随着04年起J2EE平台在省税务行业逐渐占统治地位,公司才开始进行技术转型。一大批项目都要从C/S架构转向B/S架构、从PHP转到JSP,这是公司当时的技术大方向,我后来几年的个人发展其实是顺应了这个潮流——不过当时的我自然想不到这些。 大家都知道,技术平台转型是很危险的。虽然说船小好调头,但其实也没这么容易,招聘一批Java高手?No,公司一向的策略是招应届生,以旧带新能干活就行,便宜嘛。而且最好是本地人,否则一年半载就跑掉的概率太高。也没有什么培训,完全靠自学。这是内部现状,外部呢?那时候电子政务还没兴起多少时间,税务局离成熟的客户还差得远,那时候往往是开一个会,说一堆模模糊糊的要求,然后给你一个最后交付时间,等你开发了一半会突然来个电话说:“唉呀,我又想起来还要什么什么”。而且他们会认为什么功能都很简单,“明天给我行不行?”,听到这种话就考验你的忽悠能力了。不像现在,国地税已经熟悉了软件开发的基本规律,甚至会自己写好需求文档再来跟你讨论。强势又不成熟的客户会让你疲于奔命,一定要学会拒绝客户的不合理要求并且把守住需求边界!这我深有体会。 加上与中国大多数软件公司一样,这是个不讲究技术(实际也没多少技术含量)和代码质量的小公司,他的理念是服务至上(客服人员与程序员之比是1:1强),而实际上的生存之道是要与相关部门保持良好的关系,这才是首要的。因此技术微不足道,至少在老总眼里如此。你只要实现功能,谁也不来管你的代码是不是把一坨代码复制粘贴到另一处。很自由,是不是? 在这种情况下,结果你也猜到了:从原先就很糟糕的php转换到对技术要求更高的J2EE,结局只会更加糟糕。开发效率低下,性能低下,天天忙着补漏救火。而我这个新丁纯粹出于个人的技术追求,无意中起到了不少正面作用,才脱颖而出,于2年多后升到公司的中层之一——技术经理。
转型过程比较缓慢。 首先用jsp重写的产品就是地税申报网站。05年3月份我进入地税组时,这个工作已经由地税组经理老唐完成。如前所述,我用了大概一个月学会了jsp开发——完全用php方式写的jsp,唯一的开发工具是UltraEdit,服务器是Weblogic,数据库用Sybase+PowerBuilder。这时候我完全是学习阶段,学sql学html学js学css学业务规则学xxx,什么都要学,没有文档没有培训,自己看着工程代码琢磨,实在搞不定就去请教老唐——被戏称第一调试高手的老唐对用out.print抓到bug实在是很有心得,令我获益匪浅。
1.连接池泄漏show一下我们那时候的精彩代码,仔细看看,你能从中发现多少问题?
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312"> <title>用户信息确认</title> </head> <body bgcolor="#F6F6F6" onLoad="fix()" onScroll="fix()" onResize="fix()"> <%@ include file="wsqz.jsp" %> <% DBConnect conn=new DBConnect(); String sql = "select xxx from ddd where id = ?"; conn.setPstmt(sql); conn.setString(1,sessUserID); ResultSet result=conn.executeQuery(); //$result = sybase_query($sql); //$row = sybase_fetch_row($result); %> 请确认您的用户信息: <table width="100%" align="center" border="0" cellpadding="0" cellspacing="0"> <tr> <td height="20"></td> </tr> </table> <table width="100%" align="center" border="0" cellpadding="0" cellspacing="0"> <tr valign="middle"> <td >纳税人税号:</td> <td><%=result.getString(1)%> </td> </tr> <tr> <td> 微机代码:</td> <td><%=result.getString(2)%></td> </tr> <tr> <td>纳税人名称:</td> <td><%=result.getString(3)%></td> </tr> </table> <table width="100%" align="center" border="0" cellpadding="0" cellspacing="0"> <tr> <td height="20"></td></td> </tr> </table> 请确认您。。。<br> 联系电话:xxx <% result.close(); conn.close(); %> </body> </html> 这批jdbc代码后来直接导致weblogic在高峰期频频崩溃假死,老唐天天盯着weblogic的监控手动重启。客户投诉暴涨,不管服务部还是开发部都承受着巨大的压力,请bea的工程师远程会诊也没查出所以然来,还是老唐放狗搜索发现这会导致连接池泄漏。我接到任务开始改写所有的jdbc代码,给他们加上try..catch..finally..close ,大概几千处,足够我加班干个几天几夜的。不行,我决定发挥程序员的懒惰,写个程序自动修改。 怎么写呢?页面很杂乱,嵌套多得要死,代码风格也多,没有时间写一个面面俱到的独立程序来兼容所有可能性,我决定以一种所见即所得的修改方式来最快完成任务——用jEdit写一个macro 。 那段时间我正好研究了几个月jEdit和beanshell,打开jEdit的API边查边写:
/* */ // beginning of Run_Make_New_JSP.bsh public ArrayList getConnList(){ ArrayList list = new ArrayList(); int index = 0; String text = textArea.getText(); while((index = text.indexOf("= new DBConnect();",index))>0){ //reference name String text = textArea.getLineText(textArea.getLineOfOffset(index)); StringTokenizer tok = new StringTokenizer(text,"= tnr"); if(tok.nextToken().equals("DBConnect"))//reference name list.add(tok.nextToken()); index = index+20; } return list; } public String[] getRsArray(String connName){ int index = 0; String[] a = null; ArrayList al = new ArrayList(); //find rs line String rstmp = "= " + connName + ".executeQuery"; while((index = textArea.getText().indexOf(rstmp,index)) > 0) { lineOfRs = textArea.getLineOfOffset(index); //token String rsLineText = textArea.getLineText(lineOfRs); tok = new StringTokenizer(rsLineText,"= trn"); tok.nextToken(); rsName = tok.nextToken(); al.add(rsName); index+=rstmp.length(); } if(al.size()==0) return null; else { a = new String[al.size()]; Iterator it = al.iterator(); for(int i=0;i<al.size();i++) { a[i] = (String)(it.next()); } } return a; } public int[] getLineOf(String word) { int index = 0; ArrayList al = new ArrayList(); String text = textArea.getText(); while((index = text.indexOf(word,index))>0){ al.add(textArea.getLineOfOffset(index)); index = index+word.length(); } int[] a = new int[al.size()]; Iterator it = al.iterator(); for(int i=0;i<al.size();i++) { a[i] = (int)(it.next()); } return a; } //按照被替换行的缩进进行替换,每一行的缩进与前一行相同,但最后一行有点小问题 public void replaceLines(int line,String t){ int offset = textArea.getLineStartOffset(line); String text = textArea.getLineText(line); i=0; String pre = ""; while(text.charAt(i)=='t'||text.charAt(i)==' ') { if(text.charAt(i)=='t') pre+="t"; if(text.charAt(i)==' ') pre+=" "; i++; } textArea.setCaretPosition(offset); textArea.deleteLine(); buffer.insertIndented(offset,pre+t); } // main routine public void makeOne(String connName) { //Macros.message(view,""+map.size()); int lineOfConn = 0, lineOfRs = 0,lineOfRsClose = 0,lineOfConnClose = 0; int lineOfConn = getLineOf(connName)[0]; das = getRsArray(connName); if(das!=null) { String rsName = getRsArray(connName)[0]; //DBConnect conn = ... String j = "DBConnect "+connName+" = null;rnResultSet "+rsName+ " = null;rntry{rn"+connName+" = new DBConnect();rn"; replaceLines(lineOfConn,j); //ResultSet rs = ... int rsn = getLineOf("ResultSet "+rsName+" = "+connName)[0]; rsnn = textArea.getLineText(rsn); suffix = rsnn.substring(rsnn.indexOf(rsName)); replaceLines(rsn,suffix+"rn"); //delete rs.close() //textArea.setCaretPosition(textArea.getLineStartOffset(getLineOf(rsName+".close()")[0])); //textArea.deleteLine(); replaceLines(getLineOf(rsName+".close()")[0],""); //conn.close(); String d = "}rn"+ "catch(Exception e)rn"+ "{rn"+ " e.printStackTrace();rn"+ "}rn"+ "finallyrn"+ "{rn"+ " tryrn"+ " {rn"+ " if("+rsName+"!=null)rn"+ " "+rsName+".close();rn"+ " if("+connName+"!=null)rn"+ " "+connName+".close();rn"+ " }rn"+ " catch(Exception e)rn"+ " {rn"+ " e.printStackTrace();rn"+ " }rn"+ "}rn"; replaceLines(getLineOf(connName+".close()")[0],d); //Macros.message(view,connName+getLineOf(connName+".close()")[0]); }else{ //DBConnect conn = ... String j = "DBConnect "+connName+" = null;rntry{rn"; replaceLines(lineOfConn,j); //conn.close(); String d = "}rn"+ "catch(Exception e)rn"+ "{rn"+ " e.printStackTrace();rn"+ "}rn"+ "finallyrn"+ "{rn"+ " tryrn"+ " {rn"+ " if("+connName+"!=null)rn"+ " "+connName+".close();rn"+ " }rn"+ " catch(Exception e)rn"+ " {rn"+ " e.printStackTrace();rn"+ " }rn"+ "}rn"; replaceLines(getLineOf(connName+".close()")[0],d); } } // this single line of code is the script's main routine // it calls the methods and exits if(buffer.isReadOnly()) Macros.error(view, "Buffer is read-only."); else{ ArrayList list = getConnList(); it = list.iterator(); while(it.hasNext()) { makeOne((String)(it.next())); //sa+=" "+(String)(it.next()); } it = list.iterator(); sa = ""; while(it.hasNext()) { //makeOne((String)(it.next())); sa+=" "+(String)(it.next()); } Macros.message(view,sa); } /* Macro index data (in DocBook format) <listitem> <para><filename>run_Make_New_JSP.bsh</filename></para> <abstract> <para> Adds user-supplied <quote>prefix</quote> and <quote>suffix</quote> text to each line in a group of selected lines. </para> </abstract> <para>s Text is added after leading whitespace and before trailing whitespace. A dialog window receives input and <quote>remembers</quote> past entries. </para> </listitem> */ // end Add_Prefix_and_Suffix.bsh 这是我首次为开发写辅助工具,马上就尝到了甜头。只要用jEdit打开jsp文件按一下快捷键,rs、conn等就自动改成了关闭形式,我可以立刻检查改动是否正确。我感到很自豪,避免了几万次枯燥无味的copy/paste,嘿嘿,这才是程序员的做事风格!虽然写macro用了一天时间,但仍然比手工修改要合算得多,不但省力,更避免了引发新的错误——以我的经验,机械麻木的copy/paste过程必然引发忘改变量名之类的低级问题。 后来我写了一些jEdit的应用经验在blogjava 上(留言里有pi1ot ,他是个jEdit铁杆,甚至为jEdit修改了一套字体,前段时间还在javaeye发了个jedit4.3的新闻 ),本来还想写高级篇,但是随后杯具——某天我没有关机导致compaq笔记本硬盘在颠簸中报废了——大量代码永远安息,也包括我为jEdit写的十几个bsh。我很受伤,兴致缺缺,这个计划就搁到脑后了。
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2010-02-02
继续写 加油
|
|
返回顶楼 | |
浏览 2100 次