paulwong

#

JUnitBenchmark Junit性能测试

如果你希望用 JUnit 来测试一些性能问题,那么 JUnitBenchmark 可以帮到你,主要特性:

  • 记录执行时间
  • 监控垃圾收集
  • 测试热身

package com.paul;

import com.carrotsearch.junitbenchmarks.AbstractBenchmark;
import com.carrotsearch.junitbenchmarks.BenchmarkOptions;
import javolution.text.TextBuilder;
import org.junit.Test;
 
/**
 * Benchmark for String concatenation. Compares StringBUilder (JDK) and
 * TextBuilder (Javolution).
 
*/
public class StringConcatenationBenchmark extends AbstractBenchmark {
 
    public static final long LOOPS_COUNT = 10000000;
 
    @Test
    @BenchmarkOptions(benchmarkRounds = 3, warmupRounds = 1)
    public void stringBuilderBenchmark()  {
         
        StringBuilder builder = new StringBuilder();
        for (long i = 0; i < LOOPS_COUNT; i++) {
            builder.append('i').append(i);
        }
        System.out.println(builder.toString().length());
    }
     
    @Test
    @BenchmarkOptions(benchmarkRounds = 3, warmupRounds = 1)
    public void textBuilderBenchmark()  {
         
        TextBuilder builder = new TextBuilder();
        for (long i = 0; i < LOOPS_COUNT; i++) {
            builder.append('i').append(i);
        }
        System.out.println(builder.toString().length());
    }
}


Maven依赖:
<dependency>
        <groupId>javolution</groupId>
        <artifactId>javolution</artifactId>
        <version>5.4.5</version>
</dependency>


结果显示:
78888890
78888890
78888890
78888890
StringConcatenationBenchmark.stringBuilderBenchmark: [measured 3 out of 4 rounds, threads: 1 (sequential)]
 round: 0.57 [+- 0.01], round.gc: 0.00 [+- 0.00], GC.calls: 33, GC.time: 0.02, time.total: 2.60, time.warmup: 0.90, time.bench: 1.70
78888890
78888890
78888890
78888890
StringConcatenationBenchmark.textBuilderBenchmark: [measured 3 out of 4 rounds, threads: 1 (sequential)]
 round: 0.46 [+- 0.03], round.gc: 0.00 [+- 0.00], GC.calls: 14, GC.time: 0.14, time.total: 1.92, time.warmup: 0.55, time.bench: 1.38

posted @ 2013-03-01 10:37 paulwong 阅读(787) | 评论 (0)编辑 收藏

EJB3资源

eclipse + JBoss 5 + EJB3开发指南(1):编写第一个无状态的SessionBean


eclipse + JBoss 5 + EJB3开发指南(2):编写有状态的SessionBean


eclipse + JBoss 5 + EJB3开发指南(3):使用Session Bean的本地接口


eclipse + JBoss 5 + EJB3开发指南(4):Session Bean中的注释方法


eclipse + JBoss 5 + EJB3开发指南(5):使用配置文件发布Session Bean


eclipse + JBoss 5 + EJB3开发指南(6):编写第一个实体Bean程序


eclipse + JBoss 5 + EJB3开发指南(7):实现Entity Bean的一对一(one-to-one)映射


eclipse + JBoss 5 + EJB3开发指南(8):实现Entity Bean的一对多(one-to-many)映射


eclipse + JBoss 5 + EJB3开发指南(9):实现Entity Bean的多对多(many-to-many)映射


eclipse + JBoss 5 + EJB3开发指南(10):通过继承实体Bean,将单个表映射成多个表(单表策略,SINGLE_TABLE)


eclipse + JBoss 5 + EJB3开发指南(11):实体Bean的连接策略(JOINED Strategy)


eclipse + JBoss 5 + EJB3开发指南(12):使用命名查询执行JPQL


eclipse + JBoss 5 + EJB3开发指南(13):在Servlet中访问应用程序管制EntityManager对象


eclipse + JBoss 5 + EJB3开发指南(14):消息驱动Bean


eclipse + JBoss 5 + EJB3开发指南(15):拦截器方法和拦截器类


a
JAVAEE6+MAVEN+GLASSFISH
http://www.hascode.com/2011/09/java-ee-6-development-using-the-maven-embedded-glassfish-plugin/



JAVAEE7+MAVEN+GLASSFISH+JBOSS+TOMEE
https://github.com/javaee-samples/javaee7-samples

OPEN EJB客户端
http://openejb.apache.org/hello-world.html
http://tomee.apache.org/clients.html

OPEN EJB互相引用
http://tomee.apache.org/ejb-refs.html

http://tomee.apache.org/tomee-and-eclipse.html

Deploying in TomEE
http://tomee.apache.org/deploying-in-tomee.html

http://www.javacodegeeks.com/2014/05/stateless-ejbs-pooling-and-lifecycle.html

http://www.javacodegeeks.com/2011/11/jboss-as-7-ejb3-pools-configuration.html

http://www.javacodegeeks.com/2014/07/java-ee-7-with-angular-js-part-1.html

SPRING+EJB3+JBOSS
https://github.com/bpark/spring-ejb3-webapp
https://access.redhat.com/documentation/en-US/JBoss_Web_Framework_Kit/1.2/html/Spring_Developer_Guide/ch07s05s02.html


!!JBOSS系列 -EJB远程调用-客户端的配置
http://www.cnblogs.com/liutengteng130/p/4270832.html

JBOSS中远程调用EJB
https://docs.jboss.org/author/display/AS71/EJB+invocations+from+a+remote+server+instance


JBOSS 8的DEMO
https://github.com/wildfly/quickstart

EJB VS Spring/Hessian
http://java.dzone.com/articles/remote-access-your-services


posted @ 2013-02-26 10:46 paulwong 阅读(294) | 评论 (0)编辑 收藏

简单的用 Java Socket 编写的 HTTP 服务器应用,帮助学习HTTP协议

所谓HTTP协议,就是TCP协议+状态信息之类的字符。

资源:http://www.blogjava.net/nokiaguy/category/38517.html

/**
 * SimpleHttpServer.java
 
*/

import java.io.*;
import java.net.*;
import java.util.StringTokenizer;

/**
 * 一个简单的用 Java Socket 编写的 HTTP 服务器应用, 演示了请求和应答的协议通信内容以及
 * 给客户端返回 HTML 文本和二进制数据文件(一个图片), 同时展示了 404, 200 等状态码.
 * 首先运行这个程序,然后打开Web浏览器,键入http://localhost,则这个程序能够显示出浏览器发送了那些信息
 * 并且向浏览器返回一个网页和一副图片, 并测试同浏览器对话.
 * 当浏览器看到 HTML 中带有图片地址时, 则会发出第二次连接来请求图片等资源.
 * 这个例子可以帮您理解 Java 的 HTTP 服务器软件是基于 J2SE 的 Socket 等软件编写的概念, 并熟悉
 * HTTP 协议.
 * 相反的用 Telnet 连接到已有的服务器则可以帮忙理解浏览器的运行过程和服务器端的返回内容.
 *
 * <pre>
 *       当用户在Web浏览器地址栏中输入一个带有http://前缀的URL并按下Enter后,或者在Web页面中某个以http://开头的超链接上单击鼠标,HTTP事务处理的第一个阶段--建立连接阶段就开始了.HTTP的默认端口是80.
 *    随着连接的建立,HTTP就进入了客户向服务器发送请求的阶段.客户向服务器发送的请求是一个有特定格式的ASCII消息,其语法规则为:
 * < Method > < URL > < HTTP Version > <\n>
 * { <Header>:<Value> <\n>}*
 * <\n>
 * { Entity Body }
 *    请求消息的顶端是请求行,用于指定方法,URL和HTTP协议的版本,请求行的最后是回车换行.方法有GET,POST,HEAD,PUT,DELETE等.
 * 在请求行之后是若干个报头(Header)行.每个报头行都是由一个报头和一个取值构成的二元对,报头和取值之间以":"分隔;报头行的最后是回车换行.常见的报头有Accept(指定MIME媒体类型),Accept_Charset(响应消息的编码方式),Accept_Encoding(响应消息的字符集),User_Agent(用户的浏览器信息)等.
 *    在请求消息的报头行之后是一个回车换行,表明请求消息的报头部分结束.在这个\n之后是请求消息的消息实体(Entity Body).具体的例子参看httpRequest.txt.
 *     Web服务器在收到客户请求并作出处理之后,要向客户发送应答消息.与请求消息一样,应答消息的语法规则为:
 * < HTTP Version> <Status Code> [<Message>]<\n>
 * { <Header>:<Value> <\n> } *
 * <\n>
 * { Entity Body }
 *    应答消息的第一行为状态行,其中包括了HTTP版本号,状态码和对状态码进行简短解释的消息;状态行的最后是回车换行.状态码由3位数字组成,有5类: 
 * 参看:HTTP应答码及其意义 
 * 
 * 1XX 保留 
 * 2XX 表示成功 
 * 3XX 表示URL已经被移走 
 * 4XX 表示客户错误 
 * 5XX 表示服务器错误 
 * 例如:415,表示不支持改媒体类型;503,表示服务器不能访问.最常见的是200,表示成功.常见的报头有:Last_Modified(最后修改时间),Content_Type(消息内容的MIME类型),Content_Length(内容长度)等.
 *    在报头行之后也是一个回车换行,用以表示应答消息的报头部分的结束,以及应答消息实体的开始.
 *    下面是一个应答消息的例子:
 * HTTP/1.0 200 OK
 * Date: Moday,07-Apr-97 21:13:02 GMT
 * Server:NCSA/1.1
 * MIME_Version:1.0
 * Content_Type:text/html
 * Last_Modified:Thu Dec 5 09:28:01 1996
 * Coentent_Length:3107
 * 
 * <HTML><HEAD><TITLE></HTML>
 * 
 * 在用Java语言实现HTTP服务器时,首先启动一个java.net.ServerSocket在提供服务的端口上监听连接.向客户返回文本时,可以用PrintWriter,但是如果返回二进制数据,则必须使用OutputStream.write(byte[])方法,返回的应答消息字符串可以使用String.getBytes()方法转换为字节数组返回,或者使用PrintStream的print()方法写入文本,用write(byte[])方法写入二进制数据.
 * 
 * </pre>
 * 
@author 刘长炯
 * 
@version 1.0 2007-07-24 Sunday
 
*/
public class SimpleHttpServer implements Runnable {
    /**
     * 
     
*/
    ServerSocket serverSocket;//服务器Socket
    
    /**
     * 服务器监听端口, 默认为 80.
     
*/
    public static int PORT=80;//标准HTTP端口
    
    /**
     * 开始服务器 Socket 线程.
     
*/
    public SimpleHttpServer() {
        try {
            serverSocket=new ServerSocket(PORT);
        } catch(Exception e) {
            System.out.println("无法启动HTTP服务器:"+e.getLocalizedMessage());
        }
        if(serverSocket==null)  System.exit(1);//无法开始服务器
        new Thread(this).start();
        System.out.println("HTTP服务器正在运行,端口:"+PORT);
    }
    
    /**
     * 运行服务器主线程, 监听客户端请求并返回响应.
     
*/
    public void run() {
        while(true) {
            try {
                Socket client=null;//客户Socket
                client=serverSocket.accept();//客户机(这里是 IE 等浏览器)已经连接到当前服务器
                if(client!=null) {
                    System.out.println("连接到服务器的用户:"+client);
                    try {
                        // 第一阶段: 打开输入流
                        BufferedReader in=new BufferedReader(new InputStreamReader(
                                client.getInputStream()));
                        
                        System.out.println("客户端发送的请求信息:\n***************");
                        // 读取第一行, 请求地址
                        String line=in.readLine();
                        System.out.println(line);
                        String resource=line.substring(line.indexOf('/'),line.lastIndexOf('/')-5);
                        //获得请求的资源的地址
                        resource=URLDecoder.decode(resource, "UTF-8");//反编码 URL 地址
                        String method = new StringTokenizer(line).nextElement().toString();// 获取请求方法, GET 或者 POST

                        
// 读取所有浏览器发送过来的请求参数头部信息
                        while( (line = in.readLine()) != null) {
                            System.out.println(line);
                            
                            if(line.equals("")) break;
                        }
                        
                        // 显示 POST 表单提交的内容, 这个内容位于请求的主体部分
                        if("POST".equalsIgnoreCase(method)) {
                            System.out.println(in.readLine());
                        }
                        
                        System.out.println("请求信息结束\n***************");
                        System.out.println("用户请求的资源是:"+resource);
                        System.out.println("请求的类型是: " + method);

                        // GIF 图片就读取一个真实的图片数据并返回给客户端
                        if(resource.endsWith(".gif")) {
                            fileService("images/test.gif", client);
                            closeSocket(client);
                            continue;
                        }
                        
                        // 请求 JPG 格式就报错 404
                        if(resource.endsWith(".jpg")) {
                                                    PrintWriter out=new PrintWriter(client.getOutputStream(),true);
                        out.println("HTTP/1.0 404 Not found");//返回应答消息,并结束应答
                        out.println();// 根据 HTTP 协议, 空行将结束头信息
                        out.close();
                        closeSocket(client);
                        continue;
                        } else {
                            // 用 writer 对客户端 socket 输出一段 HTML 代码
                            PrintWriter out=new PrintWriter(client.getOutputStream(),true);
                            out.println("HTTP/1.0 200 OK");//返回应答消息,并结束应答
                            out.println("Content-Type:text/html;charset=GBK");
                            out.println();// 根据 HTTP 协议, 空行将结束头信息

                            out.println("<h1> Hello Http Server</h1>");
                            out.println("你好, 这是一个 Java HTTP 服务器 demo 应用.<br>");
                            out.println("您请求的路径是: " + resource + "<br>");
                            out.println("这是一个支持虚拟路径的图片:<img src='abc.gif'><br>" +
                                    "<a href='abc.gif'>点击打开abc.gif, 是个服务器虚拟路径的图片文件.</a>");
                            out.println("<br>这是个会反馈 404 错误的的图片:<img src='test.jpg'><br><a href='test.jpg'>点击打开test.jpg</a><br>");
                            out.println("<form method=post action='/'>POST 表单 <input name=username value='用户'> <input name=submit type=submit value=submit></form>");
                            out.close();

                            closeSocket(client);
                        }
                    } catch(Exception e) {
                        System.out.println("HTTP服务器错误:"+e.getLocalizedMessage());
                    }
                }
                //System.out.println(client+"连接到HTTP服务器");//如果加入这一句,服务器响应速度会很慢
            } catch(Exception e) {
                System.out.println("HTTP服务器错误:"+e.getLocalizedMessage());
            }
        }
    }
    
    /**
     * 关闭客户端 socket 并打印一条调试信息.
     * 
@param socket 客户端 socket.
     
*/
    void closeSocket(Socket socket) {
        try {
            socket.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
                            System.out.println(socket + "离开了HTTP服务器");        
    }
    
    /**
     * 读取一个文件的内容并返回给浏览器端.
     * 
@param fileName 文件名
     * 
@param socket 客户端 socket.
     
*/
        void fileService(String fileName, Socket socket)
    {
            
        try
        {
            PrintStream out = new PrintStream(socket.getOutputStream(), true);
            File fileToSend = new File(fileName);
            if(fileToSend.exists() && !fileToSend.isDirectory())
            {
                out.println("HTTP/1.0 200 OK");//返回应答消息,并结束应答
                out.println("Content-Type:application/binary");
                out.println("Content-Length:" + fileToSend.length());// 返回内容字节数
                out.println();// 根据 HTTP 协议, 空行将结束头信息
                
                FileInputStream fis = new FileInputStream(fileToSend);
                byte data[] = new byte[fis.available()];
                fis.read(data);
                out.write(data);
                out.close();
                fis.close();
            }
        }
        catch(Exception e)
        {
            System.out.println("传送文件时出错:" + e.getLocalizedMessage());
        }
    }
    
    /**
     * 打印用途说明.
     
*/
    private static void usage() {
        System.out.println("Usage: java HTTPServer <port>\nDefault port is 80.");
    }
    
    
    /**
     * 启动简易 HTTP 服务器
     * 
@param args 
     
*/
    public static void main(String[] args) {
        try {
            if(args.length != 1) {
                usage();
            } else if(args.length == 1) {
                PORT = Integer.parseInt(args[0]);
            }
        } catch (Exception ex) {
            System.err.println("Invalid port arguments. It must be a integer that greater than 0");
        }
        
        new SimpleHttpServer();
    }
    

posted @ 2013-02-25 22:29 paulwong 阅读(332) | 评论 (0)编辑 收藏

职场上做人做事做管理

作者:何云隆
网易上斩建通写的很好的文章分享下


大道至简,越是根源和基本的问题,道理实际上越简单。关于如何做人、做事、做管理的书很多,我看得不多,但是我觉得这些书更多是侧重技术和实现细节上的,而很少从人的思想和观念去讲。实际上,从根本上去说,如何做人做事是世界观的问题,也是一个哲学话题。很多人和我一样,已经到了快30的年纪,是需要去思考一下应该如何做人如何做事的,也需要一套简单、有效、完整的体系来指导自己,而这套体系将是让自己安身立命于这个世界的基石。


职场上如何做人

关于在职场上如何做人,我只谨记两个字--服务。你要把自己当成一个品牌去爱惜,当成一家公司去经营,你要牢牢记住你之所以能在一家公司立足,靳建通是因为公司需要你的服务。我们经常会抱怨某某银行的工作人员服务态度不好、某某商品的售后服务不好,但从来不去思考自己对公司的服务好不好?公司的任务有没有如期完成,是不是没有哪个任务是提前完成的,几乎所有任务都拖到“最后期限”?工作完成的够不够彻底,是不是答复已经完成了,结果日后又出状况?完成后有没有向上级反馈,是不是等到上级问你完成了没有,你才去报告进度?拖延的任务有没有持续跟进,是不是上级不追了这个任务最后就不了了之了?上面这些问题我都是反复遇见的,其实根本原因就是没有意识到你其实在做一项服务,你在公司的发展前景,全都取决你对公司的服务够不够好。设想一下,如果交给你的每件事情都可以迎刃而解、化险为夷,让人感觉稳妥、放心、踏实,你自然会收到更多更重要的“订单”。当你的单多到你忙不过来的时候怎么办?招下属啊,呵呵,恭喜你,你已经是领导了。反之,如果给你一件事情你要拖延,给你一件事情你办不好,给你一件事情就没了下文了,让人不放心,久而久之你就“无单可做”了,那么公司重新请一个人就可以了,干嘛非要用你呢?


服务不光是对于自己供职的公司,对于公司的客户也是一样的。每一次去客户那里出差前,我总是再三叮嘱自己,我此次之行是为客户做服务的,是去为客户解决问题的。这个心态非常重要,我们做软件系统的,去见客户除了做演示、做培训,很多时候就是处理现场问题,难免遇到客户对系统的投诉,比如系统速度慢、bug多等问题。当你有了这样的心态,你就会谦虚地接受客户的批评,细致地记录客户提出的问题,然后一项项地去思考如何解决,并且应该给客户一份详尽的解决方案。有了这样的心态,你会不自觉地、自然而然地与客户站在一边,让他感到你是在为他着想,帮助他去解决问题的。在你面对客户时,应该有这样一个虔诚的信念:我是去为客户服务的,为他解决他所解决不了的问题的。如果你没有这样的心态,面对投诉很可能就会产生厌烦,而且容易为自己的问题进行辩解。这种做法给客户的感觉就是你竭力在证明你是对的他是错的,这样你就站在客户的对面了。


在客户面前的表现对你的职场发展也是非常有好处的,尤其是接触到一些跨国企业时,你优良的职业素养会为你赢来客户的认同与尊敬。这样当你哪天希望寻找更高的平台,只要放个口风出去,立即就会有Offer了。所以认真服务好客户只赚不赔。


职场上如何做事

关于如何做事,也有很多的理论,比如要事第一,把事情分为紧急、重要等等,这些我都不讨论了,我只就我自己的经验来谈一谈。


对于如何做事,我也恪守一个信条:不焦不燥,把心沉下去,将注意力集中于要解决的问题上。


我看过这样一个故事,是说从前有一户人家,家里的菜园中有一块大石头,经常会有人不小心撞到;儿子就问:为什么不把他挖走呢?他的爸爸说:这个石头爷爷的时代就有了,就是因为它那么大,不好挖才一直在那里;又过了一代人,家里的一个媳妇实在受不了,就扛着锄头去挖了,她已经做好了心理准备要挖几天的时间,结果一天就挖完了... ...原来那个石头的中间是空的。


我们遇到的很多事情也是一样的,看似棘手、难以解决,实际上只要你认真地去分析、去思考,然后放手去做,往往并没有想象中的那么困难。你需要克服心中的顽石。我发现一些人遇到问题后,很轻易地就会说:这个我做不了,这个实现不了,这个我也没办法。其实就好像看到这块大石头一样,被它的“外表”吓住了,而放弃了应有的行动。


而且我发现了一个有趣的现象,不管多么困难的问题,只要你沉下心去思考如何解决,就好像在冥冥之中上苍在看着你一样,当你拼到最后就要打算认输的时候,往往会出现新的契机和方法。


另外,我发现有些人遇到问题的时候,他想的是这件事如何困难如何难以完成,这样的思维方式是有问题的,是一种保守且退缩的思维;遇到问题的时候,想的应该是如何才能够完成。我一般采取这样几个步骤:1、列出所有的可能性;2、分析各种可能性;3、选择一种实现起来最简单、快速的可能性;4、去实现。


除此以外,我发现一些人在做事的时候,会以“这样做很麻烦”来作为不采纳方案的理由,而不是“这样是否必要”或者“这样是否更好”来作为标准,实际上“麻烦”应该是排在“是否必要”、“是否更好”后面进行考虑的。如果一种实现方式,虽然麻烦,但是很有必要,且对客户来说更好,那么就算麻烦也要去做。但是程序员往往关心的是会不会很麻烦,是不是要修改很多地方,是不是给自己带来很多工作量... ...告诉你,你关心的这些不是最重要的。


职场上如何做管理

和上面一样,做管理也有很多的细节,我也都不谈了,因为这些都是一本书一本书的讲,而我觉得要简单、有效、好操作,所以我也只说三点。
我觉得做好一个技术经理,只要下面的三点就好了:


1、德行

德行其实就是品德,简单地讲就是要善良、诚恳。最重要的,你做事的出发点要是好的,对别人是没有坏心的。为什么说出发点一定要是好的呢?我们还是以服务客户的例子来说,在为客户解决问题的时候,如果我们的出发点是好的,是站在客户一边尽心尽力去为客户解决问题的,那么即便由于方法、能力、条件等各方面的原因,事情搞砸了或者没有做好,也很容易获得客户的理解和原谅。很可能的情形是,你就算做失败了也一样赢得客户;相反,如果你的出发点是“省麻烦”,“赶紧交差了事”,“完成任务”,如果事情做成了也就算了,一旦失败了,你看看客户会怎么样?告诉你,好的客户会批评你、投诉你,因为他对你还有期望;更多的客户是什么话也不说,直接换个供应商就是了,才懒得理你。记住永远不要把客户当成傻瓜,你是如何做事情的,客户是很容易感受得到的。所以,面对和服务客户没有那么多的技巧,你不需要有多好的口才和魅力,也用不着忽悠和夸大其词(我发现很多销售人员都是这样,你可以骗客户一次,但就没有第二次了),你只需要放下身段,兢兢业业地为客户着想,设身处地地解决他的问题就可以。对待下属也是一样的,你对他的奖励也好,惩罚也好,出发点一定要是好的。我对待下属遵循的原则就是:我是在帮助你,帮你把工作做的更好,帮你获得更大的提高,而不是说找你茬儿,跟你过意不去,或者是挤兑你压迫你。德行是基本的,有一个好的德行,至少可以保证你的下属不会讨厌你。


2、敬业

如果有人问我,下属和经理的区别是什么。我会告诉他:下属等着别人交代事情做,经理想着还有哪些事情可以做。这其实是一个积极心态的问题,作为一个中层干部,你需要将公司的事情当成自己家的事情来处理,当你有这样的心态,你就是再怎么加班都不会有怨言的,即便分文不取... (有谁见过给自己家装修叫苦不迭的?)如果你可以长期保持这样的状态,你的这种献身精神和敬业精神,会很轻易地感染你的下属和你的同事,你会感觉到在公司左右逢源,而且你也会更有话语权,大家会更重视你的意见,同事和下属也会对你报以更多的信任。当这种情况出现时,管理起下属还会困难吗?但需要注意的是,你的敬业精神不是说体现在无休止的加班上,工作异常繁忙、经常性加班其实是工作没有做好的表现之一,加班只应该出现在紧急情况发生的时候,而不应该是一种常态。


3、技术

如果有人问我,技术人员和其他人员最大的区别是什么。靳建通我会告诉他:技术人员个个自以为是,认为别人的技术都不如自己。呵呵,可能大家不爱听,但我观察到的现象就是这样的。很少有人愿意去读别人的代码,彼此都觉得写得好烂。所以,如果想赢得技术人员的钦佩,你需要有压倒性的技术能力。这个压倒性的优势,不是下属70分,你80分,而是下属70分,你要做到100分;下属100分,你要做到150分。所以,缺乏技术能力的人去管理技术人员往往是吃力不讨好的,可能下属表面上服从你,心里根本不当你一回事儿,这样管理起来就存在障碍了。当然,如果你的德行非常好,也非常敬业,技术就显得不那么重要了;而如果你已经满足了前面两条,同时技术也很精湛,那自然是锦上添花了。

posted @ 2013-02-24 16:53 paulwong 阅读(305) | 评论 (0)编辑 收藏

企业信息管理系统 JeeSite

JeeSite是一个 开源的企业信息管理系统 基础框架。主要定位于“企业信息管理”领域,可用作企业信息管理类系统、网站后台管理类系统等。JeeSite是非常强调开发的高效性、健壮性和安全性的。

JeeSite是轻量级的,简单易学,本框架以Spring Framework为核心、Spring MVC作为模型视图控制器、Spring Data JPA + Hibernate作为数据库操作层,此组合是Java界业内最经典、最优的搭配组合。前端界面风格采用了结构简单、性能优良、页面精致的Twitter Bootstrap作为前端展示框架。

JeeSite 已内置 一系列企业信息管理系统的基础功能,目前包括两大模块,系统管理(SYS)模块和内容管理(CMS)模块。系统管理模块,包括企业组织架构(用户管理、部 门管理、区域管理)、菜单管理、角色权限管理、字典管理等功能;内容管理模块,包括内容管理(文章、链接),栏目管理、站点管理、公共留言、文件管理、前 端网站展示等功能。

JeeSite提供了常用工具进行封装,包括日志工具、缓存工具、服务器端验证、数据字典、当前组织机构数据(用户、区域、部门)以及其它常用小工具等。另外还提供一个基于本基础框架的 代码生成器 ,为你生成基本模块代码,如果你使用了JeeSite基础框架,就可以很快速开发出优秀的信息管理系统。

为何选择

  1. 使用 Apache License 2.0 协议,源代码完全开源,无商业限制。
  2. 使用目前最主流的J2EE开发框架,简单易学,学习成本低。
  3. 数据库无限制,支持MySql、Oracle、SQL Server、H2等数据库。
  4. 模块化设计,层次结构清晰。内置一系列企业信息管理的基础功能。
  5. 权限控制精密细致,对所有管理链接都进行权限验证,可控制到按钮。
  6. 提供基本功能模块的源代码生成器,提高开发效率及质量。
  7. 提供常用工具类封装,日志、缓存、验证、字典、组织机构等,常用标签(taglib),获取当前组织机构、字典等数据。
  8. 完全兼容目前最流行浏览器(IE6、IE7+、Firefox、Chrome)。

使用技术

1、Services相关

  • Core Framework:Spring Framework 3.1。
  • Security Framework:Apache Shiro 1.2。

2、Web相关

  • MVC Framework:SpringMVC 3.1。
  • Layout Decoration:SiteMesh 2.4。
  • JavaScript Library:JQuery 1.7。
  • CSS Framework:Twitter Bootstrap 2.0.4。
  • JavaScript/CSS Compressor:YUI Compressor 2.4。
  • Front Validation:JQuery Validation Plugin 1.9。

3、Database相关

  • ORM Framework:Spring-Data-JPA 1.2、Hibernate 4.1。
  • Connection Pool:BoneCP 0.7
  • Bean Validation:Hibernate Validation 4.3.0。
  • Cache:Ehcache 2.6。

4、Tools 相关

  • Commons:Apache Commons
  • JSON Mapper:Jackson 2.1
  • Bean Mapper:Dozer 5.3.2
  • Full-text search:Hibernate Search 4.2(Apache Lucene 3.6)、IK Analyzer 2012_u6中文分词
  • Log Manager:Log4j 1.2

安全考虑

  1. 开发语言:系统采用Java 语言开发,具有卓越的通用性、高效性、平台移植性和安全性。
  2. 分层设计:(数据库层,数据访问层,业务逻辑层,展示层)层次清楚,低耦合,各层必须通过接口才能接入并进行参数校验(如:在展示层不可直接操作数据库),保证数据操作的安全。
  3. 双重验证:用户表单提交双验证:包括服务器端验证及客户端验证,防止用户通过浏览器恶意修改(如不可写文本域、隐藏变量篡改、上传非法文件等),跳过客户端验证操作数据库。
  4. 安全编码:用户表单提交所有数据,在服务器端都进行安全编码,防止用户提交非法脚本及SQL注入获取敏感数据等,确保数据安全。
  5. 密码加密:登录用户密码进行SHA1散列加密,此加密方法是不可逆的。保证密文泄露后的安全问题。
  6. 强制访问:系统对所有管理端链接都进行用户身份权限验证,防止用户

快速体验

  1. 具备运行环境:JDK1.6、Maven3.0、MySql。
  2. 修改src\main\resources\application.properties文件中的数据库设置参数。
  3. 根据修改参数创建对应MySql数据库。
  4. 运行bin\resresh-db\refresh-db.bat脚本,导入表结构及演示数据
  5. 运行bin\jetty.bat,启动服务器(第一次运行,需要下载依赖jar包,请耐心等待)。
  6. 最高管理员,用户名:thinkgem 密码:admin

posted @ 2013-02-24 16:45 paulwong 阅读(497) | 评论 (0)编辑 收藏

我做的一个的项目,如何才能顺利的交付(转)

先把项目背景简单说一下,项目A可以认为是在原有业务系统的基础上衍生出来的新需求(派生的新业务),原有业务系统是一个比较大的系统,在公司也是一个拳头产品,卖了几十套,目前也有好几个人在上面维护+二次开发+缺陷修复等(人力资源紧张)。早期公司高层只是说肯定要做这个项目,但由于人力资源的问题迟迟没有决定要开工(还有一个重要原因是领导希望能够签下1-2个典型客户再启动项目A的开发),而仅仅是上销售去那几十家客户那里兜售新业务,吹的天花乱坠的,比较市场有些竞争,需要先拉单子。这些事情是年中的事情。

等到下半年的时候,市场对这个新的业务反应比较强烈,已经有客户说要看原型再签合同,原因是竞争对手已经出原型了。而此刻,公司以为高层决定要即刻启动项目开发,说先把原型做出来,限期一个月。而中层领导还是由于人手紧张,就随便抽调了4个开发人员,一半是1年工作经验以内的新手,就这样匆忙上阵。由于人手有限、时间紧迫、业务需求虽然已经明确,但很多业务细节这4个开发人员都不清楚,只有一个懂业务的但也谈不上精通。

项目计划就定了一个月,基本上按天把计划排好了,1个月后系统原型出来了。但比较粗糙,缺陷也比较多,设计基本没有做,代码质量也比较差。拿去客户那里安装后,客户认为这个系统太粗糙了,【到客户那里,客户就不会认为这是个原型系统了】

至此,按常规项目管理的做法,应该重新梳理真实的客户需求、业务流程和功能设计、架构设计、概要设计。。。。
但事情的发展却不是这样进行的。由于客户迫切系统以周为单位看到项目的进展,于是领导决定就在原型系统上扩展和修改,其结果就是计划制定后很难执行,变成了按周来排计划,主要就是按客户的需求来改。

好不容易在年底前把版本基本上稳定了,但只是业务流程和功能比较温度,缺陷开始收敛了。

但元旦后到客户现场安装测试版本,客户对此版本又提了很多需求变更和新模块。此刻麻烦就比较大了,因为系统的架构灵活性比较差,改起来对原有代码影响比较大,改动范围大。于是又是时间紧张,又是工作量,刚把功能实现,客户就开始催啥时候测试。缺陷一直居高不小,于是决定花2周时间专门修改缺陷。

到现在为止,开发基本完成了。但问题也比较突出:
系统的性能存在问题(有些模块客户的意见很大,但这个从技术上讲,改动会比较大,不是1周能解决的)
系统的稳定性(与1相关)
功能的可用性(有些功能早期按照开发人员的思维来设计的,到客户那里客户提出新的想法,开发时把这种体验需求压住了,但在后续还是要改)
马上要启动二期的需求开发,这个更麻烦

---------------------
至此,整个项目风险还是比较大的,我总结有以下几个原因:

1. 项目的目标、业务流程、大体需求是很明确的,但细节需求在项目中前期,整个项目组都是一知半解的,造成后续返工较大,客户和开发人员包括公司领导对质量的意见都较大;

2. 项目从开始到现在领导和项目经理的分工不明确;由于人是凑起来的,大家之前没有合作过不了解;

3. 原型系统出来后,项目经理大部分时间都去解决客户的需求沟通和售前支持了,少部分时间在真正项目开发上;

4. 一直对项目的总体计划和推进情况估计不足,造成项目计划形同虚设,完全是开发人员做到哪算哪;

5. 中前期领导对这个项目不重视,等到元旦后发现问题比较严重,就临时抽调人手进来协助,而刚进来的人一方面不是项目经理想要的人(仍然是新手),另外一方面由于系统的业务性比较强,新手加进来后1-2周内根本不起作用;

6. 测试工程师,派过来的2名测试工程师是后期加进来的,业务都不熟悉,培养的2周后才慢慢熟悉,而且在客户现场,测试工程师根本应付不了客户的问题,即客户讲的需求测试工程师根本不懂或不熟悉;

大致就这些吧。 

posted @ 2013-02-23 23:12 paulwong 阅读(351) | 评论 (0)编辑 收藏

PM成长日记第三话-那些年我们一起做过的项目(转)

第三话按照原计划是要写写平常心的,因为飞跃计划要交作业,所以就改为写自己对项目管理的一些经验总结,刚好前一段时间那些年我们一起追过的女孩很是流行,这一话的名字就叫做那些年我们一起做过的项目。

我的第一个项目是在2005年,那是一家市场占有率前三的本地化翻译公司,公司的信息部门只有两个人:老大和我,我们一起开发公司内部的协同办公系统。要解决的问题很简单:由于公司发展迅速,以前单纯依靠纸质单据和邮件分派和追踪任务已经越来越让项目经理和财务不堪重负,迫切需要将这些工作给自动化。系统的技术架构也很简单:

jsp+javabean+mysql。没有专门的开发计划,基本开发流程是这样的:每周一我们访谈一个业务部门经理,了解他的需求,周中开发,开发中有任何问题都可以直接找业务经理,周五的时候系统上测试环境,再和业务经理坐到一起看一下是否满足了他的需求。系统就一直这样不紧不慢的开发着,老板办公室就在我们身后,一有时间老板就会和我们一起使用该系统。整个开发过程只有一个细节让我印象深刻,就是对任务估算工作量时,不管我估算多少,老大都会给我乘以3,一次要给业务表单增加一个字段,老大问我需要多长时间,我说不就是增加数据库字段吗10分钟,结果老大给了我半天时间,老大说,增加字段确实只需要几分钟,但打开编辑器需要时间吧,集中注意力需要时间吧,改完了启动系统测试需要时间吧,测试完了和业务经理确认需求需要时间吧,我们估算的是完成整个事情的时间而不仅仅是编码的时间。

这个项目完成时获得了公司上下的一致好评,从公司老板到业务经理,每个人都非常满意,而让我感到唯一遗憾的却是身为IT人员竟然从来都没有加过班。

回想起来,这个项目之所以成功固然是因为技术简单和系统不复杂(我们甚至都不需要 SVN,完全依靠脚本同步代码),但最重要的还是持续交付和持续的用户反馈,老板和业务经理每周都能看到新功能的上线,这增强了他们的信心,同时反馈几乎每天都在进行,并且他们很快都能看到这是否是他们想要的。

第二个项目在2006年,这一年我换工作了,因为当时我认为不加班的程序员不是好程序员。新公司在上地,是一家做协同办公业务平台的公司,最开始去的是项目部,一开始很为业务平台这个概念着迷,因为当写程序时最先不是写代码而是用代码生成器生成代码,并且生成完的代码马上可以运行!第一个项目是丰田公司的销售管理系统,我们创新的使用了当时最热的Ajax技术,我们完全是用技术热情加上周末时间完成对原有功能的 Ajax增强,这个项目获得了用户极高的评价,因为当大多数web系统还在使用点击 /刷新的方式进行交互时,我们却可以直接拖拽完成操作了。如果在当时,我会认为是技术的创新让项目获得了成功,但是现在,我会用渐进式增强这个词,即只有在完成用户所需要的核心功能(什么叫核心功能,即缺少这个功能系统不能工作)后才开始对系统用户体验、性能进行渐进式优化。

第三个项目是在公司的平台部,这里部门经理正准备对原有的业务平台进行重写,原先业务平台的技术框架是:jsp+struts+ojb+sqlserver,新的技术框架定义为: ajax+freemarker+webwork+spring+hibernate。这让我兴奋,因为新的技术框架几乎是当时最流行的技术。加部门经理共有三个开发人员(所以沟通一直不是问题),老大使用project来管理项目,每个人负责一个模块,估算以周为单位,最初计划是 5个月交付,功能直接就是老平台的翻版换的只是技术实现,但是 5个月后进行测试和项目试用时却发现了大量缺陷,最后几乎用了半年时间才将缺陷收敛,产品发布计划延期半年。回顾这个项目,需求没有进行详细的分解和评审导致实现与需求不一致 似乎是项目延期最重要的问题,然而更深的思考却是我们需不需因为技术原因开始新产品的开发,在不影响用户使用的情况下对原业务平台进行渐进式增强是否更加合适。即我们在启动项目时更多关注的应该是用户价值(只有有用户价值用户才会买单公司才有收益)。

第四个项目是我负责的,这个项目几乎是上一个项目的翻版,重写公司的工作流产品:支持更多的工作流模式,更易集成的api和管理界面,唯一不同的是这个项目采用了很多敏捷里的实践:持续集成、单元测试、站会、迭代,但这些实践均不影响这个项目最终的失败。同样是该不该重写这个项目的问题,在公司资金链紧张、时间要求紧、新产品相比竞品没有突出特性的情况下,这个项目从一开始就决定了失败。如果没有特别充足的理由就不要重写产品,这几乎成为我目前最重要的一条原则,尤其要从公司全局的角度看待产品不能局限在技术。现在,只要谁一说到要重写产品,而给出的仅仅是技术原因,我就会两股加紧,冷汗直流。在对项目完全负责的情况下,我另一点深刻感受就是人的重要性,对团队中的每个人员,作为leader 你都需要知道他的需求是什么,没有人愿意做机器人,在一次对某一技术方案简单粗暴拍板后,一个核心技术人员流失了,这成了压垮这个项目的最后一根稻草。

08年底去了一家新公司,新公司采用敏捷实践。第一个项目很成功,几乎是敏捷项目的一个成功范例,需求分析、迭代、持续集成、结对、客户 showcase、持续交付,项目甚至提前半个月完成。唯一美中不足的是项目二期时新团队由于一期文档很少带来了很多困扰。突出的感受是:团队人员有了角色、有了分工也就有了流程。现在,到了一个新的部门或中心,第一件事情往往就是梳理项目开发流程,定义出每个人的角色,职责不清是互相埋怨之源。

第二个项目是咨询项目,略去不表。第三个项目是分布式团队,一部分团队在国外,一部分团队在国内,最开始一切顺利,但在上线前一个月遇到了严重的性能问题,陷入了一片混乱当中,所有人都不知道我们离上线还有多远,还有哪些工作需要完成,优先级都是什么,项目经理甚至自己都失去对整个项目的把控,她不知道项目上线究竟需要满足什么条件,于是一次次在等待国外团队优化后的测试结果,于是一次次的测试结果不满意,于是项目在一次次的下周二上线的空头承诺中成了整个公司的笑柄。这个项目回顾起来就是团队遇到挫折时放弃了计划,迭代没有了,故事墙没有了,所有人都在等待,而项目经理为了不让开发人员被公司收回还不得不想一些优先级不高的任务给团队完成装着我们很忙。教训就是,任何情况下都不能放弃计划,计划是项目之本。其他包括团队能不分布式就不要分布式,如果必须分布式那么一定要从架构开发任务上进行隔离,尽量减少两个团队之间的交互(很多项目经理进入到部门之后推进项目制,其实也是同样的原则,团队大了就要拆解,产品代码多了也要模块化,尽量减少团队之间、模块之间的交互,做到能够各自独立演进和发布)。尽早进行实际环境的测试,越早越好。测试越早进行越好,测试环境越贴近产品环境越好,这一原则什么时候强调都不过分(我们上线前的测试才发现严重的性能问题)。

第三个项目是幸运的,因为他们有钱,能够等待,在多等待了大半年后系统终于上线。而第四个项目就没有这么走运了,这个项目是一个在线 saas CRM系统的重写,而且有着强时间约束(如果半年不能交付,将错过该系统客户每年做预算的窗口期),看吧,又是重写,又是时间约束,这几乎总预示着它厄运难逃。表面上看项目是在一次中期的架构重写中崩溃了,重写耗去了团队太多的时间,而由于对未知领域知识的不正确估算(需要学习)再次令项目雪上加霜,项目目标又不能变化,要在六个月后上线,但更深层的原因还是项目开始之前没有决策正确,真的要重写产品吗?老产品确实界面很丑、一些功能没有,但这些不能渐进式增强进行吗,一定要重新开始吗?重写使用新团队,他们对该业务领域并没有经验,过去系统遇到的坑他们不清楚,他们的计划因为少考虑了一些情况是否显得过于乐观?这个项目的其他问题包括项目计划一直没有发生变化,尽管所有人都认为在规定日期到来之前不可能交付,但这个日期却没有发生变化。最后不得不说这是一个技术强大的团队,一切都做到了自动化,甚至部署产品环境也是一键完成,但是这些在项目目标失败的情况下显得黯然失色。而客户贷款做这个项目则让很多团队成员良心不安。

来到腾讯,来到soso,最重要的收获是对运维有了新的认识,以前曾经认为devops就是自动化部署,全功能团队,现在发现它关乎架构:一条搜索的badcase是否能够很快找出错误的原因?是抓取失败,是索引时丢失,还是相关性排序不好?关乎监控和报警,我们能否很快从监控中定位出原因?关乎组织结构,前台开发,后台架构,基础架构,运维测试团队都是分离的,如何协作才能使团队合作的成本最低而整体利益最大化?

回顾往事,保尔柯察金说:如何才能不虚度光阴,只有为共产主义奋斗终身;柯景腾说:唯有沈佳宜让我怀念;而我想说的是:
做任何项目之前一定要想清楚为什么要做这个项目,一定要想清楚这个项目的价值是对用户和公司的(尤其需要跳出站到一个比较高的层次看项目),一定要想清楚项目的约束(时间约束、人员约束),不仅是项目开始之前要想,过程中要不断回顾;;
项目任何时候都必须有计划,对所有干系人透明;
项目一定是持续交付和持续反馈的,不允许黑盒出现;
测试和运维一定要尽早介入;
从每个团队成员的角度出发关注所有人的利益实现共赢。

posted @ 2013-02-22 11:20 paulwong 阅读(258) | 评论 (0)编辑 收藏

大计划有大未来

年轻时,不犹豫,年长时,不后悔。年轻时要尽早的给自己定位,是鸟就飞的更高,是鱼就游得更快。

发挥自己的特长,有所专一,不能什么都会。根据别人的经验为自己找方法。

趁自己还年轻,把想干的事都干了,只要对自己能力有提升的,别犹豫。不能等到年长时后悔当年

自己没有干什么事,不能等到年老时再聊发少年狂。

年轻时,努力的探索自己,发掘自己,积极的上进,努力的学习,积攒技能,学习人事。

要努力学习,以开放积极的心态来面对困难与挑战。

三十岁时,让自己能够独当一面,能够为人所用。跟着一群优秀的人合作共赢,积攒人脉,让自己
变得更优秀。

四十岁时,让优秀的人为自己工作,五十岁时,让优秀的人变得更加优秀。

年轻时,积累自己的耐心,价值,能力,知识,创造,付出,原则

年轻时,靠的是努力。重点是学习如何成为一员有专业素养的精兵,找到立身之本的根。

年轻时,最困难在于要在最耐不住寂寞的年纪做耐得住寂寞的事。

或许某些努力看上去是无望的,但是不要放弃,坚持不懈怠,有傻×一样的努力才有牛叉一样的结果。

三十岁,靠的是实力。重点是学习如何成为一名有管理能力的猛将,要能独挡一面。
这时,要将专业的深度,人格的成熟度,人情的练达度拧成自己的综合实力。

四十岁,靠资历。重点是学习如何成为一位有经营水平的名帅,建设枝繁叶茂的系统。
这时,你的经验,资格,见识,荣誉都要上得了台面。

五十岁,靠势力。重点是学习如何成为一位成就组织的王者,培育众木成林的势力生态。
桃李满天下,知交遍天下,关系满天下。成为培育组织,保护组织,成长组织的人。
依靠以前铺好的轨迹走自己的路。

年轻时跟优秀的人工作,三十岁跟优秀的人合作,四十岁找优秀的人为你工作,五十岁
努力是别人成为更加优秀的人。

年轻时可教,三十岁可用,四十岁有资格可捧,五十岁可敬。

五十岁的功德是自己成就的,是自己人生经验财富的积累。

posted @ 2013-02-20 00:12 paulwong 阅读(259) | 评论 (0)编辑 收藏

三个人的2012-工作篇

作者:邹振文
初六的早晨,刚从老家回来,坐在出租屋的阳台上,阳光灿烂,竟然是北京难得的好天气。距离上次写年终总结已经过去好久,打开博客,发现上次写年终总结已经是四年前的事情。上次写总结的时候还是在东直门温暖的办公室里,随着年龄的增长,觉得时间过得越来越快,四年时间,发生了太多太多的事情:有小孩了,换工作了,最重要的,是三十了。三十,意味着很多事情,古人说,三十而立,对我来说,更重要的是有了更多的责任,不仅仅是家庭,工作也如是。

年初负责的第一个项目是配置管理组的运维自动化项目,简单的说就是将之前手工管理的20多台机器使用puppet管理起来。想一想,命运真是讽刺,就在一年前,在上一家公司,自己还对持续集成工具不太感冒,不愿去学,甚至认为有些太难:机器环境的管理、构建工具、jenkins、puppet/chef、shell,觉得这些东西太琐碎,一心只想写代码。换了工作,阴差阳错,先到配置管理组工作一段时间,必须学习这些东西,过程就不多说了,只有一个感悟:很多时候,你觉得太难,只是因为你不了解它。用了两周时间,将整个puppet环境搭建起来,一切皆SVN,一切皆代码。

接下来的第二个项目是负责调研搜索新架构的自动化发布方案,这是跨部门的合作项目,大大小小跨越20多个项目组,这其中还包括了运维同事、测试同事和云计算基础服务的同事,调研一礼拜,实际上事前准备了很长时间,仅仅那一周的调研计划就修改了四版,系统整理了整个新架构的架构方式,和对方领导达成一致,取得他们的支持,了解大家的期望:开发同事希望能够更快更有效率的发布代码,测试同事希望测试的代码与发布的代码同源,运维同事希望发布过程能够遵从规范可控,当大家对共同的目标达成一致时,方案就顺理成章了:持续集成服务器负责一键编译测试打包上传到包服务器,包服务器保存所有的预发布包,预发布包经过测试后才转为发布包,发布包透过发布系统一键推送到Torca集群调度系统,Torca完成最终集群的发布调度。相比老架构,感觉新架构最明显的提升是:下载、索引和检索三大模块被分离成各自独立的服务,独立演进;统一的数据管理平台,以前追踪badcase很难判定是哪个模块处理数据出了问题,现在透过数据管理平台,数据处理过程被可视化可追踪;统一的脚本执行系统,所有脚本以及执行过程透明可视化;云计算平台,XFS文件系统、Xcube数据库、Torca集群调度、mapreduce并行计算,这些服务大大简化了上层应用的开发。越来越体会到架构的本质:随着系统的演进,我们需要不断进行系统的分解,做到服务的独立演化。当然当时也有困惑:当所有的希望都被压在新架构身上,毕其功于一役,现网老架构停止开发运营时,项目的风险可想而知。做完这个项目,感悟有两个:一是机会只青睐有准备的人;二是跨部门沟通一定要找到共同的利益点,一定要多换位思考。

4月份,准备调回项目管理组,去云计算基础架构部做项目经理。在配置管理组的最后一个项目是Jenkins的报表系统,只有一周半时间,最开始准备使用scala,考虑到后续维护最后使用了java,好久没有编码了,找回久违的感觉:打印出IDE的快捷键,搭建开发环境、测试环境和产品环境,jenkins一键自动部署,数据库版本管理,TDD,一周半的时间就上线第一个版本,最后还不得不赞一下jenkins的rest api。感悟是:感谢一期开发时间只有一周半,这使得我们不断思考到底我们要做些什么,哪些是我们最紧急最需要的,哪些是锦上添花的,一期上线后,唯一也是最大的好处就是:我们再也不用手动统计和发送构建周报了,每个礼拜一再也不用那么忙碌了。时间盒,很重要。

终于转回了项目经理,去云计算,牛人聚集的地方。首先仍旧是补课:计算机原理、Linux系统编程、C++ primer,一个都不能少。去了没多久,出现了一起事故:搜索模块对云计算SDK的依赖是源代码依赖,云计算有5个产品,但是一个产品单独发布时与之前的SDK不兼容,一发布就直接导致了大量搜索模块的无法编译。正好由我负责来推动解决这个问题,立了一个发布流程规范化项目:通过规范化发布流程、增加自动化集成测试,减少云计算平台的发布风险。所有SDK统一打基线发布,发布前必须进行自动化集成测试,server发布时也要与所有SDK版本进行兼容性测试。随着项目的进行,逐渐融入了这个部门:这是一个工程师文化非常强烈的部门,所有人都在技术上追求卓越,加班到10点以后是非常常见的事情,单元测试覆盖率令人惊讶的全部达到85%,但是很多同事一听到规范和流程就头疼,项目计划也是比较随意,延期比较常见,另外因为之前发布版本升级比较随意,也会经常受到上游兄弟部门的投诉,有很多次出现问题,兄弟部门抱怨云计算平台不稳定,而仔细检查后发现很多时候是使用的方式不对,比如查找文件时使用了遍历。逐渐意识到,部门最大的问题其实是缺少产品运营,大家的关注点全部集中在产品本身上(吞吐量、最大存放文件数、强一致性),或多或少的忽略了用户。5月下旬,风神项目启动,项目目标是搭建台风统一的监控平台和自动化部署框架,打造一站式的台风服务。开始在项目中引入项目管理的实践,WBS是最基本的了,迭代计划找到开发节奏、回顾、每个迭代结束后都努力向线上发布版本,实现持续交付,工程上则将开发环境与线上环境进行了隔离。效果都还不错,但思考更多的还是,我们还应该做些什么。产品发布规范化,必须通过自动兼容性测试和周知用户;集群环境的修改必须可被审计,暂时不能自动化,那么先必须周知部门内同事或结对操作;监控有风神项目,但集群运营、用户数据、可用率日报也需要发送;开发、测试和线上环境互相隔离;定期和用户进行主动沟通,了解他们的问题。这段经历的感悟很简单:产品的核心在于运营,作为服务部门,我们交付的一定是用户满意度而不是产品。

紧跟着,新架构还未上线,组织结构调整来了,喜欢ls的直率:我现在的任务很简单,就是看到哪里有山头就把它给平了,所有人都必须听我的,所有人的思路必须一致。

在敏捷中国大会发表了演讲《百年历史看管理》,这个session足足准备了2个月时间,重新思考了流程、组织结构和人之间的关系。从20世纪初到40年代,管理科学完成了从无到有的第一个阶段发展,这个阶段最重要的成就就是将管理作为一门科学建立起来,发现了管理的三要素:工作流程、组织结构和人,并振聋发聩的告诉所有人:管理是可以学习的。我们可以看到,所谓管理,都不过是在流程、组织结构和人这三者之中进行权衡调节,管理没有固定模式,只有不同企业根据不同情况在这三者间权衡裁剪罢了。如果说管理科学的第一个阶段是在探讨如何正确的做事,如何提高工作的效率,那么50到60年代这二十年管理科学的第二个阶段则是在探讨如何做正确的事:以顾客为中心、做事之前一定要想清楚做事的目的。管理至此也终于有了一个完整的定义:做正确的事、正确的做事。从70年代开始,管理科学进入第三个发展阶段,在这个阶段,首先提出的思想就是没有银弹,管理是一门艺术需要柔性,接下来就是流程的内涵开始延伸,不再是单纯的工作流程,而是面向顾客,强调端到端满足顾客需求的整个过程,这个过程在全球化背景下越来越强调企业之间的协调、强调整个面向交付生态系统的协调,业务流程的概念被提出。进入新世纪,不管是更合理组织结构的思考(扁平化),还是对人的推崇(乔布斯、创新)抑或是业务流程效率的竞争(供应链),都明白无误的告诉我们:管理只有恒久的问题,没有终结的答案。

9月份调整到新的部门:搜搜问问。先负责的是后台组的项目管理。新团队,老人只有一个,士气低下,缺少文档,上百个服务,光维护就非常困难,重写计划。从回顾会议开始,持续改进。这段时间的感悟是:提升团队士气的最好方式就是帮助大家成功,任何一点成绩都值得鼓励。我们引入了持续集成和自动化发布,鼓励同事做总结和分享;引入了自动化测试,鼓励同事做汇报,帮助review ppt;积极的让大家做有态度的程序员,对产品进行思考和反馈,把团队精神传递到部门经理,让部门经理进行鼓励。可以自豪的说,后台组是现在问问最有战斗力的团队。还有一点最重要的感悟是:一定是团队leader决定团队是否给力,幸运的是,我们有一个非常优秀的leader。

12月份开始负责部门的社区化运营项目。这和今年工作的感悟是一致的,产品的核心在于运营,这正是我想做的。项目立项一定要有一个NB的名字,我们就叫黑暗骑士。这个项目同样面对很多的挑战,目前最大的挑战还是在于人,团队的信心目前还没有建立,年后可能还会有人提出离职,而招人又是如此的困难,所以,上班第二天的第一件事是回顾会议。团队年前第一个版本发的很有挫折感,需求反复修改,开发人员都心灰意冷,所以,感悟是:一份优秀的需求文档是一切合理计划的起点。

1月份组织了技术中心的部门年会节目,我们原创的小品《非问勿扰》获得了二等奖。把新人都变为主角,这也算团队建设的一部分。

依然在不停思考,对问问来说,我们还应该做些什么。传统问答模式作为搜索引擎的补充是否已经走到了尽头?SNS的问答模式是否值得探索?与微博是否有更深的整合方式,或者,它们本身就是一种产品的两种展现方式?新浪微什么的探索是否还不够大胆?在移动端,独立的app没有前景,如何和微信更有力的结合。

终于到了可以结尾的段落,还有一件事情似乎忘了总结,那就是我们写了长达四年的那本书《流程的永恒之道-一个工作流和BPM项目的实战》,什么也不说了,一个例子来说明为什么值得期待:当我们把房管局及各委办局的数据和流程用BPM全部打通后,客户却依旧坚持要手动盖章走人工流程,BPM实施技术根本就不是瓶颈,瓶颈依旧是人啊。今年上半年一定出版。之所以写了四年,是因为写着写着总觉得知道的越来越不够,不断读书和补充内容,真是,那时年少,无知者无畏,唉。

2013,黑暗骑士崛起!
本文为转载:原创地址http://www.software8.co/wzjs/cxyyg/2953.html

posted @ 2013-02-20 00:07 paulwong 阅读(246) | 评论 (0)编辑 收藏

Phoenix: HBase终于有SQL接口了~

这项利器是由CRM领域的领导Saleforce发布的。相当于HBase的JDBC。

具体详见:https://github.com/forcedotcom/phoenix

支持select,from,where,groupby,having,orderby和建表操作,未来将支持二级索引,join操作,动态列簇等功能。

是建立在原生HBASE API基础上的,响应时间10M级别的数据是毫秒,100M级别是秒。


http://www.infoq.com/cn/news/2013/02/Phoenix-HBase-SQL

posted @ 2013-02-19 23:15 paulwong 阅读(2794) | 评论 (0)编辑 收藏

仅列出标题
共115页: First 上一页 70 71 72 73 74 75 76 77 78 下一页 Last