- 浏览: 326159 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
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 1133http://www.slideshare.net/ihowe ... -
怎样才是一个好的架构?
2012-05-18 17:37 3777关于软件设计的抽象思想 曾经被阿里的某CTO问过一个问题 ... -
nginx的编译选项
2012-04-25 17:30 1584下载nginx源码包,编译命令之一: ./co ... -
10 Core Architecture Pattern Variations for Achieving Scalability
2011-11-20 22:00 1099【转载】:http://highscalability.com ... -
wowza doc of multi-bitrate streaming
2011-11-06 11:49 2403http://www.wowza.com/forums/con ... -
今天回首
2011-09-01 22:13 1306突然发觉很久不上javaeye了,仿佛生活中遗忘了这一块。 每 ... -
你的邮件”被垃圾“了吗?
2010-11-30 20:37 1143最近在注册系统中使用邮件激活,用公司的邮箱服务器发送帐号激活邮 ... -
mongodb的map/reduce实属鸡肋
2010-11-24 22:47 1543曾经被mongodb的特性所吸引,没想到map/reduce却 ... -
[老博迁移2005-11-09]TeracMiracle反编译成功
2010-08-12 22:13 903TeracMiracle反编译成功 TM:中国人写 ... -
[老博迁移2005-11-09] 越是官大,越是懒
2010-08-12 22:11 1183越是官大,越是懒 小小的公司里就有官僚了,真 ... -
danga的MemcachedClient的几个缺陷
2010-08-11 16:19 17435最近实际用起来我发现,java版danga的memcached ... -
今天参加RubyConfChina的活动,见识了
2010-06-27 00:27 1231这次是RubyConfChina的 ... -
该死的CXF
2010-04-15 21:20 1189为了连https web services,初步选择以前用得还 ... -
jsp太大编译不了,原来是64k的方法限制
2010-02-11 12:04 2856昨天遇到一个诡异的问题,吓出一身冷汗。 20几个300k ... -
javascript技巧:(function(){})()
2010-02-11 12:03 1213javascript技巧:(function(){})() ... -
lucene搜索引擎简单应用
2010-02-11 12:02 1264还用lucene架了个搜索引擎,对pdf进行全文搜索(联合 ... -
java进行pdf解析-----pdfbox
2010-02-11 11:58 10576对pdf解析有不少成熟技术,经过选型,我最后选定用pdfb ... -
用flash动态上传文件
2010-02-11 11:52 1197用flash写了一个动态的文件上传功能,当然也用了jque ... -
不当家不知道柴米贵,不开发不知道重启费
2010-02-11 11:21 1171话说我开始逐渐脱离群众,开发得越来越少。还好最近做了 ... -
【转】Getting real
2010-02-11 11:18 925【转】Getting real 刚才偶然看到的, ...
相关推荐
本书旨在帮助读者更好地理解Java程序员这一职业的发展路径,从求职到职场生存再到职业发展,全方位地为读者提供宝贵的建议和指导。接下来,我们将深入探讨书中提出的关键知识点。 #### 二、求职与工作中的...
java 程序员职业生涯规划 在软件行业中,程序员的职业生涯规划是非常重要的。很多程序员在毕业时充满活力和激情,但是在几年的摸爬滚打后,冲劲就会慢慢减弱甚至消失。这是因为在 IT 行业中,技术和.mode 是不断...
"java 程序员职业生涯规划" java 程序员职业生涯规划是许多程序员职业生涯的关键。刚毕业时充满活力,然而几年的摸爬滚打后,冲劲就会慢慢减弱甚至消失。这并不奇怪,工作的新鲜感褪程序员首先需要提高系统设计...
### Java程序员简历模板知识点解析 #### 一、简历模板的重要性及作用 - **提供统一格式**:简历模板有助于标准化简历的格式,使求职者的简历在视觉上显得更加专业和一致,便于招聘人员快速获取关键信息。 - **突出...
本书《Java程序员面试宝典》由杨磊等编著,由清华大学出版社出版,是Java程序员在求职面试前不可或缺的准备材料。它集结了200个Java技术面试的真题,并对这些题目进行了详细解析,旨在帮助应聘者掌握企业招聘Java...
看这本书你的职业生涯将受益终生,...一个奋斗多年的Java程序员给刚毕业的java程序员的建议 帮助刚毕业的Java程序员做好自己的职业规划! 希望更多的人实现自己的理想 中国的软件行业蒸蒸日上需要更多的有激情的人们
本文将详细介绍Java程序员如何制定有效的职业规划,并探讨其在职业生涯中的重要作用。 #### 二、明确职业规划目标 对于即将毕业的学生而言,明确自己的职业目标至关重要。很多学生往往对自己的目标职位较为模糊,...
作为技术人员,Java程序员意识到持续学习和自我提升的重要性,以及在项目中展现出的团队协作和执行能力。 在工作中,程序员主要完成了以下几个方面的工作: 1. 学习并应用ASP语言,为后续的项目打下了基础。 2. ...
Java程序员面试宝典第二版的第一章主要探讨了程序员在求职过程中的关键环节和注意事项,旨在帮助求职者,尤其是应届毕业生和寻求职业发展的程序员,更好地理解并应对求职市场。以下是本章涉及的重要知识点: 1. **...
【Java程序员面试宝典】是为Java程序员量身定制的一份求职指南,旨在帮助程序员在求职过程中更好地准备和规划自己的职业生涯。以下是对标题和描述中所述知识点的详细说明: 1. **职业规划**:首先,程序员应理解...