Clean Coders - Form

develkkm·2025년 10월 17일

CleanCoders

목록 보기
4/6

주석(Comment)

좋은 주석 — “읽는 사람에게 감사받는 주석”

주석은 이름으로 의도를 표현할 수 없을 때만 사용해야 한다.
코드가 충분히 명확하다면 주석은 불필요하다.
즉, 주석은 “설명이 필요한 코드”의 대체물이 아니라, 예외적인 보조 장치여야 한다.

필요한 경우

  • 법적 고지 / 라이선스 문구
  • 정규식이나 복잡한 표현식 설명
  • 시간이 오래 걸리는 테스트에 대한 주의문
  • TODO (명확한 작업 예정)
  • Public API 문서화
// 정규식: MM:DD 형식의 날짜만 허용
Pattern.compile("^(0[1-9]|1[0-2]):(0[1-9]|[12][0-9]|3[01])$");

// TODO: 성능 개선 필요 - 캐시 적용 예정

피해야 할 주석

  • 중얼거리는 주석
    // i를 1 증가시킨다.
    i++;
  • 변경 이력 주석 → Git이 관리한다.
  • 빅 배너 주석, 장식용 구분선
  • 조건문, 반복문 끝 표시
  • 누가 작성했는지 기록
  • 멀리 떨어진 코드 설명

좋은 코드는 이런 주석 없이도 읽히며,
주석이 필요하다면 코드를 개선해야 한다는 신호일 수도 있다.


공란(Whitespace)

공백은 코드의 ‘호흡’이다.
적절한 공백은 코드를 덩어리로 나누고, 논리적 관계를 드러낸다.

공백을 넣어야 하는 위치

  • 메소드와 메소드 사이
  • publicprivate 멤버 변수 사이
  • 변수 선언부와 실행부 사이
  • if, while 블록 전후
int count = 0;

if (isValid()) {
    process();
}

return count;

빈 줄 하나로 논리 흐름이 구분되면,
읽는 사람은 더 이상 코드를 ‘해석’하지 않고 ‘이해’하게 된다.


클래스(Class)

1) 정보 은닉 (Encapsulation)

클래스의 핵심은 데이터 보호와 응집된 행동 제공이다.
private 변수는 외부에서 보이지 않아야 하며,
외부에 노출되는 것은 항상 ‘행동’이어야 한다.

class Speaker {
    private int volume;

    public void increaseVolume() {
        if (volume < 100) volume += 10;
    }
}

외부에서 speaker.volume = 200 같은 조작이 불가능해야 한다.
이것이 객체의 무결성을 지키는 첫걸음이다.


2) 게터·세터의 함정

게터(getter)와 세터(setter)는
클래스를 단순한 데이터 구조로 바꾸며, 응집도를 약화시킨다.

//  데이터 노출형
int getBalance();
void setBalance(int balance);

//  추상화된 행동형
void deposit(int amount);
void withdraw(int amount);

게터세터를 완전히 없앨 수는 없지만, 객체의 행위를 중심으로 설계해야 한다.


3) 응집도와 추상화

응집도가 높은 클래스는 단일한 책임을 가진다.
행동은 관련된 데이터에 직접 작용하며, 내부 구조는 외부에서 보이지 않는다.

추상화는 “무엇을 하는지”에 집중하게 하고, “어떻게 하는지”는 숨긴다.

이 구조 덕분에 클래스는 변경에 강한 단위가 된다.


데이터 구조(Data Structure)

데이터 구조는 클래스의 반대 개념이다.
행동이 아닌 값 자체를 표현하며, 구현이 노출되어 있다.

구분클래스데이터 구조
구성private 변수 + 메서드public 변수 또는 getter/setter
특징캡슐화 / Tell 가능구현 노출 / Ask만 가능
장점타입 확장에 강함기능 추가에 강함
// 데이터 구조
class PointData {
    public int x;
    public int y;
}

// 클래스
class Point {
    private int x, y;
    public double distanceTo(Point other) { ... }
}

데이터 구조는 기능 추가에 유리하지만 타입 추가에 약하고,
클래스는 타입 추가에 강하지만 기능 확장에는 약하다.

→ 즉, 두 개념은 서로 보완적이다.


바운더리(Boundary)

애플리케이션은 본질적으로 두 계층으로 나뉜다.

  • Main Partition (Concrete)
  • Application Partition (Abstract)

의존성의 방향은 항상 추상적인 쪽으로 향해야 한다.
즉, 구체적인 구현이 상위 정책을 의존해서는 안 된다.

//  나쁜 예시
Service service = new JdbcService();

//  좋은 예시
Service service = new DatabaseService(new JdbcRepository());

이 원칙은 IoC(Inversion of Control)와 DI(Dependency Injection)의 기초다.
상위 정책(High-level policy)은 하위 구현(Low-level detail)로부터 보호되어야 한다.


객체지향과 데이터베이스의 경계

OOP와 RDB는 서로 다른 세계에 존재한다.

  • DB Table은 데이터 구조다.
  • 객체(Object)는 클래스다.

ORM은 이 둘을 연결하려 하지만,
본질적으로는 데이터 구조 ↔ 객체 간 불일치 문제(Object-Relational Impedance Mismatch)를 안고 있다.

  • DB는 “엔터프라이즈 전체”를 위한 최적화 구조를 갖는다.
  • 객체는 “특정 애플리케이션”을 위한 행동 중심 구조다.

따라서 Repository, DAO, Service Layer 등을 통해
이 경계를 명확히 분리해야 한다.

@Repository
class UserRepository {
    // DB 접근 (데이터 구조)
}

@Service
class UserService {
    // 비즈니스 로직 (객체 행동)
}

이렇게 계층을 구분함으로써
객체지향의 유연함과 DB의 안정성을 동시에 얻을 수 있다.


정리

항목핵심 개념
주석이름으로 표현 불가능할 때만, 읽는 사람에게 감사받을 주석
공란논리 단위 사이의 여백은 코드의 리듬
클래스행동 중심, 캡슐화, 최소한의 게터세터
데이터 구조값 중심, 구현 노출, 기능 추가에 강함
바운더리의존성은 추상 → 구체 방향, IoC·DI 원칙
OOP vs DB객체와 테이블은 철학이 다르다 — 계층으로 분리하라
profile
알던것을 더 확실하게

0개의 댓글