THE Elements OF JAVA Style


1. General Principles

 

1.      Original coding style을 고수 하라.

 

2.      Simplicity : class method는 간결히 작성 하라

Clarity : class, interface, method, variable 그리고 object는 그 목적을 확실히 하고 작성 하라.

Completeness : documentation을 확실히 하라

Consistency : 일관성 있게 만들고 적용하라

Robustness : error exception에 대한 처리를 확실히 하라

 

3.      처음부터 이와 같은 모든 Rule적용하여 작성하라

 

4.      표준을 벋어나는 어떠한 예외사항에 대해서도 그 이유를 document 하라

 

 

2. Formatting Conventions

 

5.      가독성을 위해 들여쓰기를 한다. 이때 자바 개발 환경에 영향을 입지 않기 위해서 tab 키를 사용하지 말고 space를 사용 한다. 들여쓰기는 2공백(내 생각으로는 4공백)이 일반적이다. 만약 팀을 이루어서 프로그래밍을 한다면 특히 개인적인 들여쓰기 Rule을 인정해서는 안 된다.

 

6.      코딩 중 긴 line은 여러 line으로 나누어 써라.

)  double length = Math.sqrt(Math.pow(x, 2.0),

                              Math.pow(y, 2.0)) ;

)  boolean equals(Object obj) {

         return this == obj

                || (this.obj instanceof MyClass

                    && this.field == obj.field) ;

     }

 

7.      적당한 띄어쓰기를 사용하라

) for(){                                           // 칸 띄어쓰기

      

   }

) void handleMessage(Message message) {               // 줄 띄어쓰기

 

        DataInput content = message.getDataInput() ;

        int messageType = content.readInt() ;

 

        switch (messageType) {

 

            case WARNING :

                do some stuff here

                break ;

 

case ERROR :

                do some stuff here

                break ;

 

default :

                do some stuff here

                break ;

         }

     }

 

8.      hard tab을 사용하지 말라 (5번 원칙과 비슷)

 

 

3. Naming Conventions

 

9.      class, variable, method, constant, interface등의 Naming시에 의미 있는 이름을 사용하라

 

10.    해당 domain친숙한 이름을 사용하라

 

11.    Naming에 있어서 그 목적을 잘 설명할 수 있게 의미 있는 이름을 사용하되 너무 지나치게 길지 않도록 유의 하라.

 

12.    Full Name을 사용하라. 생략된 이름은 그 뜻이 모호해 질 수 있다

 

13.    합성어의 각 첫 글자는 대문자로 나타내라. , 상수(constant)는 전체를 대문자로 나타내며, method, variable, parameter의 최초 시작 문자는 소문자로 한다.

 

14.    비록 Java compiler가 대소문자를 구분하지만 단지 대소문자만 다르게 해서 구분하는 Naming은 사용하지 말라.

 

Package Names

15.    패키지 이름의 root 부분으로 당신이 속한 조직의 Internet domain의 역순으로 소문자를 사용하여 Naming 하라.

) kr.co.penta.   com.sun.  

 

16.    패키지의 이름은 의미 있는 소문자의 생략형을 사용할 수 있다.

) java.io    java.net  

 

17.    이전 패키지와 binary와 그 행위가 호환되지 않을 경우에 새로운 패키지를 지정한다. 이때 새로운 패키지를 지정하는 방법 중 아래 예제와 같이 사용하여 지정 할 수도 있다.

) com.roguewave.server.v1

       com.roguewave.server.v2

 

Type Names

18.    class interface의 이름의 첫 글자 variable와 쉽게 구분할 수 있게 하기 위해서 대문자를 사용한다.

 

19.    class 이름은 명사를 사용한다.

 

20.    attributes, static services 또는 constants를 대표하는 class의 이름은 복수형으로 한다.

) java.awt.font.LineMetrics, java.beans.Beans, java.sql.Types

 

21.    interface의 이름은 명사 또는 형용사형으로 구성 한다.

) ActionListener, Runnable

 

Method Names

22.    메소드 이름은 모두 소문자를 원칙으로 하고, 중간의 구분되는 단어의 첫 글자만 대문자로 표기 한다.

) public void flush() { }

   public Image getScaledInstance() { }

 

23.    메소드의 이름은 일반적으로 동사를 사용한다.

 

24.    속성(property)을 참조하는 메소드의 이름은 JavaBeans Naming 규칙을 따른다.

) boolean값을 반환하는 메소드 :

boolean isValid() {

    return this.isValid ;

}

값을 얻을 때는 get, 설정할 때는 set을 사용 :

    String getName() {

        return this.name ;

    }

    void setName(String name) {

        this.name = name ;

    }

 

Variable Names

25.    22번 규칙과 동일

 

26.    명사를 이용하여 Naming한다.

27.    배열 또는 Vector와 같은 복수형 참조 변수는 복수로 표기한다.

) Customer[] customers = new Customer[MAX_CUSTOMERS] ;

Vector orderItems = new Vector() ;

 

28.    중요하지 않은 변수의 이름의 대표를 설정하여 사용할 수 있다

) Character                      c, d, e

Coordinate                     x, y, z

Exception                       e

Graphics                       g

Object              o

Stream                          in, out, inOut

String              s

 

29.    지역 변수(local variable) field varible를 구분하기 위해서 this를 사용한다.

) public class AtomicAdder {

 

        private int count ;

 

        public AtomicAdder(int count) {

            this.count = count ;

        }

    }

 

30.    생성자(constructor) 또는 set 메소드에서 사용하는 파라미터는 필드(field)변수와 동일한 이름을 사용한다.

 

Constant Names

31.    상수(Constant)는 모든 문자를 대문자로 표기 한다.

) public static final byte MAX_VALUE = 255 ;

 

 

4. Documentation Conventions

 

32.    당신의 code에 익숙하지 않은 누군가가 그것을 사용하거나 유지보수 해야 한다고 생각하고 Document 하라

 

33.    When the code and the comments disagree, both are probably wrong

- Norm Schryer, Bell Labs

code comment를 항상 일치시켜라

34.    comment는 실제적인 말을 사용하고 필요 없는 말은 생략하라.

 

Comment Types

Documentation comment : /** 으로 시작하고 */ 으로 끝난다.

Standard or C-style comment : /* 으로 시작하고 */ 으로 끝난다.

One-line or End-line comment : // 으로 시작 하는 단 한 줄의 comment

 

35.    Javadoc 유틸리티는 모든 public classes, protected classes, inner classes, interfaces, constructors, methods fields의 바로 위의 단 하나의 documentation comment에 대해서 HTML형식의 문서를 산출해 주는 기능이 있다.

Documentation comment의 원래 목적은 서비스의 사용자(client)와 공급자(supplier)사이의 programming contract를 정의 하는 것이다.

 

36.    컴파일러로부터 임시 코드를 감추고자 할 때 소스 파일로부터 실제로 삭제하지 말고 standard comment를 사용 하라. standard comment documentation comment 와 혼동되지 않도록 이와 같은 용도로만 사용하라

 

37.    one-line comment implementation을 상세히 설명하기 위해서 사용한다. 이때 code 그 자체로 document 기능을 할 수 있는 것은 제외하고 단지 추가적인 정보가 필요한 것들만 comment 하도록 한다.

 

Documentation comments

38.    code를 완전히 작성하기 전에 프로그램 interface에 대한 documentation comment를 작성하라

 

39.    package 및 모든 class 멤버에 대한 documentation comment를 작성 하라

 

40.    Javadoc 유틸리티는 패키지에 대한 설명으로 package.html 파일을 이용한다. 이때 이 파일은 패키지가 존재하는 디렉토리와 같은 위치에 있어야 하며 <body> </body>태그 사이의 내용을 사용한다.

 

41.    Javadoc 유틸리티는 어플리케이션 또는 패키지 그룹에 대한 설명을 작성하기 위하여 overview comment file .html 을 사용할 수 있다. 이때 Javadocoption 을 사용하여 이 파일을 지정해 주어야 한다.

 

42.    documentation comment는 다음과 같은 형식에 따라서 작성 한다.

-          /** 으로 시작 한다.

-          다음 줄부터는 *로 시작하며, /**의 첫번째 *의 위치에 정렬한다.

-          위의 * 다음에는 공백 한 칸을 띄운다.

-          설명문과 Javadoc 태그를 구분하기 위해서 한 개의 공백 라인을 사용한다.

-          */으로 끝마친다.

         ) /**

* Descriptive text for this entity.

* @tag Descriptive text for this tag.

              */

 

43.    documentation comment내의 모든 keywords identifiers, constants 등을 <code></code> 태그로 mark-up 하라

) /**

* Allocates a <code>Flag</code> object

* representing the <code>value</code> argument.

*

*/

             public Flag(Boolean value) {}

 

44.    documentation comment내의 code<pre></pre> 태그로 mark-up 하라

)  /**

*

* The following example uses a

* <code>Class</code> object to print the class

* name of an object :

*

* <pre>

* void printClassName(Object o) {

*     System.out.println(The class of

*                       + o

*                       + is

*                       + o.getClass().getName()) ;

* }

* </pre>

*

*/

public final class Class { }

 

45.    식별자에 대한 {@link} 태그의 사용은 꼭 필요한 경우만 적당히 사용하라. 지나친 사용은 오히려 혼동을 야기할 수 있다. 사용 방법은 다음과 같다.

)  /**

* Allocates a <code>Flag</code> object

* representing the <code>value</code> argument.

* Use this form of constructor as an alternative

* to the {@link #Flag(String)} form.

*

*/

public Flag(Boolean value) { }

 

/**

* Allocates a <code>Flag</code> object

* representing the value <code>true</code> if

* the string argument is not <code>null</code>

* Use this form of constructor as an alternative

* to the {@link #Flag(boolean)} form.

*

*/

public Flag(String s) { }

 

46.    정해진 순서에 의해서 Javadoc 태그를 사용하라

1) class interface descriptions

/**

* Description

*

* @author

* @version

*

* @see

* @since

* @deprecated

*/

2) method descriptions

/**

* Description

*

* @param

* @return

* @exception

*

* @see

* @since

* @deprecated

*/

3) field descriptions

/**

* Description

*

* @see

* @since

* @deprecated

*/

 

47.    3인칭 화법으로 기술하라

 

48.    Javadoc documentation comment의 첫번째 문장 또는 문구를 summary description으로 사용하므로 이를 간결하고 명확하게 작성하여야 한다.

 

49.    액션이나 서비스에 대한 summary descriptions에서는 주어를 생략하라

 

50.    사물(thing)에 대한 설명에서는 주어와 동사를 생략하라

 

51.    Use this rather than the when referring to instance of the current class. (해당사항 없음)

 

52.    메소드나 생성자가 overload된 것이 아니라면 이름 뒤에 괄호를 사용하지 마라

 

53.    모든 클래스, 인터페이스, 메소드 및 필드에 summary description을 달아라

 

54.    모든 메소드는 파라미터, 예외(exception) return 값에 대한 documentation을 달아야 한다.

 

55.    중요한 클래스 또는 메소드는 간단한 예제를 이용하여 설명하라

 

56.    precondition, postcondition, invariant condition에 대해 documentation 하라.

-          precondition은 메소드의 시작부에서 method arguments가 받아들일 수 있는 값의 범위 등을 제한하는 것과 같은 조건이다

-          postcondition은 메소드의 실행이 성공적으로 완료된 후 결과값에 대한 조건 등을 말한다

-          invariant condition은 변하지 않는 조건, int vacationDays 0부터 25사이의 값 과 같은 조건을 말한다

 

57.    보완해야 할 사항이나 문제점에 대해서 documentation 하라. 가능하면 언제 해결될 수 있는지에 대해서도 기술 하라

 

58.    동기화된 block 또는 메소드에 대해 documentation 하라

 

Internal Comments

59.    다른 사람들의 이해를 돕기 위해서만 사용하라

 

60.    code가 무엇을 하는지 만을 설명하지 말고, 무엇을 왜 하는지에 대해서 documentation 하라

잘 작성된 code는 그 자체가 documentation이다. 따라서 무엇을 하는가 보다는 왜 하는가에 대한 설명을 기술 하도록 한다.

 

61.    지역 변수에 대한 설명을 간단히 기술하는 것을 제외 하고는 code의 명령어 line 마지막에 comment를 달지 마라. Code와 혼동 되기 쉽고, 또한 code를 수정할 경우 다음 line으로 넘어 갈 수 있다

 

62.    지역 변수를 간단히 설명하고자 할 경우는 동일한 line에 설명을 달라.

 

63.    해결되지 않은 문제를 comment 하기 위해 특별한 기호를 사용하여 기술하라. 이때 작성자 및 작성일자에 대한 정보를 포함 한다.

)  // :UNRESOLVED: 홍길동, 2001 3 7

    // This still does not handle the case where

    // the input overflows the internal buffers!!

while (everMoreInput) {}

64.    복잡한 제어문의 가독성을 위하여 end-line comment를 사용할 수 있다

) for (i) {

        for (j) {

            while () {

               

            } // end while

        } // end for j

    } // end i

 

65.    break문이 없는 case문의 마지막에 fall-through comment를 사용한다. 이 문장을 사용하지 않으면 실수로 break문을 누락 하였는지 그 의미가 모호해질 수 있기 때문이다.

 

66.    while 이나 for 와 같은 반복문에서 디자인상 아무런 행위를 하지 않는다면 다음과 같이 사용하라

)  // strip leading spaces

    while ((c = reader.read()) == SPACE) ;

    // Empty!

 

 

5. Programming Conventions

 

67.    superclass로서 활용되지 않는 간단한 class들은 final로 정의하라

 

68.    native type concrete type을 이용하여 새로운 concrete type을 만들어라. 특히 native type으로 구성된 것이 concrete type으로 구성된 것 보다 더욱 고립적(isolation)이고 안정적(stability)이다. concrete type은 그 밖의 다른 곳으로부터의 영향을 거의 받지 않으므로 application을 통해서 그 사용이 빈번한 경우 특히 중요하다

) 아래 예제는 기본자료형인 int, boolean형과 자바 native type Object, String, 그리고 자기 자신의 참조형인 BitSet형만을 사용한 concrete type 이다.

public final class BitSet {

              public BitSet() {}

              public BitSet(int) {}

              public void set(int) {}

              public void clear(int) {}

              public boolean get(int) {}

              public void and(BitSet) {}

              public void or(BitSet) {}

              public void xor(BitSet) {}

              public int hashCode() {}

              public int size() {}

              public boolean equals(Object) {}

              public Object clone() {}

       public String toString() {}

}

 

69.     가능한한 클래스 및 메소드의 크기를 작게 만들어라.

70.    superclass가 사용되는 어떠한 곳에서도 사용되어 질 수 있도록 subclass를 정의 하여야 한다.

일반적으로 클래스는 overriding을 통해서 그 조상 클래스의 기능을 변경하거나 제한 할 수 있기 때문에 항상 그 조상이 사용되는 곳에서 사용될 수 있는 것은 아니다. 이에 반해 subtype으로 구현한 클래스는 조상 클래스의 어떠한 기능도 overriding 하지 않고 단지 추가적인 기능만을 확장한 것이므로 동일한 속성 및 관계성을 유지한다.

새로이 파생된 클래스의 정보를 취급하기위해서 변경되어야 한다면 그것은 잘못된 디자인이다.

 

-          The Liskov Substitution Principle

기본 클래스의 참조를 사용하는 메소드는 그것으로부터 파생된 클래스가 무엇인지 모르더라도 사용할 수 있어야만 한다

: A라는 클래스가 B라는 클래스를 사용하는 경우, B subclass 중 어느것이 A에 적용 되더라도 A클래스는 정상적으로 동작 하여야 한다는 뜻.

-          The Open-Closed Principle

Software evtities(Classes, Modules, Functions)는 확장을 위해서는 열려 있어야 하지만, 그것에 대한 변경에 대해서는 닫혀 있어야 한다.

: A클래스가 B클래스의 subclass type에 따라서 그 처리를 하는 경우, B클래스의 새로운 subclass가 생기면 A클래스도 변경되어야만 한다. 이와 같은 오류를 막기위해서 A클래스는 B클래스의 subclass데 대해서 처리해 주는 것이 아니라, B클래스에게 c 처리를 요청하며, B클래스는 이를 처리하기위한 정의(: method)를 미리 선언 해 둔다. subclass들은 이를 자신에 맞게 확장하여 사용한다.

 

71.    모든 filedsprivate으로 선언하라. 그리고 그것에 대한 참조나 수정이 필요한 경우 객체 메소드를 이용하라.

 

72.    instanceof 를 사용하지 마라. 이것은 선택해야 할 object type의 집합이 변경될 때마다 수정이 필요하기 때문이다. 대신에 기본 클래스로부터 파생된 메소드 내에 object 자신이 처리해야 할 행위를 구현하는 방법으로 구현 하라.

 

 

Type Safety

73.    일반적인 목적으로 클래스를 사용할 경우에 그 객체를 java.lang.Object casting하는 것이 보다 안정적 이다.

) public class Queue {

        public void enqueue(Object object) {} ;

        public Object dequeue() {} ;

    }

    public class OrderQueue {

        private Queue queue ;

        public OrderQueue() {

            this.queue = new Queue() ;

        }

        public void enqueue(Order order) {

            this.queue.enqueue(order) ;

        }

        public Order dequeue() {

            return (Order) this.queue.dequeue() ;

        }

    }

 

74.    class들의 열거형을 encapsulation 하라.

) public class Color {

        private static int count = 0 ;

        public static final Color RED = new Color(count++) ;

        public static final Color GREEN = new Color(count++) ;

        public static final Color BLUE = new Color(count++) ;

        private int value ;

 

        private Color(int value) {

            this.value = value ;

        }

        public boolean equals(Color other) {

            return this.value == other.value ;

        }

        public static int Color.count() {

            return count ;

        }

    }

 

    Color aColor = color.RED ;

    If (anotherColor.equals(aColor)) {

       

    }

 

 

Statements and Expressions

75.    반복되는 중요한 표현식(expressions)은 메소드를 만들어서 사용하라

 

76.    모든 제어문에는 중괄호{}를 사용하라. 만약 그 문장 전체가 한 줄로 구성되며 가독성을 높이고자 할 경우만 예외로 하라.

) if (x >= 0)

        if (x > 0) positiveX() ;

    else // Oops! Actually matches most recent if

        negativeX() ;

 

    if (x >= 0) {

        if (x > 0) positiveX() ;

    }

    else {

        negativeX() ;  // This is what we really wanted!

    }

 

77.    괄호를 사용하여 연산자 우선 순위를 확실히 하라

78.    switch문의 case의 가장 마지막에는 항상 break문을 사용하라. default문에도 break문을 사용하라. 만약 break문을 사용하지 않으려면 fall-through문을 사용하라. (See rule #65)

 

79.    객체의 비교에 ==를 사용하지 말고 항상 equals()를 사용하도록 하라. 자바에서 != == 연산자는 객체의 값을 비교하는 것이 아니라 그 객체의 식별자 자체를 비교하는 연산자 이다.

참고) name.equals(Bob)이라는 표현식 보다는 Bob.equals(name)이라는 표현식이 더욱 바람직 하다. 왜냐하면 namenull일수 있기 때문이다.

 

 

Construction

80.    객체를 항상 유효한 상태(valid state)로 만들어라. 새로운 객체를 그렇게 만드는 것이 생성자 이다.

 

81.    생성자 안에서는 nonfinel method를 호출하지 말라. 왜냐하면 nonfinal 메소드는 subclass에서 override될 수 있으며, 이 메소드를 호출하는 경우 생성자는 invalid 상태에 있게 되기 때문이다.

 

82.    중복되는 code를 제거하고 생성자를 만들어라

) Class Account {

        String name ;

        double balance ;

        final static double DEFAULT_BALANCE = 0.0d ;

 

        Account(String name, double balance) {

            this.name = name ;

            this.balance = balance ;

        }

        Account(String name) {

            this.name = name ;

            this.balance = this.DEFAULT_BALANCE ;

        }

    }

 

Class Account {

        String name ;

        double balance ;

        final static double DEFAULT_BALANCE = 0.0d ;

 

        Account(String name, double balance) {

            this.name = name ;

            this.balance = balance ;

        }

        Account(String name) {

            this(name, DEFAULT_BALANCE) ;

        }

    }

Exception Handling

83.    프로그램 로직 에러와 같은 기대하지 않은 오류가 발생할 수 있는 경우 run-time exception을 사용하라

 

84.    일반적인 프로그램 연산 중에는 좀처럼 발생할 것 같지 않은 오류에 대해서도 exception을 처리 하라

 

85.    기대한 상태의 변화를 알려주는 코드를 반환하라. 그리하여 코드의 가독성과, 제어 흐름의 직관성을 높일 수 있다.

 

86.    모든 예외사항에 대한 정보를 간직하라. 결코 무시하지 마라.

 

87.    run-time 또는 error와 같은 예외 사항을 무시하지 마라. 그러면 debugging하기 어려워 진다. 특별히 예외처리를 할 것이 없다면 printStackTrace()라도 사용 하라.

 

88.    resource를 해지하기 위해서 finally 블록을 사용하라.

 

 

Assertions

89.    일반적으로 파라미터의 타당성을 조사하는 precondition과 반환할 값의 타당성을 체크하는 postcondition을 모두 사용하여 프로그래밍 하라. 기본 클래스의 메소드를 override한 파생된 클래스 메소드는 기본 클래스 메소드의 precondition postcondition 모두를 준수해야만 한다. 이렇게 하기 위해서 public method final로 만들고 그 body부분을 nonfinal protected method로 만든다. public 메소드에서는 precondition을 테스한 후에 적당한 nonfinal protected 메소드를 호출한다. 그 후에 public 메소드는 postcondition을 검사한다. 이와 같은 기본 클래스의 public 메소드를 override하고자 하는 하위 클래스들은 단지 nonfinal protected 메소드만을 override하여 구현할 수 있게 된다. 이와 같은 방법은 synchronized에도 적용될 수 있다.

 

90.    Assertion은 프로그래머가 code의 한 부분이 정확하게 처리하기 위해 true holding하는 Boolean 표현식 이다. Assertion은 기본 코딩에 대한 가설이 잘못되지 않았음을 확인시켜주는 코드로 사용된다. Assertion은 코드를 테스트 하기 위한 것이므로 배포 시에는 필요 없게 된다. 이때 이것을 제거하기 위해서 dead code elimination을 이용할 수 있다. dead code elimination은 자바 컴파일러가 도달할 수 없는 코드를 제거할 때 발생된다.

) class DeadCode {

        static final boolean FALSE = false ;

        public void example() {

            if (FALSE) {

                System.out.println(Never to be seen.) ;

            }

        }

    }

위 예에서 if문은 항상 false이므로 실행되지 않는다. 이와 같은 코드를 dead code라고 하며 이를 자바 컴파일러가 제거하는 것을 dead code elimination이라고 한다.

 

91.    로직 에러를 잡기위해 assertion을 사용하라

 

92.    precondition postcondition을 테스트하기 위해서 assertion을 사용하라

 

 

Concurrency

Concurrency는 둘 이상의 thread가 동시에 명령을 실행하고자 할 경우에 발생한다. Single processor system은 각 스레드를 교대로 실행하는 방법을 이용하여 concurrency를 지원하고, multiprocessor system은 각각의 processor가 별도의 스레드를 수행하는 병렬적 concurrency를 지원한다.

 

93.    적당한 곳에만 스레드를 사용하라. 예를 들어 아래의 경우와 같은 곳이다.

-          동시에 많은 이벤트를 처리해야 하는 경우

Ex) 인터넷 브라우저, 서버등

-          높은 수준의 대응력(responsiveness)을 제공해야 하는 경우

Ex) 어플리케이션이 다른 처리를 수행하고 있는 동안에도 사용자의 action에 대한 처리를 계속적으로 해 주어야 하는 경우

-          multiprocessor system인 경우

 

 

Synchronization

동기화(synchronization)는 공존하는 스레드 사이의 간섭이나 기대하지 않은 연산으로부터 보호하기위한 프로그래밍 기법이다. 동기화에는 mutual exclusioncondition synchronization이 있다.

Mutual exclusion은 잘 짜여진 최소의 실행모듈(action)을 그렇지 않은 실행모듈과 결합하여 새로운 최소 실행모듈로 만들어 그 순서를 정렬하여 구현하는 방식이고, condition synchronization은 프로그램이 조건을 만족할 때까지 스레드의 실행을 연기시키는 메커니즘 또는 프로세스를 말한다.

 

94.    꼭 필요한 경우에만 동기화 시켜라. 동기화는 프로그램 성능에 많은 영향을 끼친다.

 

95.    동기화 인터페이스를 제공하기위해서 synchronized wrapper를 사용하라. Synchronized wrapper는 원본 클래스와 동일한 인터페이스를 가지고 있으나 메소드가 synchronized된 것이다.

) public class Stack {

        public void push(Object o) {} ;

        public Object pop() {} ;

        public static Stack createSynchronizedStack() {

            return new SynchronizedStack() ;

        }

    }

 

    class SynchronizedStack extends Stack {

        public synchronized void push(Object o) {

            super.push(o) ;

        }

        public synchronized Object pop() {

            return super.pop() ;

        }

    }

 

96.    필요한 경우에만 메소드 전체를 동기화 하고 가급적이면 동기화 블록 기법을 사용하라

 

97.    자바에서는 객체참조와 long double을 제외한 모든 기본 자료형에 대한 읽기와 쓰기작업을 atomic으로 간주한다. 이와 같은 atomic형의 변수가 다른 변수를 참조하지 않는 이상 우리는 동기화(synchronization)를 피할 수 있다. 다음의 예는 각각 동기화가 필요한 경우와 필요하지 않는 경우의 예이다.

) // 동기화가 필요한 경우

public void synchronized setCenter(int x, int y) {

        this.x = x ;

        this.y = y ;

    }

 

    // 동기화가 필요하지 않는 경우

    public void setCenter(Point p) {

        this.point = (Point) p.clone() ;

    }

 

98.    꼭 필요한 경우가 아니라면 notifyAll() 메소드 대신에 notify() 메소드를 사용하라. notify() 메소드가 사용하기에 더욱 효과적이다.

 

99.    객체 초기화(initialization)에 대한 동기화 기법 적용시 double check pattern 기법을 사용하라. 이것은 메소드 전체를 동기화하는 것을 피할 수 있게 해준다.

) synchronized Log getLog() {

        if (this.log == null) {

            this.log = new Log() ;

        }

        return this.log ;

    }

    // 아래는 위에 대한 double check pattern 기법을 적용한 것이다.

    Log getLog() {

        If (this.log == null) {

            synchronized (this) {

                if (this.log == null) {

                    this.log = new Log() ;

                }

            }

        }

        return this.log ;

    }

Efficiency

100. 필요할 때까지 객체를 초기화 하지 말라.

 

101. 가급적 객체의 초기화를 최소화하라. 다음의 예를 참고하라

) Color getTextColor() {

        Color c = new Color() ;

        if (this.state < 2) {

            c = new Color() ;

        }

        return c ;

    }

    // 위와 같은 경우 아래와 같이 사용하라.

    Color getTextColor() {

        Color c = null ;

        if (this.state < 2) {

            c = new Color() ;

        } else {

            c = new Color() ;

        }

        return c ;

    }

 

102. 새로운 객체를 생성하여 사용하지 말고 객체를 다시 초기화하여 사용하거나 재사용하라.

103. 마지막까지 최적화(optimization)는 하지 마라. 최적화는 꼭 필요하다고 생각되는 순간에만 하는 것이 좋다. 이때 80-20 Rule(평균적으로 시스템 내의 20%의 코드가 80%의 자원(resource)을 사용한다는 규칙)을 기억하라. 최적화(optimization)를 하고자 하는 코드가 20%내에 존재한다고 확신하는 경우에만 시도하라.

 

 

6. Packaging Conventions

 

104. 공통적으로 사용되고, 변경되고 함께 배포되거나 상호 의존적인 type들을 동일한 패키지로 묶어라. 이 규칙은 아래의 몇가지 규칙을 포함한다.

-          The Common Reuse Principle : 패키지는 같이 사용되는 클래스들로 구성된다. 만약 패키지내의 하나의 클래스를 사용한다면 당신은 그것들 중 모든 패키지를 사용하는 것이다.

→ 보통 함께 사용되는 클래스나 인터페이스를 같은 패키지에 위치시켜라.

-          The Common Closure Principle : 패키지는 같은 부류의 변화에 대해서 폐쇄된 클래스들로 구성된다. 패키지에 영향을 주는 변화는 패키지내의 모든 클래스에 영향을 미친다.

    → 동일한 이유 때문에 동시에 변경될 클래스들을 하나의 패키지로 묶어라.

-          The Reuse/Release Equivalence Principle : 재사용(reuse)의 단위는 배포(release)의 단위 이다. 효과적인 재사용은 제어 시스템의 변경으로부터의 배포순서가 요구된다. 패키지는 재사용과 배포의 효과적인 단위이다.

    → 실제로 어플리케이션은 수천개의 클래스들로 구성되기 때문에 클래스 by 클래스로 관리하고 배포한다는 것은 매우 복잡하고 비효율적이다. 따라서 패키지를 이용하는 것이 좋다.

-          The Acyclic Dependencies Principle : 패키지 사이에는 순환적 의존성이 존재해서는 안된다.

    → 만약 두 패키지가 상호간에 직/간접적으로 의존성을 가지고 있다면 우리는 그 중 하나의 패키지를 독립적으로 배포할 수 없다. 왜냐하면 그 패키지는 또 다른 하나의 패키지에 영향을 미치기 때문이다. 순환적 의존성을 배제하기위해서 두 패키지를 하나의 패키지로 재 구성하거나 두 패키지가 상호 의존적이지 않도록 새로운 추상 패키지를 만드는 방법이 있다.

 

105. 패키지 내의 변하기 쉬운 클래스 및 인터페이스를 그렇지 않은 것들과 분리하라.

 

106. 변경하는 패키지에 의존적인 변경되기 어려운 패키지를 만들지 마라.

        The Stable Dependancies Principle : 패키지 사이의 의존성은 안전성이 증가하는 쪽으로 방향 지어진다. 패키지는 자신보다 더욱 안정적인 패키지에 의존해야만 한다.

 

107. 안전성(stability)을 최대화하기 위해서 추상화(abstraction)를 최대화 하라.

        The Stable Abstractions Principle : 패키지의 안전성은 그것의 추상화 레벨에 직접적으로 비례한다. 패키지가 추상적일수록 더욱 안정적인 경향이 있다. 패키지가 견고할수록 안전성은 더욱 없어지는 경향이 있다.

견고한 클래스로부터 추상적인 클래스와 인터페이스를 분리하여 안정적인 패키지와 그렇지 않은 패키지를 만들어라.

 

108. 좋은 디자인은 빠르게 안정화되어야 한고 그렇게 유지되어야 한다. 만약 시스템이 계속적으로 변경된다면 어떤 개발 관리자도 정확히 계획하고 설계하고 자원을 할당할 수 없다.

 

저작자 표시 비영리 동일 조건 변경 허락
신고

'programing > JAVA' 카테고리의 다른 글

JNDI를 이용한 DB 커넥션 얻기  (0) 2009.10.30
THE Elements OF java Style  (1) 2009.08.31
java & jsp 개발 팁  (0) 2009.08.19
JSP charset  (0) 2009.08.14
HTML A태그, IMG태그 추출  (1) 2009.06.22
HTML 태그제거 소스  (0) 2009.06.22
Posted by 대절님

댓글을 달아 주세요

  1. ㅁㅁㅁ 2009.09.08 09:33 신고  댓글주소  댓글쓰기 수정/삭제

    퍼갈께요~



티스토리 툴바