> **TL;DR** — Clean ABAP은 SAP가 **오픈소스로 공개한 ABAP 코딩 스타일 가이드**다. 핵심은 단 하나: *"6개월 뒤의 나, 그리고 옆자리 동료가 1초라도 덜 고민하게 쓰자."* 이름은 의도를 드러내고, 매직넘버 대신 상수를, 불리언은 `abap_bool`로, 메서드는 작게·한 가지만, 에러는 클래스 기반 예외로 다룬다. 아래 do/don't 표만 훑어도 코드 리뷰 지적의 절반이 사라진다. 이 글은 SAP의 공개 스타일 가이드(`github.com/SAP/styleguides`)와 SAP 공식 ABAP 문서를 1차 출처로 정리한 것이다. 규칙마다 **"왜"**와 **짧은 예제**를 붙였고, 한국 현업에서 자주 헷갈리는 함정(특히 `BOOLC`)은 공식 문서로 교차 검증했다. --- ## 0. Clean ABAP이 뭔가, 왜 쓰나 Clean ABAP은 Robert C. Martin의 *Clean Code* 정신을 ABAP 문법에 맞게 옮긴 규칙 모음이다. 목표는 "동작하는 코드"가 아니라 **"읽는 사람이 빨리 이해하고 안전하게 고칠 수 있는 코드"**다. - **읽는 시간 > 쓰는 시간**: 코드는 한 번 쓰고 수십 번 읽힌다. 읽기 비용을 줄이는 게 남는 장사다. - **테스트·리팩터링 용이성**: 작은 메서드·객체지향·명시적 예외는 단위 테스트와 mocking을 쉽게 만든다. - **신구 ABAP 혼재**: 7.40+ 의 모던 문법(인라인 선언, 함수형 표현, `NEW`)을 쓰면 코드가 짧고 명확해진다. 가이드는 17개 장으로 구성된다: 이름 · 언어 · 상수 · 변수 · 내부테이블 · 문자열 · 불리언 · 조건 · IF · 정규식 · 클래스 · 메서드 · 에러처리 · 주석 · 포매팅 · 테스트. 이 글에선 **현업 임팩트가 큰 6개 영역**만 추린다. --- ## 1. 이름 (Names) — 타입이 아니라 의미를 담아라 이름은 변수의 **데이터 타입**이 아니라 **무엇을 담는지**를 말해야 한다. 헝가리안 표기나 의미 없는 접미사는 잡음일 뿐이다. | 원칙 | 왜 | 👍 Do | 👎 Don't | |---|---|---|---| | 서술적 이름 | 의미가 곧 문서 | `max_wait_time_in_seconds` | `lv_n`, `sysubrc_04` | | 약어 피하기 | 사람마다 다르게 읽음 | `customer_name` | `cust_nm` | | `snake_case` 일관 | ABAP은 대소문자 무시 → 한 방식으로 통일 | `max_response_time` | `maxResponseTime` | | 클래스=명사, 메서드=동사 | 역할이 한눈에 | `CLASS account`, `METHODS withdraw` | `CLASS do_account` | | 잡음 단어 제거 | `_data`/`_info`/`_object`는 정보 0 | `account` | `account_data` | > 💡 한국 현업 팁: `lv_`, `lt_`, `ls_`, `lo_` 같은 헝가리안 접두어는 Clean ABAP이 **권장하지 않는다**(타입은 IDE가 알려준다). 단, 팀 표준이 이미 접두어라면 *일관성*이 더 중요하니 팀과 합의 후 점진 전환하라. --- ## 2. 매직넘버 & 상수 (Constants) 코드에 박힌 리터럴 `'D'`, `4`, `'X'`는 6개월 뒤 아무도 의미를 모른다. 이름 있는 상수로 바꾸면 코드가 곧 설명이 된다. ```abap " 👎 Don't — 'D'가 뭔지 주석 없으면 모름 IF abap_type = 'D'. " 👍 Do — 의도가 드러남 IF abap_type = cl_abap_typedescr=>typekind_date. ``` 상수가 여러 개 묶일 땐 **상수 인터페이스보다 `ENUM`**(7.51+)을 선호한다 — 타입 안전성이 생긴다. ```abap TYPES: BEGIN OF ENUM message_severity, warning, error, END OF ENUM message_severity. ``` --- ## 3. 불리언 (Booleans) — 여기서 진짜 버그가 난다 ⚠️ | 원칙 | 왜 | 👍 Do | |---|---|---| | 타입은 `abap_bool` | 일반 `char1`과 혼동 방지 | `DATA has_entries TYPE abap_bool` | | 비교는 `abap_true`/`abap_false` | 의도를 명시 | `IF has_entries = abap_true` | | 값 설정은 `xsdbool( )` | 식을 불리언으로 안전하게 변환 | `DATA(ok) = xsdbool( line IS NOT INITIAL )` | ### `BOOLC` vs `XSDBOOL` — 반드시 알아야 할 함정 둘 다 식을 "참/거짓"으로 바꾸지만 **반환 타입이 다르다**. 이 차이가 조용한 버그를 만든다 (SAP 공식 ABAP 문서 기준): | 함수 | 반환 타입 | `abap_true`와 비교 시 | |---|---|---| | `boolc( )` | `string` | ⚠️ **위험** — `c`를 `string`으로 변환하며 **뒤 공백을 무시** → 의도와 다르게 동작 가능 | | `xsdbool( )` | `c LENGTH 1` (= `abap_bool`과 동일) | ✅ 안전 — `abap_true`/`abap_false`와 그대로 비교 가능 | ```abap " 👎 Don't — boolc 결과를 abap_true와 비교: string 변환으로 공백 무시 → 함정 DATA(flag) = boolc( sy-subrc = 0 ). IF flag = abap_true. " 의도대로 안 될 수 있음 " 👍 Do — xsdbool: char1 반환이라 abap_bool과 정확히 호환 DATA(flag) = xsdbool( sy-subrc = 0 ). IF flag = abap_true. " 안전 ``` **결론**: 불리언 변환은 무조건 `xsdbool`. `boolc`는 결과를 `abap_true`와 비교하지 말 것. --- ## 4. 메서드 (Methods) — 작게, 한 가지만 | 원칙 | 왜 | 요지 | |---|---|---| | IMPORTING 파라미터는 3개 미만 | 조합 폭증 → 테스트 난이도↑ | 관련 값은 구조체로 묶어라 | | `OPTIONAL` 대신 메서드 분리 | 한 메서드 = 한 용도 | `do_a()` + `do_b()` > `do( optional_a, optional_b )` | | `EXPORTING`보다 `RETURNING` | 함수형 호출이 명확 | `result = get_total( )` | | 출력은 정확히 1개 | 출력 여러 개 = 책임 섞임 신호 | 관련 값은 구조체 1개로 반환 | | 작게 유지 | 이해·테스트·리팩터링 쉬움 | 한 메서드 3~5문장 지향 | | 하나만, 잘, 그것만 | 단일 책임 | 복잡 로직은 헬퍼로 추출 | ```abap " 👎 Don't method( EXPORTING output = result ). " 👍 Do — 함수형, 의도 명확 result = method( ). ``` --- ## 5. 에러 처리 (Error Handling) — 조용히 삼키지 마라 | 원칙 | 왜 | |---|---| | 리턴코드보다 예외 | `sy-subrc`는 무시되기 쉽다 — 예외는 비정상 흐름을 강제로 드러낸다 | | 실패를 흘려보내지 말 것 | 모든 에러 경로를 명시적으로 처리 (silent catch 금지) | | 예외는 "에러"에만 | 정상 분기를 예외로 처리하지 말 것 | | 클래스 기반 예외 사용 | 타입 안전 + 계층 구조 (`CX_STATIC_CHECK` / `CX_NO_CHECK`) | ```abap " 👎 Don't — 빈 CATCH = 에러 증발 TRY. do_risky( ). CATCH cx_root. ENDTRY. " 👍 Do — 잡았으면 최소한 기록/변환 TRY. do_risky( ). CATCH cx_some_error INTO DATA(error). RAISE EXCEPTION NEW zcx_my_error( previous = error ). ENDTRY. ``` --- ## 6. "X를 Y보다 선호하라" 모음 모던 ABAP 한 줄 정리. 새로 짜는 코드라면 오른쪽을 버리고 왼쪽으로. | 선호 (Prefer) | 대신 (to) | 이유 한 줄 | |---|---|---| | 객체지향 | 절차형(프로그램/함수모듈) | 모듈화·테스트·리팩터링 | | 함수형 표현식 | 절차형 구문 | 짧고 명확, 모던 | | 합성(composition) | 상속(inheritance) | 유연·이해 쉬움 | | 인스턴스 메서드 | 정적 메서드 | 다형성·mocking 가능 | | `LINE_EXISTS( )` | `READ TABLE` / `LOOP AT` 존재확인 | 의도 직접 표현 | | `INSERT INTO TABLE` | `APPEND TO` | 모든 테이블 타입 호환 | | `CASE` | `ELSEIF` 연쇄 | 구조 명확, 중첩 실수 방지 | | 긍정 조건 | 부정 조건 | 인지 부하↓ | | 인라인 선언 | 상단 일괄 선언 | 변수를 쓰는 곳 가까이 | | `NEW` | `CREATE OBJECT` | 짧고 모던한 문법 | --- ## 7. 어떻게 시작하나 (실전) - **전부 한 번에 바꾸지 마라.** 레거시는 "건드리는 김에 청소(Boy Scout Rule)"가 현실적이다. - **자동 검사 도구**로 사람 리뷰 부담을 줄여라 (모두 공개/무료): - **ABAP Cleaner** (Eclipse ADT 플러그인) — 저장 시 자동 정리 - **Code Pal for ABAP** — Clean ABAP 규칙 기반 ATC 체크 - **abapLint** — CI에서 정적 검사 - **팀 합의가 먼저**다. 접두어 폐지 같은 변화는 팀 표준을 함께 바꿔야 한다. --- ## 출처 & 더 읽을거리 - SAP 공