2006年3月30日
#
很不错的一个UML建模工具-argouml
argouml下载地址
我一眼就看上他的原因是:生成的用例和包图可能直接生成JAVA代码,而且准备无误,这正是我要找的。
我想:以后使用一些框架的话,可能由PD生成一些实体,然后Hibernate生成pojo等,加入到argouml,然后根据一个框架的特性生成一些包
和类.就等于详细设计了吧.应该来说是比详细设计还实用的东西.总比哪些WORD文档好吧.还有让人看不懂的概要设计.
我想从技术出发,这个是一条比较适用的路子.下班了.我明天将会汇报一下我使用的情况和一些范例.
反过来又想像.这好象是一个组合的脚手架.好象ROR的零星操作步骤.应该学习.ROR毕竟是一个新生事物,JAVAEYE的推广也需要一个时间.如果像我这样的打工,混口饭吃的人还是专心的研究J2EE好一点.否则明天就没有饭吃了.
呵呵.我的文章可被JAVAEYE收回到水贴里了,可能自己的能力不如人吧,好好学习,天天向上,如果看客有什么好的工具和软件生产思路,可以共同交流。
今天学习了一下ROR,有一些学习经验东西要与大家分享。
给ROR加一个座右铭--------狭窄心肠的日本产物。
首先,不要一个一个的下载Ruby,Rails,建议使用一键安装,下载地址如下:
InstantRails-1.3-win
版本说明:ruby 1.8.4 (2005-12-24) [i386-mswin32]
其次,下载一个目前为止比较好的一个ROR的实践工具:RadRails
下载地址:radrails-0.7.1-win32
接下来,设置一下Radrails的环境
1)、Windows/perferences/Ruby/Installed Inteperters/ ->add ruby所在路径:比如D:\InstantRails\ruby\bin\ruby.exe
2)、Windows/perferences/Rails/Configuration ->Rails path:比如D:\InstantRails\ruby\bin\rails
->Rake path:比如D:\InstantRails\ruby\bin\rake 绝不是bat/cmd
->mogrel path:比如D:\InstantRails\ruby\bin\mongrel_rails绝不是bat/cmd
有了如上的配置后,就只需要和在JAVA当中ANT一样使用。(成功用过APPFUSE的人就不用害怕了)
看看日本人写的第一步:
1),在RadRails中创建一个Rails Project,怎么样会出来一堆的东东。
2),进入DOS命令吧,后面的工序都是这样的,好象买了海尔的洗衣机,第一次是送货、第二次是用户回访,第三次是.....
进入到你的项目处,运行ruby script\generate controller MyTest,
则得到的服务如下:
exists app/controllers/
exists app/helpers/
create app/views/my_test
exists test/functional/
create app/controllers/my_test_controller.rb
create test/functional/my_test_controller_test.rb
create app/helpers/my_test_helper.rb
修改一下my_test_controller.rb
代码
class
MyTestController
<
ApplicationController
def index
render_text
"
Hello world!!
"
end
end
在浏览器里输入:http://127.0.0.1:3000/my_test/
会出现 Hello world!!字样,
不过有意思的是你可以输入:http://127.0.0.1:3000/My_test/
http://127.0.0.1:3000/My_Test/
http://127.0.0.1:3000/my_Test/
都可以得到这个值,可能没有JAVA哪样严格吧。
3)、还有对数据库的操作,要配置一个database.yml(好象Log4j的东东)
4)、创建数据库表的时候只能够使用复数起名,比如User就不行,只能够起Users
下面只要执行几个命令就可以使用增删改查了。
如下是我的操作,下班了,就不多写了,例子能够说明一切问题:
代码
1 E:\RORProject\demo>ruby script/generate model user
2
3 exists app/models/
4
5 exists test/unit/
6
7 exists test/fixtures/
8
9 create app/models/user.rb
10
11 create test/unit/user_test.rb
12
13 create test/fixtures/users.yml
14
15 exists db/migrate
16
17 create db/migrate/001_create_users.rb
18
19 E:\RORProject\demo>ruby script/generate controller user
20 exists app/controllers/
21 exists app/helpers/
22 create app/views/user
23 exists test/functional/
24 create app/controllers/user_controller.rb
25 create test/functional/user_controller_test.rb
26 create app/helpers/user_helper.rb
27
修改user_controller.rb如下:
代码
1 class UserController < ApplicationController
2 scaffold:user
3 end
最后你的浏览器当中输入:http://127.0.0.1:3000/user/list,就包括了对数据库表的四个操作.当然你也可以自己定义四个操作的任意一种.
最后总结:
ROR可能是敏捷开发的一个好实践,但是我觉得他完成复杂应用进不会有大做为,而至于这一点还需要再做探究。不过现阶段最好的需求就是能够给用户快速的写出一个不完整的DEMO,这一点为以后打单取得主动。
摘要: 只需要你三个JAVA类和两个配置文件,就可以完成你的MVC应用,我们就做一个示例吧。本文以一个登录为例。第一个JAVA文件Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->/**======================================...
阅读全文
在项目开发的很多时候,用户需要更友好,更容易理解的操作界面,而为了能够达到这种表现界面,struts标签显得力不从心,本人经过几个项目的开发当中 逐渐的摈弃了struts标签,而由JSTL来做为JSP页面的表达者。
struts标签之死穴一 不支持嵌套
看看这种常见的需求吧。一个用户隶属于一个职能部门,比如
项目要求 职能部门有五个(乱写的)
1、企划部
2、网络集成部
3、行政部
4、营销部
5、产品部
项目要求 一共有二个员工
1、张三 隶属于行政部
2、李四 隶属于营销部
而你想把张三和李四都列表出来,显示为如下:
姓名 部门名称
张三 行政部
李四 营销部
而且还需要用户的列表链接到修改页面当中(假如只修改部门)应该如何做呢。
在使用struts标签是很难做到的,除非你非常不在意内存的使用(乱写技术性代码)
看看JSTL是如何做的吧。
从STRUTS的ACTION当中加载两个对象
List GetAllDept
=
UserDAO.GetAllDept();
//
取得所有部门
List GetALLUser
=
UserDAO.GetAllUser();
//
取得所有用户
request.setAttribute(
"
View_Dept
"
, GetAllDept);
request.setAttribute(
"
View_User
"
, GetALLUser);
在页面当中加入对JSTL的引用
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
然后写代码如下:
<table>
<tr>
<td align="center">
<a href="User.do?method=EditUser&UserId=<c:out value='${View_User.UserId}'/>">
<c:out value="${View_User.UserName}" /> </a>
</td>
<td align="center">
<c:forEach items="${View_Dept}" var="View_Dept">
<c:if test="${View_User.Dept.DeptId==View_Dept.DeptId}">
<c:out value="${View_Dept.DeptName}" />
</c:if>
</c:forEach>
</td>
</tr>
</table>
其中View_User.Dept.DeptId表示USER表与DEPT表的一个关系(外键)
你就可以看到所显示的列表了。
还有如果在修改用户时,则也与上面的差不多,首先在ACTION当中加入:
String ModifyUserId = request.getParameter("GroupUserId");
if (ModifyUserId == null && ModifyUserId.equals("")) {
//这是出错处理
request.setAttribute("UserMsg", "User.ValidateUser");
return mapping.findForward("Fail");
}
DynaValidatorForm UserActionForm = (DynaValidatorForm) form;
User user = UserDAO.GetUser(ModifyUserId);
List GetAllDept = UserDAO.GetAllDept();//取得所有部门
request.setAttribute("View_Dept", GetAllDept);
UserActionForm.set("User", User);
然后页面当中显示如下(部门为LISTBOX),例子当中只显示部门
<html:select property="DeptAsString">
<c:forEach items="${View_Dept}" var="View_Dept">
<c:choose>
<c:when test="${User.Dept.DeptId==View_Dept.DeptId}">
<option value="<c:out value='${View_Dept.DeptId}' />"selected>
<c:out value="${View_Dept.DeptName}" />
</option>
</c:when>
<c:otherwise>
<option value="<c:out value='${View_Dept.DeptId}' />">
<c:out value="${View_Dept.DeptName}" /></option>
</c:otherwise>
</c:choose>
</c:forEach>
</html:select>
可以看到HTML的SELECT有一个DeptAsString,你可以在FORM当中指定一个STRING的FORM属性。
这样用户的要求就可以完成了。
本次只说明方法,而代码没有经过测试。希望大家多多观注我的BLOG,下一次将臭骂ACTIONFROM不支持的DATE类型及解决方法。
摘要: 在大家的编码过程当中,有没有遇到过这么一种情况,很多零乱的状态、分类和其它常用选项常常是定义死了。但是没有一个完整的东东来约束他,在每个模块当中使用相关的信息时,往往重新COPY一次,或者COPY过来修改一次。如果多人协作的话,务必会让代码变的零乱、不好管理等。
本次主要是把一些静态的分类、状态或者其它常用选项使用二维数组管理起来。如果你是一个使用JSTL或者STRUTS做前台表现的话,你就更应该好好关注了.......
阅读全文
在工作当中,遇到了一个不明智的上级,我是刘罗锅,但是领导不一定是乾隆。设计当中的争执成为私下做对的理由,从此,我感觉到今年的财运不佳。
因为工作当中的争执,而让领导失去了面子??我在郁闷当中,为什么呀!好事反而成了坏事。
领导的报复心理,让我失去了绩效,所以我感觉到财运不佳。我很想跳出这个魔鬼圈,是不是能够改善一下自己的经济收入呢?正在想离开这个公司......
发现自己的软肋:UML整体设计(最好有代码生成)和XP敏捷开发。近期需要加强这两方面的学习,可以以权限设计为UML做为训练(生成代码??),以CRM->VtigerCRM为业务主线,做一个XP开发,不过VtigerCRM的表设计真是很糟糕,Indiea人呀。
今年的公司很乱,是一个很糟糕的管理层,可能我以后离开这个公司后才感觉到领导者的“聪明才智”吧!完全在内耗当中生存。我已经被领导国边缘化,我会在灰色的区域彷徨很长的时间,或许公司另有高人吧,我已经被领导逐渐忽视,自己发光的时间也只有一年,好象知了一样。
“人贵有自知之明”,如果领导没有重视,只是为了发挥自己的最低性能的话,我完全有很多的时间来学习知识,我很庆幸自己和开源代码有很大的信心,我将在以后的时间里,为开源界展示自己的能力。
首先要把自己学习到的知识透明化,其次我会在开源中小型的CRM软件当中做出自己应有的贡献。
struts表单主要是利用actionform来取得JSP页面所有的request的,所有的Struts标签无非在取得request当中的所有INPUT,并赋值回标签值的,同理,JSTL能够在JSP表单当中轻易的表现要输出的结果。
如果你是高手,你就知道这个标题有误,是的,struts表单与JSTL表现没有可比性,但是如果我们要在实现一个多条件的查询页面时,这个比较就比较有效了。
我不妨比较一下利用struts表单的查询实现 和 利用JSTL做为表现而实现的查询功能有什么不同,让读者寻其方便。
示例说明:
用户表-USER
username 用户名称
loginid 登录ID
sex 性别
一、利用struts表单的查询实现
实现步骤:
创建多条件的序列化对象(java)->在struts.config当中申明actionform->Action当中实现->输出结果
/** The value of the simple userName property. */
private java.lang.String userName;
/** The value of the simple loginId property. */
private java.lang.String loginId;
/** The value of the simple sex property. */
private java.lang.String sex;
/**
* Return the value of the USER_NAME column.
* @return java.lang.String
*/
public java.lang.String getUserName()
{
return this.userName;
}
/**
* Set the value of the USER_NAME column.
* @param userName
*/
public void setUserName(java.lang.String userName)
{
this.userName = userName;
/**
* Return the value of the LOGIN_ID column.
* @return java.lang.String
*/
public java.lang.String getLoginId()
{
return this.loginId;
}
/**
* Set the value of the LOGIN_ID column.
* @param loginId
*/
public void setLoginId(java.lang.String loginId)
{
this.loginId = loginId;
}
/**
* Return the value of the sex column.
* @return java.lang.String
*/
public java.lang.String getSex()
{
return this.sex;
}
/**
* Set the value of the sex column.
* @param loginId
*/
public void setSex(java.lang.String sex)
{
this.sex = sex;
}
<!-- struts_fonfig -->
<form-bean name="UserActionForm" type="org.apache.struts.validator.DynaValidatorForm">
<form-property name="userCondition" type="com.antbee.searchCondition.UserFindCondition" />
</form-bean>
Action当中
DynaValidatorForm UserForm = (DynaValidatorForm) form;
UserFindCondition Condition = (UserFindCondition) UserActionForm
.get("userCondition");// 取得查询条件
List user = userManager.find(Condition,
(iCurPageNo - 1) * pageCon.PAGE_SIZE, pageCon.PAGE_SIZE);//呵呵,加入了hibernate的分页
具体实现:
public List find(UserFindCondition Condition, int begin,
int count) {
StringBuffer sql = new StringBuffer("from User as a where 1=1");
if (Condition != null) {
makeSql(sql, shipmentFindCondition);
}
String fsql = sql.toString();
Query query = this.getSession().createQuery(fsql);
if (Condition != null) {
setParameter(query, Condition);
}
query.setFirstResult(begin);
query.setMaxResults(count);
List tt = query.list();
return tt;
}
--
/**
* 根据条件生成一个sql语句
*
* @author 和
* @param sql
* 初始的sql语句(一般为select a from A as a where 1=1)
* @param condition
* 查询的条件
* @return
* @version 1.0
*/
private void makeSql(StringBuffer sql, UserFindCondition condition) {
if (condition.getUsername() != null
&& !condition.getUsername().toString().equals("")) {
sql
.append(" and a.username like :username");
}
if (condition.getLoginid() != null
&& !condition.getLoginid(().equals("")) {
sql
.append(" and a.loginid( = :loginid(");
}
if (condition.getSex() != null
&& !condition.getSex().equals("")) {
sql.append(" and a.sex = :sex");
}
}
/**
* 根据条件设置query的值
*
* @author 和
* @param query
* 一个hibernate的Query对象
* @param condition
* 查询的条件
* @return
* @version 1.0
*/
private void setParameter(Query query, UserFindCondition condition) {
if (condition.getUsername() != null
&& !condition.getUsername().equals("")) {
query.setString("username", "%" + condition.getUsername()
+ "%");
}
if (condition.getLoginid() != null
&& !condition.getLoginid().equals("")) {
query.setString("loginid", condition.getLoginid());
}
if (condition.getSex() != null
&& !condition.getSex().equals("")) {
query.setString("sex", condition.getSex());
}
}
呵呵,笑死人了,这个方法很通用,我才在我的第二个项目当中才用到,真是可惜,当然了,使用Actionform有一个毛病就是对date类型要转换成STRING类型来处理,这是actionform的一个死穴。还有对Actionform不能够重置,只能够回来从前。不知道这群设计者怎么想的,真是由于这一点,所以我们有必要使用最原始的方法来解决问题了。使用页面当中的input,我们来拼request如何?
二、利用JSTL做为表现而实现的查询功能
步骤:在JSP页面布置很多的input,当然,你可以加入value了。(省略了...)
创建查询条件的序列化对象(同样user.java)
在action当中拼个condition了,做为查询条件,后面的处理类同第一种方式。
UserSearchCondition userSearchCondition = null;
userSearchCondition = makeUserSearchCondition(request);
private UserSearchCondition makeUserSearchCondition(HttpServletRequest request) throws Exception{
UserSearchCondition userSearchCondition = new OrderSearchCondition();
String username = request.getParameter("Username");
String loginid = request.getParameter("Loginid");
String sex = request.getParameter("Sex");
if(username!= null && !username.trim().equals("")){
usernameSearchCondition.setUsername(username);
}
if(loginid != null && !loginid.trim().equals("")){
userSearchCondition.setLoginid (loginid );
}
if(sex != null && !sex.trim().equals("")){
userSearchCondition.setSex(sex);
}
return userSearchCondition;
}
以后的方法,我就不用再做举例了吧,可以参考如上第一种方法的实现.
第二种方法的好处就是:在页面上比较好控制,比如重置,又比如日期性数据等。
(所有过程当中的代码没有经过测试,只是说明这种方法而已)
呵呵,在忙一个项目,潜水很久,现在冒个泡:
(本文适用在struts+spring+hibernate3上做开发的虫虫们)
类名:HibernateUtil
package com.antbee.j2eemodel.util;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Iterator;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
public class HibernateUtil extends HibernateDaoSupport {
/**
* 初始化POJO类
* @author @家军
* @param object POJO对象
* @param methodName 方法名称
* @return
* @version 1.0
*/
public void initialize(Object object, String methodName) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
String[] methodArray = methodName.split("\\.");
Method method = null;
Object initializeObject = object;
if(methodArray.length == 1){
this.getHibernateTemplate().lock(initializeObject, org.hibernate.LockMode.NONE);
method = object.getClass().getMethod(methodArray[0], new Class[] {});
initializeObject = method.invoke(initializeObject, new Object[] {});
this.getHibernateTemplate().initialize(initializeObject);
}else{
for(int i=0;i<methodArray.length;i++){
method = initializeObject.getClass().getMethod(methodArray[i], new Class[] {});
initializeObject = method.invoke(initializeObject, new Object[] {});
}
this.getHibernateTemplate().lock(initializeObject, org.hibernate.LockMode.NONE);
this.getHibernateTemplate().initialize(initializeObject);
}
}
/**
* 初始化POJO类
* @author @家军
* @param object POJO对象
* @param methodName 方法名称数组
* @return
* @version 1.0
*/
public void initialize(Object object, String methodName[])
throws SecurityException, NoSuchMethodException,
IllegalArgumentException, IllegalAccessException, InvocationTargetException {
for (int i = 0; i < methodName.length; i++) {
String[] methodArray = methodName[i].split("\\.");
Method method = null;
Object initializeObject = object;
if(methodArray.length == 1){
this.getHibernateTemplate().lock(initializeObject, org.hibernate.LockMode.NONE);
method = object.getClass().getMethod(methodArray[0], new Class[] {});
initializeObject = method.invoke(initializeObject, new Object[] {});
this.getHibernateTemplate().initialize(initializeObject);
}else{
for(int j=0;j<methodArray.length;j++){
method = initializeObject.getClass().getMethod(methodArray[j], new Class[] {});
initializeObject = method.invoke(initializeObject, new Object[] {});
}
this.getHibernateTemplate().lock(initializeObject, org.hibernate.LockMode.NONE);
this.getHibernateTemplate().initialize(initializeObject);
}
}
}
/**
* 初始化POJO类
* @author @家军
* @param object POJO对象
* @return
* @version 1.0
*/
public void initialize(Object object) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
this.getHibernateTemplate().lock(object, org.hibernate.LockMode.NONE);
this.getHibernateTemplate().initialize(object);
}
/**
* 初始化POJO类
* @author @家军
* @param collection POJO对象集合
* @param methodName 方法名称数组
* @return
* @version 1.0
*/
public void initialize(Collection collection, String methodName[])
throws SecurityException, NoSuchMethodException,
IllegalArgumentException, IllegalAccessException, InvocationTargetException {
for(Iterator i=collection.iterator();i.hasNext()Wink{
Object object = i.next();
this.initialize(object,methodName);
}
}
/**
* 初始化POJO类
* @author @家军
* @param collection POJO对象集合
* @param methodName 方法名称
* @return
* @version 1.0
*/
public void initialize(Collection collection, String methodName)
throws SecurityException, NoSuchMethodException,
IllegalArgumentException, IllegalAccessException, InvocationTargetException {
for(Iterator i=collection.iterator();i.hasNext()Wink{
Object object = i.next();
this.initialize(object,methodName);
}
}
}
这个方法的好外是:可以不在hbm.xml的文件当中,指定为lazy=true这个模式,可以直接使用。使用方法如下:
如果你使用SPRING,则需要把hibernateUtil注入其中:
<bean id="hibernateUtilTarget" class="com.antbee.j2eemodel.util.HibernateUtil">
<property name="sessionFactory">
<ref local="mssqlSessionFactory" />
</property>
</bean>
<bean id="hibernateUtil" parent="BaseTransactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="target">
<ref local="hibernateUtilTarget" />
</property>
</bean>
<!--配置基础事务-->
<bean id="BaseTransactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true">
<property name="transactionManager">
<ref bean="mssqltransactionManager" />
</property>
<property name="proxyTargetClass">
<value>true</value>
</property>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
使用示例:
如果你使用STRUTS,则需要这样:
List what_ur_view = XXXManager.find(.);//取得你要展示的对象
//如果这个对象当中有延迟加载的对象(SET)时,则需要如下加载就行
this.hibernateUtil.initialize(what_ur_view, "getTbShipmentSale");
//其中getTbShipmentSale是其对象(SET也可以操作)
在页面显示的时候,你就可以使用JSTL如下表述:
<c:out value="${what_ur_view.tbShipmentSale.goodsReceivePersonPhone}" />//呵呵,是不是很爽呀。
同样的方法,我们也可以对一个SET在页面进行显示,方法如下:
<c:forEach items="${what_ur_view.tbShipmentProductMappingSet}" var="ProductMapping" varStatus="status">
<c:out value="${ProductMapping.productNum}" />
<c:out value="${ProductMapping.tbOutOfWarehouse.outOfWarehouseNum}" />
</c:forEach>
//呵呵,支持多级嵌套,
在ACTION当中则需要加入hibernateUtil.initialize(what_ur_view.getTbShipmentProductMappingSet(),
new String[] { "getTbProduct", "getTbOutOfWarehouse",
"getTbProductConfigure" });
呵,如果你要是在HIBERNATE当中使用,这个就太简单了吧。
怎么样?呵呵呵,
从此,我对STRUTS的标签深恶痛绝,而对JSTL情有独钟了。
很长的时间陷入到与同事上级的斗争当中,无聊死了,今天回来看看自己书签当中的网站,感觉到自己是小人了。我不应该留恋明争暗斗,我应该自立自强,永不停息。
在年前的时候我曾经非常看好compiere的应用,想不到今天再看看国内使用的形势,长三角和珠三角的广泛应用,还有ORACLE免费数据库的推出,更加印证了我错误的做法。
一个人最重要的事情就是三个字:做决定。
一个人想要成功,尤其像我这样不甘愿给别人打工又有很多想法的人,除非是一种病态的坚持才能够取得成功。
我很讨厌公司现行的CRM系统,简单的说一句就是:简直就是一个糊人的、丑陋的MIS系统,一点设计思想都没有,一点产品理念都没有。最重要的设计者在拼命的逃脱自己的责任,开发者在忍受莫大的痛苦,业务在每一个开发者思想里扭曲......唉,想抽出一点时间来都难。
我要在以后的时候里,一则增加自己的业务能力,以compiere的应用为主;二则要增强我的技术能力,以
vTigerCRM为蓝本,做一个J2EE的产品移植。
在今年年底以前,自己必须要做到对compiere的应用熟练,能够完成
vTigerCRM的J2EE实现。所以自己最重要要做的事是:时间安排,
来自于:http://blog.csdn.net/Raptor/archive/2006/05/13/727299.aspx
关于软件开发的笑话有很多,下面这个是我刚在QQ群里的看到的:
1. 程序员写出自认为没有Bug的代码。
2. 软件测试,发现了20个Bug。
3. 程序员修改了10个Bug,并告诉测试组另外10个不是Bug。
4. 测试组发现其中5个改动根本无法工作,同时又发现了15个新Bug。
5. 重复3次步骤3和步骤4。
6. 鉴于市场方面的压力,为了配合当初制定的过分乐观的发布时间表,产品终于上市了。
7. 用户发现了137个新Bug。
8. 已经领了项目奖金的程序员不知跑到哪里去了。
9. 新组建的项目组修正了差不多全部137个Bug,但又发现了456个新Bug。
10. 最初那个程序员从斐济给饱受拖欠工资之苦的测试组寄来了一张明信片。整个测试组集体辞职。
11. 公司被竞争对手恶意收购。收购时,软件的最终版本包含783个Bug。
12. 新CEO走马上任。公司雇了一名新程序员重写该软件。
13. 程序员写出自认为没有Bug的代码。
要我说,如果真有这样的公司,不倒闭对不起人民。
这个笑话从程序员开始,到程序员结束,从头到尾都在说程序员的不是。但是我要说的是,这完全是管理者的失败,从整个过程中,看不到任何管理工作。这种管理者不但无知无能,还很无耻——将自己的失败责任推给程序员。
1、程序员凭什么证明他的代码没有BUG?有Test case吗?有Code review吗?这个环节管理缺失。
2、测试发现BUG有进行BUG管理吗?有跟踪吗?这个环节管理缺失。
3、凭什么证明程序员已经把那10个BUG修改好了?另10个又为什么不是BUG?BUG的评价标准难道是程序员说了算?这个环节管理缺失。
4、5个不能工作的BUG修改问题有没有追究责任?增加新BUG是修改过程中不可避免的事情,但是如果有有效的单元测试机制,可以大大减少这种情况。这个环节管理缺失。
5、迭代是正常的,但是问题处理于发散而不是收敛发展,可见没有有效的管理调控。这个环节管理缺失。
6、过于乐观的时间表和不可能达到的最后期限,都表现出管理者的无知和无能。而在这样的情况下强行推出产品,那就是无知者无畏了。
7、这是对用户的不负责任,管理者要负最大的责任。
8、这样的情况还能发项目奖金,只能说管理者不是一般的愚蠢。
9、管理工作没有任何的改进,问题仍然处于发散迭代状态。管理工作依然没有到位。
10、拖欠测试部门工资体现出管理者对质量管理工作的忽视以及对人力资源管理方面一无所知。
11、送被收购者两个字:活该。送收购者两个字:瞎眼。
12、可见新管理者与原管理者半斤八两,都没有认识到问题的根本所在。不过也只有这样的管理者才会作出收购这种公司的决策。
13、历史的重演是必然的。
一个正常的企业或是项目,其运作必须应该是循环向上进行的。而保障这种运行的工作就是管理。而管理工作的主要内容就是控制,包括控制循环的节奏——不能太快也不能太慢,控制发展的方向——只能向上不能向下,控制运作的稳定——不能大起大落或时聚时散等。
而这一切,在这个例子中都看不到。
在 这个笑话的例子中,一切都是以开发工作在驱动,这首先就是一个方向性错误,产品是为用户服务的,当然应该是以用户和市场作为驱动,并且结合自身的能力最终 确定工作的重点。这一错误折射出管理者对被管理的内容很不了解,只好任由比较了解的程序员摆布——事实上他们除了技术,并不会了解更多。
一个管理者如果对自己所管理的内容不了解,他就不可能管理得好。
这是一件毫无疑问的事,可是国内的软件业似乎总是不相信这一点。中国软件业中流毒最深的谎言之一就是:
管理者只要懂管理就可以,不需要懂技术。
其实这不过是那些无知无能无耻的管理者为了骗钱而编出来的,相信这句话的人必将付出金钱的代价。
其 次是质量管理。基本的质量管理常识告诉我们,每次循环结束前,最重的工作就是总结改进。只有这样才能保证循环运作是向上发展,而不是失去控制地向下发展。 也只有有效的质量管理,才能保证迭代过程是收敛发展,并最终达到目标。但在这个例子中,这个部分显然是缺失的——其中虽然有测试部门,但是他们的作用仅仅 是质量管理中的质量检测环节,管理部分还是缺失的。
然后是人力资源管理。软件开发是一项劳动密集型的工作,虽然这是脑力劳动,但同样意味着人在因素在其中占有决定性的地位。而例子中未改完BUG的程 序员拿到项目奖金,而同样辛苦工作的测试人员却被拖欠薪资,除了表现出管理者对他们的工作内容的不了解,以及对质量管理工作的不重视以外,还表现出管理者 完全不会管人,这是一种谋杀团队的行为——谋杀一个团队远比建设要容易得多。
最后,这个失败的管理者把他的经历编成这个笑话,让大家看到他被程序员们害得多惨,把程序员妖魔化为一群骗子。但只要稍懂管理的人简单分析一下就可以看出来,只不过是这个人的无知和无能造成了他现在的结果,而把责任推给别人的行为更是表现出他的无耻。
作为身居高位的管理者,如果连应该承担的责任都要推卸,他们还能胜任什么事情呢?
百度公司今天搬到我们这幢楼内,更加刺激了我去百度的念头,因为我喜欢创新的工作,所以我将为这一点而去努力奋斗。
不是说百度公司有多好,主要是想稳定上几年,有一点积蓄了,就可以自己出来自谋生路。呵呵。看见百度技术的职位只有无线搜索技术用到了JAVA,呵呵,不会灰心,其实,PYTHON或者RUR都将是以后的方向,至于PHP,我感觉百度会在不远的将来抛弃掉的。在服务器的性能和安全争端上我只相信JAVA,百度只不过把这一种技术很快转化成了资本,如果百度想要和GOOGLE一争高下,实质性的工作--技术上必须上要胜出GOOGLE一筹才行。而这一点只有行家才知道。
我在北京的这几年都是为代码,或者就是为纯粹的技术而奋斗,其实做为软件公司,其起步主要是靠技术,但是他成名或者有所富裕后,就觉得人情是一个比技术还好玩的东西时,这个公司就开始有了差距,不过,这个公司就开始危险了,或者是穷途末路,只能钻到钱眼里去了。如果管理层(其实就是和有权的腐败工厂DANG有关系的人)没有动静的话,这个公司必死。这就是中国的国情。
工厂DANG叫嚷的中国国情就是要隐含有权层的灰色收入,况且五千年的封建文化完全可以掩盖这一点。否则,会把老祖宗也搬出来。孔子曰:孟子说:还有什么孙子谈兵什么的。
从程序员的角度思索一下,如上是IF.....ELSE....的语句后,final,工厂DANG治理的天下乱七八糟。
呵呵,我在北京买到房子了,贷款了40万元,在签订了很多的不平等条约后,我成为了一个正式的房奴了,但是我很高兴。
我来自于农村,我最原始的生活憧憬就是改变农村这种生活方式,我在很小的时候就不喜欢农村的黄昏,因为夕阳照着我疲背一天身体时,我感觉到生命的绝望。于是我要改变自己,改变整个家庭的命运。
父亲很努力,在我懂事的时候就进入了县城,我的心理比较的蹋实了,好象有了可以骄傲的资本,虽然家庭的收入很拮据,但是我认为自己要改变的不只是这一点。
于是我只身来到北京,举目无亲的可怜像和在火车站睡觉的经历更加激励了我,我要生活下去,我从上大学的时候就有一个始终不愈的信念:打不死的精神活到老。
我对生命很是无所谓,因为我知道自己已经在阶级社会的最低层,我不害怕自己的失败,我也不在乎钱,钱对于我来说只是肯定我的成绩,肯定我的所有为是有效的。
呵呵,我成为了北京的一员了,我的想法很简单,当我20年后,如果我的儿子不在北京发展了,我将买掉我的房子,回家后,我也应该成为自由的生活者了,我已经能够让我的晚年有所事事了。
这一段时间主要在忙一个紧急的项目和公积金贷款,我将撰写一个比较权威详细的的贷款程序、
博客将给我一个表现自己全新的舞台,我将为生命之花绽放。
说起来危险吧,就是对纳税人的不满,如果纳税人有追求自由的念头,那么你就知道中国的经济有多危险。
呵呵,危险的中国楼市
危险的就业大军
危险的新农村政策
新农村的建设就是废除个人承包制,恢复现代地主制。看小X忙的不亦乐乎,他在干着财富分裂的现代社会主义建设。好象农民脱离了土地,浮萍会被枯叶败枝聚集,壮观的让人压抑。
程序员不谈政治了。否则,后果不好。
最近没有时间写BLOG,虽然心理有很多想法想写,想努力的推进开源代码的实施,但是被尖刻的客户托垮了。
可能是我目前见到最尖刻的客户吧,用户在使用软件当中,遇到任何一点可疑的问题就打电话“责令”修改,否则没有快速响应,最高的领导就出面给我施加压力。我CALL,我真是对这群滥人生气。所以我不得不打断所有的工作而快速响应,于是晚上自愿加班到9-10点,已经有三周没有休息了。最要命的这个项目的设计者、编码者、测试者和实施者就我一个人,而我上面有项目经理、销售、部门经理、副总,一有问题,四个经理就在一旁看结果,呵呵,压的人喘不过气来。
我也很气愤这个鬼公司,老板小气的要死,实施时连个笔记本都没有,而且前一段时间说为了实施方便才刚刚搞了一个移动硬盘,这才把我的老式的MP3(U盘)才换下来。所有给客户的演示的第一步骤就是搬机器,最后一个步骤也是搬机器。唉,这么诡异的公司!!!!!!!!!!!!!!!
现在客户系统要上线,说不允许出现BUG,我没有敢承诺,所以我也不说话,所有上面的领导都告诉我,不允许出现错误,你说我应该怎么说,我也没有说,只是和最小的头说:我尽量吧,错应该不是错,以后就是布丁了。
果然,正式上线的系统出现错误了,果然领导生气了,果然领导给我委派了一个测试人员(普通员工临时调配),果然我想离开这个诡异的公司。果然开源代码的推广又一步的延迟.........
不过,我觉得我还是很自信,因为我已经尽了自己的最大努力,还有积累了很多的软件工程的经验,还有快速开发的经验。
呵呵,出去混又何妨,方正我已经有了项目经理证,方正也实施了这个近百万的项目了。还是一个人执政,呵呵,和尚养大了,又觉得庙门小了。
已经有很长时间没有写日记了,公司的活太累了,所以没有清闲的时间和清静的心情来写BLOG。
我现在还深学陷入到开源代码的实现当中,我感觉不到开源代码将对以后的生活带来什么实质的影响,可能就是能够加快软件生产的效率而已,在IT界,开源代码的商业模式有过很多的探讨,这也证明了开源代码的魅力所在。因为她很深,所以以传统的专业精神是很难很快的了解开源代码。因为研究所化费的代价很大,所以她的存在价值就越来越高。
从很多的资料和个人的体验当中,我深深感觉到开源代码的盈利就是服务,而这个服务应该是多元化、多层面的服务体系,这个就好象是一个宗教一样,像是道教,人之初,性本善,开源代码的开源之初总是最好的,以后可能会鱼龙混杂,现在已经有这种迹象了。
从理论上进行分析,以后对开源代码进行管理的企业将是一个可以盈利的企业,对开源代码提供规则的将也是商家,在一定实践基础上对开源代码进行分级,将是另外一个视角看开源代码的方式,这个对开源代码的成长起辅助作用。
开源代码对软件的生产将提供最大的技术支持,这只是给有心人的。
开源代码也将指导企业应用的先进化生产,风险和效率将同时存在。将来对开源代码这种生产力的风险减低和效率提高的服务型企业将是开源代码的最大受益者。
我现在在拼命的研究AJAX技术,感觉用户体验是有了,但是又增加了写程序的能力,页面和实际业务不能够完全分离,不知道这个东东能生存多久。AJAX的出生和用户对“点击->返回”的上网体验都是不久的事,哪个将取得领导地位,还拭目以待。