2023. 12. 23. 22:22ㆍComputer Science
- 주석을 신뢰하면 안된다.
- 오래될수록 완전히 그릇된 가능성도 있다.
- 이유? 프로그래머들이 주석을 유지하고 보수하기란 현실적으로 불가능
- 코드는 변화하고 진화한다.
- → 일부가 여기서 저기로 위치가 변경되기도 함
- 부정확한 주석은 아예 없는 주석보다 훨씬 더 나쁘다.
그리고 주석은 독자를 현혹하고 오도함.
⚠️ 더 이상 지킬 필요가 없는 규칙이나 지켜서는 안되는 규칙을 명시한다.
💡 진실은 한 곳에 존재 → 바로 코드
[ 좋은 주석 ]
정말로 좋은 주석은, 주석을 달지 않을 방법을 찾아낸 주석
1. 법적인 주석
- 회사가 정립한 구현 표준에 맞춰 법적인 이유로 특정 주석을 넣으라고 명시
- 소스 파일 첫머리에 주석으로 들어가는 저작권 정보와 소유권 정보는 필요하고, 타당함
- FitNess에서 모든 소스 파일 첫머리에 추가한 표준 주석 헤더. 요즘 IDE 는 주석 헤더를 잦동으로 축소해 코드만 깔끔하게 표시함
// Copyright (C) 2003, 2004, by Object Mentor, Inc. All rights reserved.
// GNU General Public License 버전 2 이상을 따르는 조건으로 배포
2. 정보를 제공하는 주석
// 테스트 중인 Responder 인스턴스를 반환한다.
protected abstract Responder responderInstance();
Tip: 함수 이름에 정보를 담는 편이 더 좋다. 위 코드는 함수 이름을 responderBeingTested 로 바꾸면 주석이 필요 없어짐.
// kk:mm:ss EEE, MMM dd, yyyy 형식
Pattern timeMatcher = Pattern.compile(
"\\\\d*:\\\\d*:\\\\d* \\\\w*, \\\\w*, \\\\w* \\\\d*, \\\\d*"
);
코드에서 사용한 정규표현식이 시각과 날짜를 뜻함.
대안:
이왕이면 시각, 날짜 변환하는 클래스 만들어 클래스 타입 상속받은 인스턴스 생성해 코드를 가지고 오는게 깔끔함.
3. 의도를 설명하는 주석
주석은 구현 이해를 넘어 결정에 깔린 의도까지 설명해야함.
e.g. 두 객체 비교시 다른 어떤 객체보다 자기 객체에 높은 순위를 주기로 결정한 코드 예시
public int compareTo(Object o)
{
if(o instanceof WikiPagePath)
{
WikiPagePath p = (WikiPagePath) o;
String compressedName = StringUtil.join(names, "");
String compressedArgumentName = StringUtil.join(p.names, "");
return compressedName.compareTo(compressedArgumentName);
}
return 1; // 오른쪽 유형이므로 정렬 순위가 더 높다.
}
public void testConcurrentAddWidgets() throw Exception {
WidgetBuilder widgetBuilder = new WidgetBuilder(
new Class [] { BoldWidget.class }
);
String text = "'''bold text'''";
ParentWidget parent = new BoldWidget(
new MockWidgetRoot(), "'''bold text'''"
);
AtomicBoolean failFlag = new AtomicBoolean();
failFlag.set(false);
// 스레드를 대량 생성하는 방법으로 어떻게든 경쟁 조건을 만들어 시도한다.
for (int i = 0; i < Thread.activeCount(); i++) {
WidgetBuilderThread widgetBuilderThread = new WidgetBuilderThread(
widgetBuilder, text, parent, failFlag
);
Thread thread = new Thread(widgetBuilderThread);
thread.start();
}
assertEquals(false, failFlag.get());
}
4. 의미를 명료하게 밝히는 주석
5. 결과를 경고하는 주석
6. TODO 주석
‘앞으로 할 일’ 을 // TODO 주석으로 남겨두면 편하다.
// TODO-MdM 현재 필요하지 않다.
// 체크아웃 모델을 도입하면 함수가 필요없음
protexted VersionInfo makeVersion() throws Exception
{
return null;
}
함수를 구현하지 않은 이유와 미래 모습을 // TODO 주석으로 설명
- TODO 주석은 프로그래머가 필요하다 여기지만 당장 구현하기 어려운 업무를 기술한다.
- 더 이상 필요 없는 기능을 삭제하라는 알림
- 누군가에게 문제를 봐달라는 요청
- 더 좋은 이름을 떠올려달라는 부탁
- 앞으로 발생할 이벤트에 맞춰 코드를 고치라는 주의 등에 유의
7. 중요성을 강조하는 주석
대수롭지 않다고 여겨질 뭔가의 중요성을 강조하기 위해서도 주석을 사용함.
String listItemContent = match.group(3).trim();
// 여기서 trim 은 정말 중요하다. trim 함수는 문자열에서 시작 공백을 제거한다.
// 문자열에 시작 공백이 있으면 다른 문자열로 인식되기 때문
new ListItemWidget(this, listItemContent, this.level + 1);
return buildList(text.substring(match.end()));
8. 공개 API 에서 JavaDocs
설명이 잘 된 공개 API 는 참으로 유용하고 만족스럽다. 표준 자바 라이브러리에 사용한 JavaDocs 가 좋은 예다.
공개 API 구현을 한다면, 반드시 훌륭한 Javadocs를 작성한다. Javadocs 역시 독자를 오도하거나, 잘못 위치하거나, 그릇된 정보를 전달할 가능성이 존재함.
나쁜 주석
밥아저씨 왈:
대다수 주석이 이 범주에 속함. 나쁜 주석들은 허술한 코드 지탱하거나, 엉성한 코드를 변명, 미숙한 결정을 합리화 하는 등 프로그래머가 주절거리는 독백
주절거리는 주석
같은 이야기 중복하는 주석
오해할 여지가 있는 주석
의무적으로 다는 주석
이력을 기록하는 주석
있으나 마나한 주석
무서운 잡음
함수나 변수로 표현할 수 있다면 주석을 달지마라.
닫는 괄호에 다는 주석
( 헉,,SwiftUI 할때 선언형에 빌더패턴이라 그런지 세로로 길어져서 닫는 괄호에 주석을 달고 표시하곤 했었다. 사실 그건 유데미 SwiftUI 강의를 보고 그 개발자 분이 하신게 끝 부분하기 좋다고 생각해서 나도 따라하곤 했었다..근데 이게 나쁜 주석이구나..??)
아하,, 작고 캡슐화된 함수에는 좋지 못함..
그렇담 나는 써도 되겠네..세로롤 길어지다 보니 끝부분과 중괄호들 구분하기에 좋아서 쓰긴 해야겠다.
차선책: 닫는 괄호에 주석을 달아야겠다는 생각이 든다면 대신에 함수를 줄이려 시도한다.
import SwiftUI
struct CustomCirlcleView: View {
@State private var isAnimateGradient: Bool = false
var body: some View {
ZStack {
Circle()
.fill(
LinearGradient(
colors: [
.customIndigoMedium,
.customSalmonLight
],
startPoint: isAnimateGradient ? .topLeading : .bottomLeading,
endPoint: isAnimateGradient ? .bottomTrailing : .topTrailing
)
)
.onAppear {
withAnimation(.linear(duration: 3.0).repeatForever(autoreverses:true)) {
isAnimateGradient.toggle()
}
}
MotionAnimationView()
} //: ZSTACK
.frame(width: 256,height: 256)
}
}
struct CustomCirlcleView_Previews: PreviewProvider {
static var previews: some View {
CustomCirlcleView()
}
}
이런 경우 닫는 주석 허용 가능하지 않을까?
나쁜코드 예시 (내 코드)
import SwiftUI
struct MotionAnimationView: View {
// MARK: - PROPERTIES
@State private var randomCircle: Int = Int.random(in: 6...12)
@State private var isAnimating: Bool = false
// MARK: - FUNCTIONS
// 1. RANDOM COORDINATE
func randomCoordinate() -> CGFloat {
return CGFloat.random(in: 0...256)
}
// 2. RANDOM SIZE
func randomSize() -> CGFloat {
return CGFloat(Int.random(in: 4...80))
}
// 3. RANDOM SCALE
func randomScale() -> CGFloat {
return CGFloat(Double.random(in: 0.1...2.0))
}
// 4. RANDOM SPEED
func randomSpeed() -> Double {
return Double.random(in: 0.05...1.0)
}
// 5. RANDOM DELAY
func randomDeley() -> Double {
return Double.random(in: 0...2)
}
var body: some View {
ZStack {
ForEach(0...randomCircle, id: \.self) { item in
Circle()
.foregroundColor(.white)
.opacity(0.25)
.frame(width: randomSize())
.position(
x: randomCoordinate(),
y: randomCoordinate()
)
.scaleEffect(isAnimating ? randomScale() : 1)
.onAppear {
withAnimation(
.interpolatingSpring(stiffness: 0.25, damping: 0.25)
.repeatForever()
.speed(randomSpeed())
.delay(randomDeley())
) {
isAnimating = true
}
}
}
} //: ZSTACK
.frame(width: 256, height: 256)
.mask(Circle())
.drawingGroup()
}
}
struct MotionAnimationView_Previews: PreviewProvider {
static var previews: some View {
MotionAnimationView()
.background(
Circle()
.fill(.teal)
)
}
}
수정
import SwiftUI
struct MotionAnimationView: View {
@State private var randomCircle: Int = Int.random(in: 6...12)
@State private var isAnimating: Bool = false
func randomCoordinate() -> CGFloat {
return CGFloat.random(in: 0...256)
}
func randomSize() -> CGFloat {
return CGFloat(Int.random(in: 4...80))
}
func randomScale() -> CGFloat {
return CGFloat(Double.random(in: 0.1...2.0))
}
func randomSpeed() -> Double {
return Double.random(in: 0.05...1.0)
}
func randomDeley() -> Double {
return Double.random(in: 0...2)
}
var body: some View {
ZStack {
ForEach(0...randomCircle, id: \.self) { item in
Circle()
.foregroundColor(.white)
.opacity(0.25)
.frame(width: randomSize())
.position(
x: randomCoordinate(),
y: randomCoordinate()
)
.scaleEffect(isAnimating ? randomScale() : 1)
.onAppear {
withAnimation(
.interpolatingSpring(stiffness: 0.25, damping: 0.25)
.repeatForever()
.speed(randomSpeed())
.delay(randomDeley())
) {
isAnimating = true
}
}
}
} //: ZSTACK
.frame(width: 256, height: 256)
.mask(Circle())
.drawingGroup()
}
}
struct MotionAnimationView_Previews: PreviewProvider {
static var previews: some View {
MotionAnimationView()
.background(
Circle()
.fill(.teal)
)
}
}
공로를 돌리거나 저자를 표시하는 주석
주석으로 처리한 코드
HTML 주석
주석안에 HTML 태그 요소들을 다는 행위 🙅🏻♀️
전역 정보
모호한 관계
주석과 주석이 설명하는 코드는 둘 사이의 관계가 명백해야 함.
독자가 주석과 코드를 읽어보고 무슨 소린지 알아야 함.
e.g. apache - commons
/*
* 모든 픽셀을 담을 만큼 충분한 배열로 시작한다(여기에 필터 바이트를 더함).
* 그리고 헤더 정보를 위해 200바이트를 더한다.
*/
this.pngBytes = new byte[((this.width + 1) * this.height *3) + 200];
함수 헤더
짧은 함수는 긴 설명이 필요 없다.
→ 짧고 간결, 한 가지만 수행 → ⭐️ 이름을 잘 붙인 함수가 주석으로 헤더를 추가한 함수보다 훨씬 좋다.
비공개 코드에서 Javadocs
예제 ( 90p 4-7, 4-8 코드 읽고 비교하기)
'Computer Science' 카테고리의 다른 글
[ Clean Code ] 클린코드 시리즈 - 클래스 (0) | 2024.01.14 |
---|---|
[ Clean Code ] 클린코드 - 단위테스트(Unit Test) (0) | 2024.01.13 |
[ Clean Code ] 클린코드 시리즈 - 함수 (1) | 2023.12.23 |
[ Clean Code ] 클린코드 시리즈 (with Swift 가이드라인) (2) | 2023.12.14 |
[ 정보처리기사 ] 프로그래밍 언어 활용 - Java 관련 문법 (0) | 2022.03.20 |