[클린코드] 10장 : 클래스

목록으로 돌아가기
  • 클래스를 정의하는 표준 자바 관례에 따르면, 하나의 클래스 안에서 순서는 다음과 같다.
    • 모든 상수 및 변수, 메소드는 public → protected → package → private 순서로 적는다.
    • static 상수 → static 변수 → instance 변수 → 메서드

⇒ 테스트 등을 위해 private 변수 및 메소드를 protected로 선언하여 접근을 허용하기도 하지만, 캡슐화를 풀기 전에 이를 비공개 상태로 유지할 온갖 방법을 강구해야 한다.

  • 함수와 마찬가지로, 클래스도 작게 만들어야한다. 단, 코드의 행 수로 크기를 따진 함수와 다르게 클래스는 맡은 책임을 계산 및 측정한다.
    • 한 클래스가 맡은 책임이 너무 많다면, 해당 클래스의 이름을 짓기 어려울 것이다. if, and, or, but 등을 사용하지 않고 25단어 이내로 설명이 가능한 클래스를 만들도록 지향하자.

  • 클래스를 작게 만들기 위한 방법으로, 아래 세 가지를 참고할 수 있다.
    • 단일 책임 원칙(SRP)
      • SRP란 클래스나 모듈을 변경할 이유가 하나뿐이어야 한다는 원칙
      • 클래스가 맡고 있는 책임을 파악하려 해본다면, 코드를 추상화하기 쉬워진다.
      • 클래스가 맡고 있는 책임을 되도록 하나로 줄여보자.
    • 응집도를 낮게 유지
      • 응집도는 모듈 내 요소들이 서로에게 연관되어있는 정도를 뜻한다.
      • 클래스는 인스턴스 변수의 수가 적어야하며, 각 클래스 메소드는 클래스 인스턴스 변수를 하나 이상 사용해야한다.
      • 일반적으로 메소드가 변수를 더 많이 사용한다면, 이는 메소드와 클래스의 응집도가 더 높다는 이야기이다.
      • 즉, 모든 인스턴스 변수를 메소드마다 사용하는 클래스는 응집다고 제일 높다.
      • 응집도가 높아질수록 변수와 메소드를 적절하게 분리하여 새로운 클래스로 쪼개주자.
    • 변경하기 쉬운 클래스 만들기
      • 클래스를 단순하고 이해하기 쉽게 만들자
      • 새 기능을 추가하거나 기능을 변경할 때 코드를 건드리는 일이 최소하게 되어야 바람직하며, 이를 따르면 클래스는 자연스럽게 작아질 것이다.

  • 변경으로부터 격리하기
    • 구체적인 클래스는 상세한 구현에 의존되며, 추상적인 클래스는 개념에만 의존한다. 이 때, 요구사항이 변경됨에 따라 수정해야하는 구현이 구체적이라면, 이는 위험에 빠질 가능성이 높아진다.
    • 그러므로 추상적 클래스를 사용하여 변경으로부터 격리함을 통해 위험도를 낮춘다.
    • 또한 시스템의 결합도를 낮추면 유연성 및 재사용성도 높아진다.

본문에 대한 예시

예시로 쓰려고 했던 프로젝트를 타입스크립트 + 리액트 네이티브로 만들었기에, 근래 함수형 컴포넌트 작성을 지향하는 리액트 네이티브는 클래스로 쓰는 것이 거의 없었다.

그리하여, 하나의 예시 코드를 작성해보고, 위의 코드를 지키면서 수정해보고자 한다.

public class HeadPhone {
	public void outSound(Sound outputSound);
	private void equalizeSound(Sound inputSound);
	public void checkInputSound(Sound inputSound);

	public Sound inputSound;
	public Sound outputSound;
	private Sound digitalSound;
	static public Sound mainSound;
	static public boolean isMute;

	public boolean getHeadPhoneAvailiable(boolean isMute, Sound inputSound);
	public String getSoundPath(Sound outputSound, Sound inputSound);
}

위의 예시는 헤드폰의 기능 및 설정 등을 다루는 클래스다. 위의 클래스는 1. 표준 자바 관례, 2. SRP, 3. 응집도를 낮게 유지 등 본문의 여러 방법을 따르지 않고 있다.

public, private 간의 순서와 변수 및 메소드 간의 순서를 지키지 않았고 (1번), 스피커와 마이크의 책임을 한 번에 다루고 있으며 (2번), 응집도도 변수 사용이 많아짐에 따라 높기 때문이다.(3번)

이를 의식하여 고친다면 다음과 같이 바뀔 수 있다.

public class Speaker{
	public Sound outputSound;
	private Sound digitalSound;

	public void outSound(Sound outputSound);
}
public class Microphone {
	static public Sound mainSound;
	static public boolean isMute;
	public Sound inputSound;
	private Sound digitalSound;

	public boolean getHeadPhoneAvailiable(boolean isMute, Sound inputSound);

	public void checkInputSound(Sound inputSound);
	private void equalizeSound(Sound inputSound);
}

public과 private간의 순서를 맞췄으며, 상수→변수→메소드 순서로 가는 자바 관례를 지켰다. 또한 각각의 책임을 갖는 클래스로 쪼개어 책임을 최소한으로 가져가게 구현하였으며, 이를 통해 응집도도 낮추었다.

클래스의 클린코드 작성 방법은 함수와 매우 비슷하다. 작은 단위로 쪼개는 조건을 다르게 지정하였을 뿐, 작성 관례 및 최소 단위를 지향하는 등의 행위는 많은 점이 닮아있다.

그리하여 책임을 적게 쥐어주며 최대한 추상적으로 클래스를 작성하는 것은 코드를 깔끔하게 유지해 줄 것이며, 요구사항 변경으로 인한 구현의 어려움에서 다소 쉽게 탈출시켜 줄 것이다.

author-profile
Written by 상 한규

댓글