编码规范(摘抄自Expert One-on-One J2EE Design and Development)

本文强调了在大型J2EE项目中遵循统一编码规范的重要性,以确保团队合作和软件维护的效率。作者指出,许多J2EE示例应用存在代码质量问题,如Smart Ticket Demo。建议从Sun的Java编码规范开始,并考虑引入改进,但要保持与Java社区的普遍实践一致。文章还讨论了避免代码重复、使用final关键字、实现toString()方法、防御性编程和日志记录等实践。
摘要由CSDN通过智能技术生成

Coding Standards

J2EE projects tend to be big projects. Big projects require teamwork, and teamwork depends on consistent programming practices. We know that more effort is spent on software maintenance than initial development, so it's vital to ensure that applications are easy to work on. This makes good Java coding standards – as well as the practice of sound OO design principles – vital across J2EE projects. Coding standards are particularly important if we choose to use XP. Collective code ownership can only work if all code is written to the same standards, and there are no significant discrepancies in style within a team.

Why does a section on Java coding standards (albeit with a J2EE emphasis) belong in a book on J2EE? Because there's a danger in getting lost in the details of J2EE technology, and losing sight of good programming practice. This danger is shown by many J2EE sample applications, which contain sloppy code.

Sun are serious offenders in this respect. For example, the Smart Ticket Demo version 1.1 contains practically no comments, uses meaningless method parameter names such as u, p, zc and cc, and contains serious programming errors such as consistently failing to close JDBC connections correctly in the event of exceptions. Code that isn't good enough to go into a production application is definitely not good enough to serve as an example.

Perhaps the authors of such applications believe that omitting such "refinements" clarifies the architectural patterns they seek to illustrate. This is a mistake. J2EE is often used for large projects in which sloppy practices will wreak havoc. Furthermore, bringing code to production standard may expose inadequacies in the original, naïve implementation.

As with design principles, this is a huge area, so the following discussion is far from comprehensive. However, it tries to address issues that I've found to be of particular importance in practice. Again, there are necessarily matters of opinion, and the discussion is based on my opinions and practical experience.

Start from the Standard

Don't invent your own coding conventions or import those from other languages you've worked in. Java is a relatively simple language, offering only one way to do many things. In contrast, Java's predecessor C++ usually offered several. Partly for this reason, there's a greater degree of standardization in the way developers write in Java, which should be respected.

For example, you may be familiar with "Hungarian notation" or Smalltalk naming conventions. However, Hungarian Notation exists to solve problems (the proliferation of types in the Windows API) that don't exist in Java. A growing proportion of Java developers haven't worked in other languages, and will be baffled by code that imports naming conventions.

Start from Sun's Java coding conventions (available at http://java.sun.com/docs/codeconv/html/CodeConvTOC.doc.html). Introduce refinements and variations if you prefer, but don't stray too far from common Java practice. If you organization already has coding standards, work within them unless they are seriously non-standard or questionable. In that case, don't ignore them: initiate discussion on how to improve them.

Some other coding standards worth a look are:

It is, however, worth mentioning one common problem that results from adhering to standard Java practice. This concerns the convention of using the instance variable name as a parameter, and resolving ambiguity using this. This is often used in property setters. For example:

  private String name;

  public void setName (String name) {
      this.name = name;
  }

On the positive side, this is a common Java idiom, so it's widely understood. On the negative, it's very easy to forget to use this to distinguish between the two variables with the same name (the parameter will mask the instance variable). The following form of this method will compile:

  public void setName(String name) {
    name = name;
  }

As will this, which contains a typo in the name of the method parameter:

  public void setName(String nme) {
    name = name;

In both these cases (assuming that the instance variable name started off as null) mysterious null pointer exceptions will occur at runtime. In the first erroneous version, we've assigned the method parameter to itself, accomplishing nothing. In the second, we've assigned the instance variable to itself, leaving it null.

I don't advocate using the C++ convention of prefixing instance or member variables with m_ (for example, m_name), as it's ugly and inconsistent with other Java conventions (underscores are normally only used in constants in Java). However, I recommend the following three practices to avoid the likelihood of the two errors we've just seen:

  • Consider giving parameters a distinguishing name if ambiguity might be an issue. In the above case, the parameter could be called newName. This correctly reflects the purpose of the parameter, and avoids the problem we've seen.

  • Always use this when accessing instance variables, whether it's necessary to resolve ambiguity or not. This has the advantage of making explicit each method's dependence on instance data. This can be very useful when considering concurrency issues, for example.

  • Follow the convention that local variable names should be fairly short, while instance variables names are more verbose. For example, i should be a local variable; userInfo an instance variable. Usually, the instance variable name should be an interface or class name beginning with a lower case letter (for example SystemUserInfo systemUserInfo), while local variable names should convey their meaning in the current context (for example SystemUserInfo newUser).

  Note 

See http://www.beust.com/cedric/naming/index.html for arguments against standard Java convention in this area, from Cedric Beust, lead developer of the WebLogic EJB container.

Consistent file organization is important, as it enables all developers on a project to grasp a class's structure quickly. I use the following conventions, which supplement Sun's conventions:

  • Organize methods by function, not accessibility. For example, instead of putting public methods before private methods, put a private method in the same section of a class as the public methods that use it.

  • Delimit sections of code. For example, I delimit the following sections (in order):

  • Any static variables and methods. Note that main() methods shouldn't be an issue, as a class that does anything shouldn't include a main() method, and code should be tested using JUnit.

  • Instance variables. Some developers prefer to group each bean property holder with the related getter and setter method, but I think it is preferable to keep all instance variables together.

  • Constructors.

  • Implementations of interfaces (each its own section), along with the private implementation methods supporting them.

  • Public methods exposed by the class but not belonging to any implemented interface.

  • Protected abstract methods.

  • Protected methods intended for use by subclasses.

  • Implementation methods not related to any one previous group.

I use section delimiters like this:

  //---------------------------------------------------------------------
  // Implementation of interface MyInterface
  //---------------------------------------------------------------------

Please refer to the classes in the /framework/src directory in the download accompanying this book for examples of use of the layout and conventions described here. The com.interface21.beans.factory.support.AbstractBeanFactory class is one good example.

  Note 

If you need to be convinced of the need for coding standards, and have some time to spare, read http://www.mindprod.com/unmain.html.

Allocation of Responsibilities

Every class should have a clear responsibility. Code that doesn't fit should be refactored, usually into a helper class (inner classes are often a good way to do this in Java). If code at a different conceptual level will be reused by related objects, it may be promoted into a superclass. However, as we've seen, delegation to a helper is often preferable to concrete inheritance.

Applying this rule generally prevents class size blowout. Even with generous Javadoc and internal comments, any class longer than 500 lines of code is a candidate for refactoring, as it probably has too much responsibility. Such refactoring also promotes flexibility. If the helper class's functionality might need to be implemented differently in different situations, an interface can be used to decouple the original class from the helper (in the Strategy design pattern).

The same principle should be applied to methods:

  Important 

A method should have a single clear responsibility, and all operations should be at the same level of abstraction.

Where this is not the case, the method should be refactored. In practice, I find that this prevents methods becoming too long.

I don't use any hard and fast rules for method lengths. My comfort threshold is largely dictated by how much code I can see at once on screen (given that I normally devote only part of my screen to viewing code, and sometimes work on a laptop). This tends to be 30 to 40 lines (including internal implementation comments, but not Javadoc method comments). I find that methods longer than this can usually be refactored. Even if a unit of several individual tasks within a method is invoked only once, it's a good idea to extract them into a private method. By giving such methods appropriate names (there are no prizes for short method names!) code is made easier to read and self-documenting.

Avoid Code Duplication

It may seem an obvious point, but code duplication is deadly.

A simple example from the Java Pet Store 1.3 illustrates the point. One EJB implementation contains the following two methods:

  public void ejbCreate() {

    try {
        dao = CatalogDAOFactory.getDAO();
    } catch (CatalogDAOSysException se) {
        Debug.println("Exception getting dao " + se);
        throw new EJBException(se.getMessage());
    }
  }

and:

  public void ejbActivate() {

      try {
        dao = CatalogDAOFactory.getDAO();
      } catch (CatalogDAOSysException se) {
        throw new EJBException(se.getMessage());
     }
  }

This may seem trivial, but such code duplication leads to serious problems, such as:

  • Too much code. In this case, refactoring saves only one line, but in many cases the savings will be much greater.

  • Confusing readers as to the intent. As code duplication is illogical and easy to avoid, the reader is likely to give the developer the benefit of the doubt and assume that the two fragments are not identical, wasting time comparing them.

  • Inconsistent implementation. Even in this trivial example, one method logs the exception, while the other doesn't.

  • The ongoing need to update two pieces of code to modify what is really a single operation.

The following refactoring is simpler and much more maintainable:

 public void ejbCreate() {
     initializeDAO();
 }

 public void ejbActivate() {
    initializeDAO();
 }

 private void initializeDAO() {

    try {
        dao = CatalogDAOFactory.getDAO();
    } catch (CatalogDAOSysException se) {
        Debug.println("Exception getting dao " + se);
        throw new EJBException(se.getMessage());
    }
 }

Note that we've consolidated the code; we can make a single line change to improve it to use the new EJBException constructor in EJB 2.0 that takes a message along with a nested exception. We'll also include information about what we were trying to do:

  throw new EJBException("Error loading data access object: " +
                           se.getMessage(), se);

EJB 1.1 allowed EJBExceptions to contain nested exceptions, but it was impossible to construct an EJBException with both a message and a nested exception, forcing us to choose between including the nested exception or a meaningful message about what the EJB was trying to do when it caught the exception.

Avoid Literal Constants

  Important 

With the exception of the well-known distinguished values 0, null and "" (the empty string) do not use literal constants inside Java classes.

Consider the following example. A class that contains the following code as part of processing an order:

  if (balance > 10000) {
    throw new SpendingLimitExceededException (balance, 10000);
  }

Unfortunately, we often see this kind of code. However, it leads to many problems:

  • The code isn't self-documenting. Readers are forced to read the code to guess the meaning of the 10000.

  • The code is error prone. Readers will be forced to compare different literals to ensure that they're the same, and it's easy to mistype one of the multiple literals.

  • Changing the one logical "constant" will require multiple code changes.

It's better to use a constant. In Java, this means a static final instance variable. For e

 What is this book about? The results of using J2EE in practice are often disappointing: applications are often slow, unduly complex, and take too long to develop. Rod Johnson believes that the problem lies not in J2EE itself, but in that it is often used badly. Many J2EE publications advocate approaches that, while fine in theory, often fail in reality, or deliver no real business value. "Expert One-on-One: J2EE Design and Development" aims to demystify J2EE development. Using a practical focus, it shows how to use J2EE technologies to reduce, rather than increase, complexity. Rod draws on his experience of designing successful high-volume J2EE applications and salvaging failing projects, as well as intimate knowledge of the J2EE specifications, to offer a real-world, how-to guide on how you too can make J2EE work in practice. It will help you to solve common problems with J2EE and avoid the expensive mistakes often made in J2EE projects. It will guide you through the complexity of the J2EE services and APIs to enable you to build the simplest possible solution, on time and on budget. Rod takes a practical, pragmatic approach, questioning J2EE orthodoxy where it has failed to deliver results in practice and instead suggesting effective, proven approaches. What does this book cover? In this book, you will learn When to use a distributed architecture When and how to use EJB How to develop an efficient data access strategy How to design a clean and maintainable web interface How to design J2EE applications for performance Who is this book for? This book would be of value to most enterprise developers. Although some of the discussion (for example, on performance and scalability) would be most relevant to architects and lead developers, the practical focus would make it useful to anyone with some familiarity with J2EE. Because of the complete design-deployment coverage, a less advanced developer could work through the book along with a more introductory text, and successfully build and understand the sample application. This comprehensive coverage would also be useful to developers in smaller organisations, who might be called upon to fill several normally distinct roles. What is special about this book? Wondering what differentiates this book from others like it in the market? Take a look: It does not just discuss technology, but stress its practical application. The book is driven from the need to solve common tasks, rather than by the elements of J2EE. It discuss risks in J2EE development It takes the reader through the entire design, development and build process of a non-trivial application. This wouldn't be compressed into one or two chapters, like the Java Pet Store, but would be a realistic example comparable to the complexity of applications readers would need to build. At each point in the design, alternative choices would be discussed. This would be important both where there's a real problem with the obvious alternative, and where the obvious alternatives are perhaps equally valid. It emphasizes the use of OO design and design patterns in J2EE, without becoming a theoretical book ,高清文档 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值