- 浏览: 319032 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
libaogui777:
前辈,您好, 使用PDFbox 提取内容遇到一个问题,想请教您 ...
java进行pdf解析-----pdfbox -
xin_hany:
提示惊醒了一下,解决了一个让人惆怅的问题,
danga的MemcachedClient的几个缺陷 -
roroyangivan:
牛B啊。。。我觉得 这种 回答。。。阿里的的CTO 都 HOL ...
怎样才是一个好的架构? -
406657836:
今天知道了一个线程创建时会给stack分配1M内存?一个线程默 ...
jvm线程的stack -
linzx0212:
受教了……
danga的MemcachedClient的几个缺陷
年纪大了就喜欢回忆从前?
不。
人生又走到了未知的分岔路口,停下脚步回眸过去的路,正是为坚定向前跋涉的心。
过去通宵达旦努力研究的技术在现在回头看看都初级了点,但一个人处理问题的方式和态度不会过时。我心血来潮,花了不少时间来翻看工作日记和旧项目,力图总结一下工作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。我很受伤,兴致缺缺,这个计划就搁到脑后了。
发表评论
-
Ruby API代码技巧
2012-05-23 21:53 1095http://www.slideshare.net/ihowe ... -
怎样才是一个好的架构?
2012-05-18 17:37 3681关于软件设计的抽象思想 曾经被阿里的某CTO问过一个问题 ... -
nginx的编译选项
2012-04-25 17:30 1510下载nginx源码包,编译命令之一: ./co ... -
10 Core Architecture Pattern Variations for Achieving Scalability
2011-11-20 22:00 1034【转载】:http://highscalability.com ... -
wowza doc of multi-bitrate streaming
2011-11-06 11:49 2347http://www.wowza.com/forums/con ... -
今天回首
2011-09-01 22:13 1257突然发觉很久不上javaeye了,仿佛生活中遗忘了这一块。 每 ... -
你的邮件”被垃圾“了吗?
2010-11-30 20:37 1112最近在注册系统中使用邮件激活,用公司的邮箱服务器发送帐号激活邮 ... -
mongodb的map/reduce实属鸡肋
2010-11-24 22:47 1500曾经被mongodb的特性所吸引,没想到map/reduce却 ... -
[老博迁移2005-11-09]TeracMiracle反编译成功
2010-08-12 22:13 871TeracMiracle反编译成功 TM:中国人写 ... -
[老博迁移2005-11-09] 越是官大,越是懒
2010-08-12 22:11 1123越是官大,越是懒 小小的公司里就有官僚了,真 ... -
danga的MemcachedClient的几个缺陷
2010-08-11 16:19 17388最近实际用起来我发现,java版danga的memcached ... -
今天参加RubyConfChina的活动,见识了
2010-06-27 00:27 1191这次是RubyConfChina的 ... -
该死的CXF
2010-04-15 21:20 1158为了连https web services,初步选择以前用得还 ... -
jsp太大编译不了,原来是64k的方法限制
2010-02-11 12:04 2775昨天遇到一个诡异的问题,吓出一身冷汗。 20几个300k ... -
javascript技巧:(function(){})()
2010-02-11 12:03 1182javascript技巧:(function(){})() ... -
lucene搜索引擎简单应用
2010-02-11 12:02 1214还用lucene架了个搜索引擎,对pdf进行全文搜索(联合 ... -
java进行pdf解析-----pdfbox
2010-02-11 11:58 10459对pdf解析有不少成熟技术,经过选型,我最后选定用pdfb ... -
用flash动态上传文件
2010-02-11 11:52 1164用flash写了一个动态的文件上传功能,当然也用了jque ... -
不当家不知道柴米贵,不开发不知道重启费
2010-02-11 11:21 1139话说我开始逐渐脱离群众,开发得越来越少。还好最近做了 ... -
【转】Getting real
2010-02-11 11:18 897【转】Getting real 刚才偶然看到的, ...
相关推荐
java程序员职业生涯规划,提供毕业的及结业不久的友友们,希望可以给到参考!
看这本书你的职业生涯将受益终生,...一个奋斗多年的Java程序员给刚毕业的java程序员的建议 帮助刚毕业的Java程序员做好自己的职业规划! 希望更多的人实现自己的理想 中国的软件行业蒸蒸日上需要更多的有激情的人们
java+springboot it职业生涯规划系统 毕业论文.doc
本文简介了一套基于JAVA+access开发的综合测评系统的毕业设计,包括源代码、论文、开题报告和任务书。该系统针对某高校的毕业生进行综合测评,评估学生在所学专业方面的知识水平和实践能力。 系统采用JAVA语言开发,...
作为程序员,职业生涯的第一步,当然是掌握并精通至少一门编程语言。 本人是一名 Java 后端程序员,刚毕业时做过两年 C/C++ 程序员,此外,还略懂几门其他编程语言。 1.1. Java Java 领域的知识点非常庞杂,我整理成...
java招聘公司笔技巧题编程库:软件开发资源 关于此 Repo :此库是信息源和类似资源的精选集合,由教育者、专家、学习者选择,并可供程序员社区访问以供参考。 其中包括用于编程、 Web 开发、计算机科学等的资源。 ...
家成功的创业公司,从成立到销售,我的名字在几项软件专利和专利申请中,我的简历看起来很不错。 但是,我不是一个很好的程序员。 事实上,我在大学一年级获得的最低成绩是计算机编程入门课程。 谢天谢地,我已经...
我是上海威迅教育的学生,今年五月即将毕业,开始我的程序员生涯,现在我拿出部门我在威迅教育学习资料和朋友们共同分享,共同学习,共同进步,愿我们可以成为朋友。更多内容欢迎访问csdn上海威迅教育社区群和我的...
掌握Android从应用开发,到系统移植,再到设备驱动开发的全套技术,无疑会极大的提升自己的职业竞争力和薪酬谢水平 ,本课程深入浅出,手敲全部实战项目代码,经历软硬件结合的嵌入式项目开发全部过程,而且课程中不...
掌握Android从应用开发,到系统移植,再到设备驱动开发的全套技术,无疑会极大的提升自己的职业竞争力和薪酬谢水平 ,本课程深入浅出,手敲全部实战项目代码,经历软硬件结合的嵌入式项目开发全部过程,而且课程中不...
取消装箱是从 object 类型到值类型或从接口类型到实现该接口的值类型的显式转换。取消装箱操作包括:检查对象实例,确保它是给定值类型的一个装箱值。将该值从实例复制到值类型变量中。 例: int i = 123; // A ...
掌握Android从应用开发,到系统移植,再到设备驱动开发的全套技术,无疑会极大的提升自己的职业竞争力和薪酬谢水平 ,本课程深入浅出,手敲全部实战项目代码,经历软硬件结合的嵌入式项目开发全部过程,而且课程中不...