티스토리 뷰

나의 공부방

[리뷰] 클린 코드(Clean Code) 핵심 요약

망나니개발자 2018. 7. 12. 00:05
반응형

 

2018년 대학생으로의 마지막 여름방학을 보내면서, 작성하는 코드의 Quality를 높이고자 친구와 함께 Robert C.Martin의 Clean Code라는 책을 집어들었습니다. 단순 독서로는 얻은 내용을 까먹을 뿐만 아니라, 적용하지 못할 것 같아서 유용한 내용 혹은 몰랐던 내용을 정리하였습니다!! 생각보다 간단한 내용들일수도 있지만 직접 코딩을 할 때는 놓쳤던 부분들이 많았던 것 같습니다ㅠㅅㅠ

 

 

1. 유효한 내용 정리

 


 

개인적으로 Interface를 활용한 다형성에서 많은 것들을 느꼈는데 이 부분은 따로 포스팅하도록 하겠습니다:)

 

    1. Flag 값을 Parameter로 주지 마라!
      함수는 최대한 작게 만들며 하나의 역할만을 하도록 만들어야 한다. 하지만 Flag값을 인수로 준다는 것은 Flag 검사도 하고, 다른 역할도 한다는 의미이므로 함수가 한꺼번에 여러가지를 처리함을 이미 암시하고 있다.


    2. 데이터 전달 시 인스턴스변수를 활용하라!
      함수의 인수를 통해 데이터를 전달하는 것은 코드를 읽는이에게 복잡함을 줄 수 있다. 다음 함수로 데이터를 전달하는 경우에는 Parameter로 넘기지 말고 Instance 변수를 활용하면 코드가 깔금해진다.

      public class TestClass {
              
      	private StringBuffer buffer;
      
      	public void test1() {
              this.buffer = new StringBuffer();
      	}
      
      	public void test2() {
              buffer.append("Parameter로 넘기지 말고 Instance 변수를 활용한다!");
      	}
      }

       

       

    3. hueristic하게 잘 알려진 법칙인 디미터 법칙을 적용하라!
      모듈은 자신이 조작하는 객체의 속사정을 몰라야 한다는 것이다. 예를 들어 아래의 test1과 같은 코드는 조작하는 객체의 속사정을 몰라야하는데 FileManager라는 Singleton 형식의 Class의 Option Class의 absolutePath를 구하고 있는데 이러한 test1과 같은 메소드는 test2로 고쳐주는 것이 좋다.(아래에서 사용하는 클래스들은 임의로 작성한 클래스이다.)

      public class TestClass {
              
          final String outputDir;
      
      	public void test1() {
              outputDir = FileManager.getInstance().getOptions().getModule().getAbsolutePath();
      	}
      
      	public void test2() {
              Options options = FileManager.getInstance().getOptions();
              Module module = options.getModule();
              outputDir = module.getAbsolutePath();
      	}
      }
       



    4. null을 반환하지 말아라!
      우리는 흔히 null을 반환하는 습관을 가지고 있는데, 이것은 null을 검사하는 코드가 많아지는 상황을 초래할 수 있으며, 이것은 일거리를 늘릴 분만 아니라 문제를 유발할 수 있다. Employee의 List를 요구하는 getEmployees()라는 함수는 null을 반환할 필요가 없이 new List를 선언하면 null을 반환하지 않아도 된다. null값을 반환하는 getEmployees()를 처리하는 test1과 같은 상황은 null을 반환하지 않는 getEmployees()로 구현된 test2와 같은 상황으로 고쳐져야 한다.

      public class TestClass {
             
          int totalPay = 0;            // 물론 생성자에서 초기화해주는게 좋다.
      
           public void test1() {
      
               List<Employee> employees = getEmployees();
      
               if(employees != null){
                   for(Employee e : employees){
                       totalPay += e.getPay();
                   }
               }
           }
              
           /* getEmployees()가 null을 반환하지 않고 new 값으로 새로운 것을 반환하면 
               for문이 0번 반복되어 오류없이 넘어갈 수 있다.          */
      	public void test2() {
      
              List<Employee> employees = getEmployees();
      
              for(Employee e : employees){
                  totalPay += e.getPay();
              }
      
      	}
      }
       

       

    5. 클래스는 적은 인스턴스 변수를 가져야 한다. 그리고 응집도가 높다는 것은 클래스의 모든 메소드들에 대하여 인스턴스 변수를 사용하는 비율이 높다는 것이다. 어떤 클래스의 응집도가 높다는 것은 메소드와 변수가 서로 의존하며 논리적인 단위로 묶여있다는 것을 의미하지만 응집도가 낮다는 것은 메소드와 변수의 논리적 연결이 약하므로 클래스를 더욱 분리할 수 있음을 암시한다. 아래의 Stack Class는 size를 제외한 함수에서 인스턴스변수를 모두 활용하므로 응집도가 높다.

public class Stack {
        
    private int topOfStack = 0;
    List<Integer> elements = new LinkedList<Integer>();

	public int size() {
        return topOfStack;
	}

	public void push(int element) {
        topOfStack++;
        elements.add(element);
	}

	public int pop() throws PoppedWhenEmpty{
        if(topOfStack ==0)
            throws new PoppedWhenEmpty();

        int element = elements.get(--topOfStack);
        elements.remove(topOfStack);
        return element;
	}
}
 

 

  1. 자바에서는 synchronized 키워드를 활용하여 동기화 하라!
    자바에서는 synchronized를 사용하여 락을 설정할 수 있는데, 락으로 감싸여진 코드 영역은 한번에 한 스레드만 실행이 가능하다. 락은 스레드를 지연시키고 부하를 가중시키므로 synchronized문을 남발하는 것은 좋지 않다. 그리고 java.util.concurrent 패키지에는 다중  스레드 환경에서 사용해도 안전하며 성능까지 좋은 클래스들을 제공하는데, 실제로 ConcurrentHashMap은 거의 모든 상황에서 HashMap 보다 빠르다. 동시 읽기/쓰기를 지원하며 자주 사용하는 복합 연산을 다중 스레드 상에서 안전하게 만든 메서드로 제공한다.



2. 개념 정리

 


 

[ SRP ]

SRP(Single Responsibility Principle)는 작성된 클래스는 하나의 기능만을 가지며 클래스가 제공하는 모든 서비스는 그 하나의 책임을 수행하는데 집중되어 있어야 한다는 것이다. SRP를 적용하면 각 클래스가 책임지는 영역이 확실해지므로, 한 클래스에서 변경사항이 요구될 때, 다른 클래스에 주는 연쇄작용을 없앨 수 있다. 

 

 

[ OCP ]

OCP(Open Closed Principle)는 소프트웨어의 구성요소(클래스, 함수, 컴포넌트 등)은 확장에는 열려있고, 변경에는 닫혀있어야 한다는 것이다. 즉, 주어진 클래스에 대한 요구사항의 변경이나 추가가 필요한 상황에서 기존 구성요소는 수정이 일어나지 말아야 하며, 확장이 용이해야 한다는 의미이다.

 

 

[ DIP ]

DIP(Dependency Inversion Principle)는 구조적 디자인에서 발생하던 하위 레벨 모듈의 변경이 상위 레벨 모듈의 변경을 요구하는 것을 끊는다는 의미입니다. 실제 사용관계는 바뀌지 않으며 추상을 매개로 메세지를 주고받음으로써 관계를 최대한 느슨하게 만듭니다.

 

반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG more
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함