프로그래밍 책

재사용, 일반화가 쉬운 코드 #좋은코드나쁜코드 #9장

열심히 사는 우진 2023. 4. 5. 22:27
반응형

* 본 아티클은, '좋은 코드 나쁜 코드' 9장을 기반으로 작성된 글입니다.

 

 

 

 


간결한 추상화 계층, 모듈화를 통해 재사용성과 일반화성이 높은 코드를 작성할 수 있다.

그리고 추가적으로 재사용성과 일반화성이 높은 코드를 작성하는 방법이 있다.

아래에서 그 방법을 알아본다.

가정을 주의하라

코드 작성 시, 어떤 가정을 통해 코드를 단순하고 효율적으로 작성할 수 있다.

하지만 이는 버그의 시작이 될 수 있다.

class Article {
	private List<Section> sections;
	...
	
	List<Image> getAllImages() {
		for (Section section : sections) {
			if (section.containsImages()) {
				// 기사 내에 이미지를 포함하는 섹션은 최대 하나만 있다.
				return section.getImages();
			}
		}
		return [];
	}
}

위의 코드처럼, 기사 내에 이미지를 포함하는 섹션이 최대 하나만 있다는 가정을 기반으로 코드를 작성한다면,

이미지 포함 섹션이 여러 개인 다른 상황에서 재사용이 불가능해진다.

섣부른 최적화

코드 최적화는 일반적으로 비용이 든다. 최적화된 해결책을 구현하는 데 시간이 필요하며, 그 결과로 코드의 가독성이 떨어지고 유지보수성이 떨어질 수 있다.

특정 가정을 기반으로 코드가 작성된다면 견고함이 떨어질 수도 있다.

게다가 최적화는 보통 수천에서 수백만 번 실행되는 코드에 대해 이루어질 때 상당한 이점ㅇ미 있다.

따라서, 대부분의 경우에는 큰 효과가 없는 코드 최적화를 하느라 애쓰기보다는

코드의 가독성, 유지보수성, 견고함에 집중하는 것이 좋다.

코드의 어떤 부분이 굉장히 많이 실행되고,

그 부분을 최적화하는 것이 성능 향상에 큰 효과를 볼 수 있다는 것이 명백할 때라야 최적화 작업을 해도 무방하다.

가정의 강제적 확인

특정 가정을 통해 코드가 엄청나게 간결해진다면,

해당 가정이 맞지 않을 경우 빠르게 실패하는 코드를 작성할 수 있다.

분기 또는 체크를 통해 예외를 발생시킬 수 있겠다.

전역 상태를 주의하라

전역 상태는 재사용성이 낮다.

static 필드의 사용을 지양하고, 인스턴스 간 의존성 주입을 통해 문제를 해결해야 한다.

기본 반환값을 적절하게 사용하라

기본값을 사용자 친화적 소프트웨어를 위한 좋은 방법이지만,

너무 낮은 층위에서 남발하는 경우 적절하게 사용하기 어렵다.

낮은 층위의 기본 반환값

낮은 층위의 코드가 기본 반환값을 가질 경우, 그것을 사용하는 많은 상위 코드들에서 영향을 받는다.

상위 코드의 모든 상황에서 같은 기본 반환값을 원할 확률은 낮다.

따라서, 상위 코드에서 원하는 기본 반환값을 직접 제공하는 것이 올바르다.

필요한 매개변수만 받아라

class TextOptions {
	private final Font font;
	private final Double fontSize;
	private final Double lineHeight;
	private final Color textColor;

	TextOptions(Font font, Double fontSize, Double lineHeight, Color textColor) {
		this.font = font;
		this.fontSize = fontSize;
		this.lineHeight = lineHeight;
		this.textColor = textColor;
	}
	
	Font getFont() { return font; }
	Double getFontSize() {	return fontSize; }
	Double getLineHeight() {	return lineHeight; }
	Color getTextColor() {	return textColor; }

위와 같이 정의된 TextOptions을 사용하는 클래스 TextBox가 있다. (아래 코드)

class TextBox {
	private final Element textContainer;
	...
	
	void setTextStyle(TextOptions options) {
		setFont(...);
		setFontSize(...);
		setLineHeight(...);
		setTextColor(options);
	}
	
	void setTextColor(TextOptions options) {
		textContainer.setStyleProperty(
				"color", options.getTextColor().asHexRgb());
	}
}

setTextColor 메서드는 TextOptions를 매개변수로 받지만, textColor 필드만 사용한다.

지금 같은 코드에서는 문제가 없지만,

setTextColor 메서드를 재사용하려고 할 때, TextOptions를 입력해야 함은 적잖이 당황스러울 것이다.

이럴 경우, 아래와 같이 필요한 것만 매개변수로 받도록 수정이 필요하다.

void setTextStyle(TextOptions options) {
	setFont(...);
	setFontSize(...);
	setLineHeight(...);
	setTextColor(options.getTextColor());
}

void setTextColor(Color color) {
	textContainer.setStyleProperty("color", color.asHexRgb());
}

이제 setTextColor를 재사용할 때, 필요한 Color만 넣어주면 되어 재사용성이 크게 증가했다.

제네릭의 사용을 고려하라

타입에 종속된 기능, 로직이 없는 일반적인 코드의 경우,

제네릭을 사용하면 일반화성을 크게 증가시킬 수 있다.

반응형