Skip to content

Code ‐ Abstraction

woojin edited this page Jul 22, 2026 · 2 revisions

Naming Conventions

1. 단수와 복수를 구분하기

  • 끝에 -(e)s를 붙여 단수/복수를 드러내는 것만으로도 중요한 정보를 전달한다.
// Bad
List<Order> order = orderRepository.findAll();
Order orders = orderRepository.findById(id);

// Good
List<Order> orders = orderRepository.findAll();
Order order = orderRepository.findById(id);

2. 이름 줄이지 않기

  • 줄임말은 가독성을 제물로 효율을 얻는 것 — 대부분 잃는 게 더 크다. 다만 관용적 줄임말(id, url, dto)은 허용.
// Bad
int usrCnt;
LocalDate regDt;
void calcTotAmt() { ... }

// Good
int userCount;
LocalDate registeredDate;
void calculateTotalAmount() { ... }

3. 은어/방언 대신 도메인 용어 쓰기

  • 농담에서 파생된 용어, 우리 팀만 아는 용어는 금지. 필요하면 도메인 용어를 먼저 정의한다.
// Bad  ("결제 취소"를 팀 은어로)
void ppuck(Order order) { ... }   // "빠꾸"
boolean isYolo;

// Good
void cancelPayment(Order order) { ... }
boolean isFirstPurchase;

4. 좋은 코드를 보고 습득하기

  • 비슷한 상황에서 자주 쓰는 단어·개념을 표준 라이브러리/오픈소스에서 익힌다.
// Bad  (직접 만든 어색한 이름)
List<User> userBox;
boolean checkUserExistOrNot(Long id);

// Good  (표준 컬렉션/JPA 관례를 따름)
List<User> users;
boolean existsById(Long id);

5. 일관성 유지하기(한 개념엔 한 단어)

  • 같은 개념을 find/get/retrieve/fetch로 섞어 쓰지 않는다. 다른 개념에 같은 단어도 쓰지 않는다.
// Bad
User getUser(Long id);
Order fetchOrder(Long id);
Product retrieveProduct(Long id);

// Good  (조회는 find 로 통일)
User findUser(Long id);
Order findOrder(Long id);
Product findProduct(Long id);

6. 대칭되는 짝 맞추기

  • 반대 동작은 관용적 짝으로: open/close, add/remove, start/stop, create/delete, begin/end.
// Bad
void addItem(Item item);
void deleteItem(Item item);   // add 의 짝은 remove

// Good
void addItem(Item item);
void removeItem(Item item);

7. Boolean은 상태를 묻는 형태로(부정형 금지)

  • is / has / can / should 접두어를 쓰고, 부정형 이름은 피한다(이중 부정 방지).
// Bad
boolean deleted;
boolean isNotValid;           // !isNotValid 이중 부정 발생

// Good
boolean isDeleted;
boolean isValid;              // 필요할 때 !isValid
boolean hasPermission;
boolean canCancel;

8. 검색 가능한 이름 (매직 넘버/문자열 제거)

  • 코드에 박힌 숫자·문자열은 상수로 이름 붙여 grep 으로 추적·수정 가능하게 한다.
// Bad
if (gameStatus == 1) { ... }
for (int i = 0; i < 7; i++) { ... }

// Good
private static final int GAME_STATUS_WIN = 1;
private static final int WORK_DAYS_PER_WEEK = 7;

if (gameStatus == GAME_STATUS_WIN) { ... }
for (int day = 0; day < WORK_DAYS_PER_WEEK; day++) { ... }

9. 단위와 의도를 이름에 담기

  • 숫자·시간은 단위를 붙인다. 단위 혼동(ms vs s)은 실제 장애로 이어진다.
// Bad
int timeout;
long size;
int delay;

// Good
int timeoutMs;
long fileSizeInBytes;
int delaySeconds;

10. 스코프에 비례한 길이

  • 좁은 지역변수는 짧게, 넓게 쓰이는 필드·public 요소는 길고 구체적으로. 불필요한 문맥은 뺀다.
// Bad  (Order 클래스 내부인데 접두어 중복)
class Order {
    Long orderId;
    LocalDate orderDate;
}

// Good
class Order {
    Long id;
    LocalDate date;
}

// 좁은 스코프는 짧아도 OK
for (int i = 0; i < size; i++) { ... }

11. 불용어(noise word) 빼기

  • Info, Data, Manager, Processor, Helper, the 등 의미 없는 단어를 붙이지 않는다.
// Bad
class ProductInfo { ... }
class ProductData { ... }
UserManager theUser;

// Good
class Product { ... }
User user;

12. 타입 정보를 이름에 인코딩하지 않기(헝가리안 회피)

  • 타입을 이름에 넣지 않는다 — 타입이 바뀌면 이름이 거짓말이 된다. 컬렉션은 복수형이면 충분.
// Bad
String strName;
int iCount;
String[] boardArray;
List<User> userList;

// Good
String name;
int count;
String[] board;
List<User> users;

13. 계층/역할 컨벤션 따르기 (백엔드)

  • 프레임워크 관례를 존중하고, REST URL 은 명사·복수형으로 짓는다(행위는 HTTP 메서드가 표현).
// Bad
class OrderHandler { ... }
class OrderManager { ... }
// GET /getOrders,  POST /createOrder

// Good
class OrderController { ... }
class OrderService { ... }
class OrderRepository { ... }
class OrderResponse { ... }
// GET  /orders/{id}
// POST /orders

Methods and Abstraction

  • 메서드와 추상화 - 한 메서드의 주제는 하나다.
  • 하나의 메서드는 하나의 일만 해야 하고, 그 안의 코드들은 같은 추상화 수준(altitude)에 있어야 한다.
  • 메서드 이름을 읽었을 때 "이 메서드는 X를 한다"라고 한 문장으로 말할 수 있어야 하고, 내부 코드가 모두 그 X를 설명하는 데 기여해야 한다.
// Bad❌(주제가 여러 개 — 추상화 수준이 뒤섞임)
function processOrder(order) {
  // 1. 검증 (낮은 수준의 세부 로직)
  if (!order.items || order.items.length === 0) throw new Error();
  if (order.total < 0) throw new Error();

  // 2. 할인 계산 (또 다른 세부 로직)
  let discount = 0;
  if (order.total > 100) discount = order.total * 0.1;

  // 3. DB 저장 (완전히 다른 관심사)
  db.connect();
  db.insert('orders', order);
}
// Good✅(주제는 하나: "주문을 처리한다")
function processOrder(order) {
  validate(order);
  const discount = calculateDiscount(order);
  save(order, discount);
}
  • 파라미터 순서가 주제(한 메서드 한 일)보다는 우선순위가 훨씬 낮다.
  • 다만 "공짜로 얻는 가독성"이라서, 알아두면 습관처럼 지키게 되는 정도이다.
copyFile(source, destination)   // ✅ "왼→오", 읽는 순서와 같음
copyFile(destination, source)   // ❌ 매번 문서 열어봐야 함
  • copy, move, assign 같은 건 관습적으로 (대상, 원본)이 아니라 (원본, 대상) 아니면 그 반대로 언어마다 정해져 있다.
  • 관습을 따르면 호출부가 주석 없이 읽힌다.

1. 중요한 것 / 주어에 해당하는 것을 앞으로

  • drawCircle(x, y, radius) — 위치가 먼저, 옵션이 나중.

2. 입력을 앞, 출력/설정을 뒤로 (관습이 있으면 관습 우선)

  • search(list, target), replace(text, old, new)

3. 선택적(optional) 파라미터는 항상 뒤로

  • 기본값 있는 건 뒤에 몰아야 호출이 깔끔해진다.

Method Declaration

  • 메서드 선언은 "이 메서드가 무엇이고, 어떻게 호출하는지"를 정의하는 코드이다.
  • 쉽게 말해, 메서드를 만들 때 이름·입력·출력·동작을 처음 적어두는 것을 말한다.
public  int   add(int a, int b)  {  return a + b;  }
  │      │     │        │              │
  │      │     │        │              └─ 본문(body): 실제 하는 
  │      │     │        └─ 매개변수(parameter): 입력값
  │      │     └─ 이름(name): 메서드 이름
  │      └─ 반환 타입(return type): 출력값의 종류
  └─ 접근 제어자(modifier): 누가   있는지
  • 이 메서드의 추상화를 외부에 약속하는 부분이다.
  • 메서드 이름의 기본 공식 : 동사로 시작한다.
uploadImage()      // ✅ 이미지를 업로드한다
deleteUser()       // ✅ 유저를 삭제한다
calculateTotal()   // ✅ 합계를 계산한다

image()            // ❌ 명사만 — 무엇을 하는지 모름
imageUpload()      // △ 뜻은 통하지만 동사가 뒤라 어색함

Abstraction Levels

  • 추상화 레벨(Abstraction Level)이란, "얼마나 세부사항을 감추고 큰 그림으로 말하느냐의 정도를 말한다.
높은 레벨(추상적):  "출근했어"
      ↕
중간 레벨:         "지하철 타고 회사 갔어"
      ↕
낮은 레벨(구체적):  "오른발 들고, 왼발 들고, 개찰구에 카드 찍고, 
                   2호선 승강장으로 내려가서..."
  • 위 케이스의 메서드 이름을 추상화한다면 "지하철 2호선을 타고 시청에서 환승해서 걸어간다"가 아니라 "출근한다"가 추상화가 적용된 것이다.
// 세부 과정들 (낮은 레벨)
function goToWork() {
  takeSubwayLine2();      // 2호선을 탄다
  transferAt("시청");      // 시청에서 환승한다
  walkToOffice();         // 걸어간다
}

Magic Numbers, Magic Strings

  • 매직 넘버, 매직 스트링은 코드 안에 아무 설명 없이 툭 튀어나온 숫자나 문자열을 말한다. "이 값이 왜 여기 있는지" 마법처럼 알 수 없다고 해서 매직이라고 부른다.
// ❌ 매직 넘버 / 매직 스트링
if (user.age >= 19) { ... }              // 19가 뭔데?
if (order.total > 100000) { ... }        // 100000은 무슨 기준?
if (user.role === "A") { ... }           // "A"가 대체 뭐지?
  • 읽는 사람이 19, 100000, "A"가 무슨 의미인지 알 수가 없다.
// ✅ 의미를 이름으로 드러냄
const ADULT_AGE = 19;
const FREE_SHIPPING_THRESHOLD = 100000;
const ROLE_ADMIN = "A";

if (user.age >= ADULT_AGE) { ... }              // "성인 나이 이상"
if (order.total > FREE_SHIPPING_THRESHOLD) { }  // "무료배송 기준 초과"
if (user.role === ROLE_ADMIN) { ... }           // "관리자면"

📖 Code Philosophy

📖 Java

📖 Kotlin

📖 Coroutine

📖 Spring

📖 Spring Security

📖 Spring Batch

📖 Database

📖 MySQL

📖 Redis

📖 JPA

📖 QueryDsl

📖 MSA

📖 Kafka

📖 Apache Flink

  • [Apache Flink - Apache Flink Architecture]
  • [Apache Flink - Stream Processing]
  • [Apache Flink - Data Stream API & Window]
  • [Apache Flink - State Management]

📖 HTTP

📖 AWS

📖 Docker

📖 Kubernetes

📖 Github Actions

📖 Jenkins

📖 Nginx

📖 Monitoring

📖 Test(feat. Load Testing)

  • [Test - Load Testing Fundamentals]
  • [Test - Identifying Bottlenecks with Load Testing]
  • [Test - Resolving Bottlenecks and Improving Performance]

📖 Test(feat. Java)

📖 Spring AI

📖 gRPC

  • [gRPC - Writing .proto Files with Protocol Buffers]
  • [gRPC - Various Communication Patterns in gRPC]
  • [gRPC - gRPC Optimization Techniques and Advanced Features]

📖 TDD(Test-Driven-Development)

📖 PostgreSQL

  • [PostgreSQL - Docker만을 사용하는 경량화된 환경 구성 방법]
  • [PostgreSQL - PostgreSQL에서 제공하는 데이터 타입]
  • [PostgreSQL - PostgreSQI의 JSONB, 역인덱싱과 활용 방법]
  • [PostgreSQL - 데이터베이스 성능을 위한 최적화 패턴 및 전략]
  • [PostgreSQL - 트랜잭션과 ACID, Isolation 수준별 차이]
  • [PostgreSQL - Database Lock 교착상태와 읽기/쓰기 성능을 보장하는 MVCC 모델]
  • [PostgreSQL - pgvector와 벡터 저장, 유사도 검색 패턴 개념]
  • [PostgreSQL - 벡터 인덱스 최적화와 벡터 검색과 전문 검색 결합 패턴]
  • [PostgreSQL - PostgreSQL 플러그인]
  • [PostgreSQL - PostGIS - 공간 쿼리와 GIST 인덱스, 지리 타입과 공간 쿼리를 위한 타입과 기본 함수]
  • [PostgreSQL - pg_search - 검색 엔진 없이 텍스트 검색 구현과 주의사항]
  • [PostgreSQL - 단일 인스턴스 한계를 극복하는 분산 패턴과 스케줄링, 분산 환경 구축 방법]
  • [PostgreSQL - Citus - 분산 테이블과 분산 쿼리를 위한 Extension과 데이터 분산 처리]
  • [PostgreSQL - pg_cron - PostgreSQL로 구성하는 CronJob]
  • [PostgreSQL - 스케줄러 + 분산 처리를 동시에 도입하는 주기적 집계 쿼리 패턴]

📖 Workflow-Driven Techniques for Large-Scale Traffic Processing

  • [Workflow-Driven Techniques for Large-Scale Traffic Processing - Kafka + Debezium을 활용한 CDC 패턴 설계]
  • [Workflow-Driven Techniques for Large-Scale Traffic Processing - Temporal을 활용한 워크플로우 패턴]
  • [Workflow-Driven Techniques for Large-Scale Traffic Processing - Docker와 경량 이미지를 활용한 환경 구축 방법]
  • [Workflow-Driven Techniques for Large-Scale Traffic Processing - Kafka에서의 메시지 Delivery Guarantee]
  • [Workflow-Driven Techniques for Large-Scale Traffic Processing - 실시간 동기화의 핵심 CDC]
  • [Workflow-Driven Techniques for Large-Scale Traffic Processing - MySQL Binary Log 기반의 CDC]
  • [Workflow-Driven Techniques for Large-Scale Traffic Processing - Binary Log 기반의 CDC 구현 플랫폼 Debezium이란?]
  • [Workflow-Driven Techniques for Large-Scale Traffic Processing - Debezium Architecture]
  • [Workflow-Driven Techniques for Large-Scale Traffic Processing - Debezium Architecture Best Practice와 주의사항]

📖 Reactive Programming

📖 ElasticSearch

  • [ElasticSearch - Search Fundamentals & How Search Works]
  • [ElasticSearch - Korean-Optimized Search]
  • [ElasticSearch - Mapping & Data Types]
  • [ElasticSearch - Common Search Features]
  • [ElasticSearch - Building a Product Search Engine with Elasticsearch]
  • [ElasticSearch - Deploying Elasticsearch with Elastic Cloud]
  • [ElasticSearch - Managing Documents]
  • [ElasticSearch - Analysis & Mapping]
  • [ElasticSearch - Search Fundamentals]
  • [ElasticSearch - Query Joins]
  • [ElasticSearch - Processing Search Results]
  • [ElasticSearch - Aggregations]
  • [ElasticSearch - Tips for Improving Search Results]
  • [ElasticSearch - Elasticsearch Clients]
  • [ElasticSearch - Understanding How Elasticsearch Works]
  • [ElasticSearch - Monitoring Elasticsearch]
  • [ElasticSearch - Elasticsearch Troubleshooting]

Clone this wiki locally