Java开发人员的十大戒律

2010-08-28 10:51:27来源:西部e网作者:

10 Commandments for Java Developers
By Aleksey Shevchenko

Go to page: 1  2  Next  

There are many standards and best practices for Java Developers out there. This article outlines ten most basic rules that every developer must adhere to and the disastrous outcomes that can follow if these rules are not followed.

1. Add comments to your code. – Everybody knows this, but somehow forgets to follow it. How many times have you "forgotten" to add comments? It is true that the comments do not literally contribute to the functionality of a program. But time and time again you return to the code that you wrote two weeks ago and, for the life of you, you cannot remember what it does! You are lucky if this uncommented code is actually yours. In those cases something may spark your memory. Unfortunately most of the time it is somebody else's, and many times the person is no longer with the company! There is a saying that goes "one hand washes the other." So let's be considerate to one another (and ourselves) and add comments to your code.

2. Do not complicate things. – I have done it before and I am sure all of you have. Developers tend to come up with complicated solutions for the simplest problems. We introduce EJBs into applications that have five users. We implement frameworks that an application just does not need. We add property files, object-oriented solutions, and threads to application that do not require such things. Why do we do it? Some of us just do not know any better, but some of us do it on purpose to learn something new, to make it interesting for ourselves. For those who do not know any better, I recommend reaching out to the more experienced programmers for advice. And to those of us that are willing to complicate the design of an application for personal gains, I suggest being more professional.

3. Keep in Mind – "Less is more" is not always better. – Code efficiency is a great thing, but in many situations writing less lines of code does not improve the efficiency of that code. Let me give you a "simple" example:

if(newStatusCode.equals("SD") && (sellOffDate == null || 
todayDate.compareTo(sellOffDate)<0 || (lastUsedDate != null && 
todayDate.compareTo(lastUsedDate)>0)) || 
(newStatusCode.equals("OBS") && (OBSDate == null || 
todayDate.compareTo(OBSDate)<0))){
		newStatusCode = "NYP";
}

How easy is it to figure out what this "if" condition is doing? Now imagine that whoever wrote this code, did not follow rule number 1 – Add comments to your code.

Wouldn't it be much easier if we could separate this condition into two separate if statements? Now, consider this revised code:

if(newStatusCode.equals("SD") && (sellOffDate == null || 
todayDate.compareTo(sellOffDate)<0 || (lastUsedDate != null && 
todayDate.compareTo(lastUsedDate)>0))){
		newStatusCode = "NYP";
}else 
if(newStatusCode.equals("OBS") && (OBSDate == null || 
todayDate.compareTo(OBSDate)<0))
{
		newStatusCode = "NYP";
}

Isn't it much more readable? Yes, we have repeating statements. Yes, we have one extra "IF" and two extra curly braces, but the code is much more readable and understandable!

4. No hard coding please. – Developers often forget or omit this rule on purpose because we are, as usual, crunched for time. But maybe if we had followed this rule, we would not have ended up in the situation that we are in. How long does it take to write one extra line of code that defines a static final variable?

Here is an example:

public class A {
	
		public static final String S_CONSTANT_ABC = "ABC";
	
		public boolean methodA(String sParam1){
			
			if (A.S_CONSTANT_ABC.equalsIgnoreCase(sParam1)){
				return true;
			}		
			return false;
		}
}

Now every time we need to compare literal "ABC" with some variable, we can reference A.S_CONSTANT_ABC instead of remembering what the actual code is. It is also much easier to modify this constant in one place rather then looking for it though out all of the code.

5. Do not invent your own frameworks. – There are literally thousands of frameworks out there and most of them are open-source. Many of these frameworks are superb solutions that have been used in thousands of applications. We need to keep up to date with the new frameworks, at least superficially. One of the best and most obvious examples of a superb widely used framework is Struts. This open source web framework is a perfect candidate to be used in web-based applications. Please do not come up with your own version of Struts, you will die trying. But you must remember rule number 3 – Do not complicate things. If the application that you are developing has 3 screens – please, do not use Struts, there isn't much "controlling" required for such an application.

6. Say no to Print lines and String Concatenations. – I know that for debugging purposes, developers like to add System.out.println everywhere we see fit. And we say to ourselves that we will delete these later. But we often forget to delete these lines of code or we do not want to delete them. We use System.out.println to test, why would we be touching the code after we have tested it? We might remove a line of code that we actually need! Just so that you do not underestimate the damage of System.out.println, consider the following code:

public class BadCode {
	public static void calculationWithPrint(){
		double someValue = 0D;
		for (int i = 0; i < 10000; i++) {
			System.out.println(someValue = someValue + i);
		}	
	}
	public static void calculationWithOutPrint(){

			double someValue = 0D;
			for (int i = 0; i < 10000; i++) {
				someValue = someValue + i;
			}
		
	}
	public static void main(String [] n) {
		BadCode.calculationWithPrint();
		BadCode.calculationWithOutPrint();
	}
}

In the figure below, you can observe that method calculationWithOutPrint() takes 0.001204 seconds to run. In comparison, it takes a staggering 10.52 seconds to run the calculationWithPrint() method.

(If you would like to know how to produce a table like this, please read my article entitled "Java Profiling with WSAD" Java Profiling with WSAD )

The best way to avoid such CPU waste is to introduce a wrapper method that looks something like this:

public class BadCode {
	
		public static final int DEBUG_MODE = 1;
		public static final int PRODUCTION_MODE = 2;
	
	public static void calculationWithPrint(int logMode){	
		double someValue = 0D;
		for (int i = 0; i < 10000; i++) {
			someValue = someValue + i;
			myPrintMethod(logMode, someValue);
		}
	}
			
	public static void myPrintMethod(int logMode, double value) {
		if (logMode > BadCode.DEBUG_MODE) {	return; }
		System.out.println(value);	
	}
	public static void main(String [] n) {
		BadCode.calculationWithPrint(BadCode.PRODUCTION_MODE);
		}
}

String concatenation is another CPU waster. Consider example below:

public static void concatenateStrings(String startingString) {
		for (int i = 0; i < 20; i++) {
			startingString = startingString + startingString;
		}
	}
	
	public static void concatenateStringsUsingStringBuffer(
String startingString) {
		StringBuffer sb = new StringBuffer();
		sb.append(startingString);
			for (int i = 0; i < 20; i++) {
				sb.append(sb.toString());
			}
}

In the following figure you can see that the method that uses StringBuffer takes .01 seconds to execute where as the methods that use string concatenation takes .08 seconds to execute. The choice is obvious.

7. Pay attention to the GUI. – No matter how absurd it sounds; I repeatedly observe that GUI is as important to the business clients as functionality and performance. The GUI is an essential part of a successful application. Very often IT management tends to overlook the importance of GUI. Many organizations save money by not hiring web designers who have experience in design of "user-friendly" applications. Java developers have to rely on their own HTML skills and their limited knowledge in this area. I have seen too many applications that are "computer friendly" rather then "user friendly". Very rarely I have seen developers that are proficient in both software development and GUI development. If you are this unlucky Java developer who has been assigned to create an application interface, you should follow these three rules:

  1. Do not reinvent the wheel. Look for existing applications that have similar interface requirements.
  2. Create a prototype first. This is a very important step. The clients like to see what they are going to get. It is better for you also because you are going to get their input before you go all out and create an application interface that will leave the clients cold.
  3. Put the user's hat on. In other words, inspect the application requirements from the user's perspective. For example, a summary screen can be created with paging and without. As a software developer, it might be temping for you to omit paging from the application because it is so much less complicated. But, from the client's perspective, it might not be the best solution because the summary results can hold hundreds of rows of data.

8. Always Prepare Document Requirements. – Every business requirement must be documented. This could be true in some fairy tale, but it is far from that in the real world. No matter how time-pressed your development is, no matter how tight the deadlines, you must always make sure that every business requirement is documented.

9. Unit-test. Unit-test. Unit-test. – I am not going to go into any details as to what is the best way to unit-test your code. I am just going to say that that it must be done. This is the most basic rule of programming. This is one rule that, above all, cannot be omitted. It would be great if your fellow developer could create and execute a test plan for your code, but if that is not possible, you must do it yourself. When creating a unit test plan, follow these basic rules:

  1. Write the unit test before writing code for class it tests.
  2. Capture code comments in unit tests.
  3. Test all the public methods that perform an "interesting" function (that is, not getters and setters, unless they do their getting and setting in some unique way).

10. Remember – quality, not quantity. - Do not stay late (when you do not have to). I understand that sometimes production problems, urgent deadlines, and unexpected events might prevent us from leaving work on time. But, managers do not appreciate and reward their employees because they stay late on regular basis, they appreciate them because they do quality work. If you follow the rules that I outline above, you will find yourself producing less buggy and more maintainable code. That is the most important part of your job.

    Conclusion

    In this article I covered ten critical rules for Java Programmers. It is not merely important to know these rules, it is also important to follow them. Hopefully, these rules will help all of us become better programmers and professionals.

    About the Author

    Aleksey Shevchenko has been working with object-oriented languages for over seven years. He is now implementing enterprise IT solutions for Wall Street and the manufacturing and publishing industries.

     

    Java开发人员的十大戒律

     
     
    Java开发者来说,有许多的标准和最佳实践。本文列举了每一个开发人员必须遵从的十大基本法则;如果有了可以遵从的规则而不遵从,那么将导致的是十分悲惨的结局。
     
    1.    在你的代码里加入注释
    每个人都知道这点,但不知何故忘记了遵守。算一算有多少次你“忘记”了添加注释?这是事实:注释对程序在功能上没有实质的贡献。但是,你需要一次又一次的回到你两个礼拜之前写的代码上来,可能一辈子都是这样,你一定记不住这些代码为什么会这样。如果这些代码是你的,你还比较的幸运。因为它有可能让你回忆起。但是不幸的是,很多时间,这些代码是别人的,而且很有可能他已经离开了公司。
     
    2.    不要让事情复杂化
    我以前就这么干过,而且我相信所有的人都这么干过。开发人员常常为一个简单的问题而提出一个解决方案。我们为仅仅只有5个用户的应用而引入EJBs。我们为一个应用使用框架而它根本不需要。我们加入属性文件,面向对象的解决方案,和线程到应用中,但是它根本不需要这些。为什么我们这样做?我们中的一些人是因为不知道怎么做更好,但是还有一些人这样做的目的是为了学习新的知识,从而使得这个应用对于我们自己来说做得比较有趣。
     
    3.    牢牢记住——“少即是多(less is more)”并不永远是好的
    代码的效率是一伟大的事情,但是在很多情况下,写更少的代码行并不能提高该代码的效率。请让我向你展示一个简单的例子。
    if(newStatusCode.equals("SD") && (sellOffDate == null || 
    todayDate.compareTo(sellOffDate)<0 || (lastUsedDate != null && 
    todayDate.compareTo(lastUsedDate)>0)) || 
    (newStatusCode.equals("OBS") && (OBSDate == null || 
    todayDate.compareTo(OBSDate)<0))){
                            newStatusCode = "NYP";
    }
    我想问一句:说出上面的那段代码的if条件想干什么容易吗?现在,我们再来假设无论是谁写出这段代码,而没有遵从第一条规则——在你的代码里加入注释。
    如果我们把这个条件分到两个独立的if陈述句中,难道不是更简单一些吗?现在,考虑下面的修正代码:
    if(newStatusCode.equals("SD") && (sellOffDate == null || 
    todayDate.compareTo(sellOffDate)<0 || (lastUsedDate != null && 
    todayDate.compareTo(lastUsedDate)>0))){
                            newStatusCode = "NYP";
    }else 
    if(newStatusCode.equals("OBS") && (OBSDate == null || 
    todayDate.compareTo(OBSDate)<0))
    {
                            newStatusCode = "NYP";
    }
    难道它不是有了更好的可读性?是的,我们重复了陈述条件。是的,我们多出了一个多余的“IF”和两对多余的括弧。但是代码有了更好的可读性和可理解性。
     
    4.    请不要有硬代码
    开发人员常常有意识的忘记或者忽视这条规则,原因是我们,和一般时候一样,在赶时间。如果我们遵从这条规则,我们可能会赶不上进度。我们可能不能结束我们的当前状态。但是写一条额外的定义静态常量的代码行又能花费我们多少时间呢?
    这里有一个例子。
                   public class A {
                   
                                   public static final String S_CONSTANT_ABC = "ABC";
                   
                                   public boolean methodA(String sParam1){
                                                  if(A.S_CONSTANT_ABC.equalsIgnoreCase(sParam1)){
                                                                 return true;
                                                  }                             
                                                  return false;
                                   }
                   }
    现在,每一次我们需要和某一些变量比较字符串“ABC”的时候,我们只需要引用S_CONSTANT_ABC而不是记住实际的代码是什么。它还有一个好处是:更加容易在一个地方修改常量,而不是在所有的代码中寻找这个代码。
     
    5.    不要发明你自己的frameworks
    已经推出了几千种frameworks,而且它们中的大多数是开源的。这些frameworks中间有很多是极好的解决方案,被应用到成千上万的应用中。你们需要跟上这些新frameworks的步伐,最起码是肤浅的。在这些极好的、应用广泛的frameworks中间,一个最好的、最直接的例子是Struts。在你所能想象到的frameworks中,这个开源的web frameworks对于基于web的应用是一个完美的候选者。但是你必须记住第二条规则——不要让事情复杂化。如果你开发的应用只有三个页面—请,不要使用Struts,对于这样一个应用,没有什么“控制”请求的。
     
    6.    不要打印行和字符串相加
    我知道,为了调试的目的,开发人员喜欢在每一个我们认为适合的地方添加System.out.println,而且我们会对我们自己说,会在以后删掉这些代码的。但是我们常常忘掉删去这些代码行,或者我们根本就不想删掉它们。我们使用System.out.println来测试,当我们测试完成以后,为什么我们还能接触到它们呢?我们可能删掉一行我们实际需要的代码,仅仅是因为你低估了System.out.println所带来的伤害,考虑下面的代码:
    public class BadCode {
     public static void calculationWithPrint(){
          double someValue = 0D;
          for (int i = 0; i < 10000; i++) {
               System.out.println(someValue = someValue + i);
          }   
     }
     public static void calculationWithOutPrint(){
     
               double someValue = 0D;
               for (int i = 0; i < 10000; i++) {
                    someValue = someValue + i;
               }
         
     }
     public static void main(String [] n) {
          BadCode.calculationWithPrint();
          BadCode.calculationWithOutPrint();
     }
    }
    在下面的表格中,你能够看到calculationWithOutPrint()方法的运行花了0.001204秒。相比较而言,运行calculationWithPrint()方法花了令人惊讶的10.52秒。
    \
    (如果你不知道怎么得到一个像这样的表格,请参阅我的文章“Java Profiling with WSAD Java Profiling with WSAD
    避免这样一个CPU浪费的最好方法是引入一个包装器方法,就象下面这样
    public class BadCode {
                   
                                   public static final int DEBUG_MODE = 1;
                                   public static final int PRODUCTION_MODE = 2;
                   
                   public static void calculationWithPrint(int logMode){           
                                   double someValue = 0D;
                                   for (int i = 0; i < 10000; i++) {
                                                  someValue = someValue + i;
                                                  myPrintMethod(logMode, someValue);
                                   }
                   }
                                                  
                   public static void myPrintMethod(int logMode, double value) {
                                   if (logMode > BadCode.DEBUG_MODE) {             return; }
                                   System.out.println(value);     
                   }
                   public static void main(String [] n) {
                                   BadCode.calculationWithPrint(BadCode.PRODUCTION_MODE);
                                   }
    }
    在下面的图中,你将看到,使用了StringBuffer的那个方法只花了0.01秒来执行,而那个使用了字符串相加的方法却花了0.08秒来运行。选择是显而易见的。
    \
     
    7.   关注GUI
    不管这听起来有多么可笑,我都要再三地说明:GUI对于商业客户来说和功能和性能一样重要。GUI是一个成功的系统的必要的一部分。(但是),IT杂志常常倾向于忽视GUI的重要性。很多机构为了省钱而不雇用那些在设计“用户友好”GUI方面有丰富经验的设计人员。Java开发人员不得不依赖他们自己的HTML知识,但是他们在这方面的知识十分有限。我看到过很多这样的应用:它们是“计算机友好”,而不是“用户友好”我很少很少能看到有开发人员既精通软件开发,又精通GUI开发。如果你是那个不幸的开发人员,被分配去开发用户接口,你应该遵从以下的三条原则:
    一、不要重复发明轮子。寻找有相似用户接口需求的已经存在的系统。
    二、首先创建一个原型。这是非常重要的步骤。客户喜欢看看他们将要得到什么。这对你来说也是很好的,因为在你全力以赴而做出一个将要使用户生气的用户接口之前,你就得到了它们的反馈。
    三、戴用户的帽子。换一句话说,站在用户的视角检查应用的需求。例如,一个总结页面到底要不要分页。作为一个软件开发者,你倾向于在一个系统中忽视分页,因为这样使得你有比较少的开发复杂性。但是,这对于从一个用户的视角来说却不是最好的解决方案,因为小结的数据将会有成百上千个数据行。
     
    8.   永远准备文档化的需求
    每一个业务需求都必须文档化。这可能在一些童话故事里才能成真,但是在现实世界却不可能。不管时间对于你的开发来说是多么紧迫,也不管交付日期马上就要到来,你永远都必须清楚,每一个业务需求是文档化的。
     
    9.   单元测试、单元测试、单元测试
    我将不会深入地讨论哪些什么是把你的代码进行单元测试的最佳方法的细节问题。我将要说的是单元测试必须要做。这是编程的最基本的法则。这是上面所有法则中最不能被忽略的一个。如果你的同事能为你的代码创建和测试单元测试,这是最好不过的事。但是如果没有人为你做这些事,那么你就必须自己做。在创建你的单元测试计划的时候,遵从下面的这些规则:
    一、在写代码之前就写单元测试用例。
    二、在单元测试里写注释。
    三、测试一切执行“interesting”功能的公有方法(“interesting”的意思是非setters或getters方法,除非它们通过一种特殊的方式执行set和get方法)。
     
    10.             记住—质量,而不是数量。
    不要在办公室里呆得太晚(当你不必呆的太晚的时候)。我理解有时,产品的问题、紧迫的最终期限、意想不到的事件都会阻止我们按时下班。但是,在正常情况下,经理是不会赏识和奖赏那些下班太晚的员工的,他赏识他们是因为他们所做产品的质量。如果你遵从了我上面给出的那些规则,你将会发现你的代码更加少的bug,更加多的可维护性。而这才是你的工作的最重要的部分。
     
    总结
    在这篇文章里,我给出了针对Java开发人员的十个重要的规则。重要的不仅仅是知道这些规则,在编码的过程中遵从这些规则更为重要。希望这些规则能够帮助我们成为更好的编程人员和专业人员。
     
    关于作者
    Aleksey Shevchenko在面向对象方面的编程有着七年以上的经验。他现在在从事华尔街、制造和出版工业方面的IT解决方案的工作。
    关键词:Java

    赞助商链接: