객체지향 프로그래밍 (객체지향 생활체조원칙)
[Refactoring] 객체지향 생활 체조 원칙
한 메서드에 오직 한 단계의 들여 쓰기만 한다
- 코드에 너무 많은 들여쓰기가 있다면, 가독성과 유지 보수에 좋지 않은 경우가 많다.
- 들여쓰기가 여러 개 존재할 경우, 해당 메서드는 여러 가지 일을 할 가능성이 있다. 맡은 일이 적을수록 재사용성이 높고 디버깅이 용이하기 때문에 이 원칙은 하나의 메서드는 하나의 일만 해야한다는 의미와도 연결됨
class Person {
func eat() -> [Int] {
var something = [Int]()
for i in 0...10 {
for j in 0...10 {
something.append(i + j)
}
}
return something
}
}
- 위와 같이 서로 다른 수준에서 다양한 조건을 갖거나, 2중 Loop가 도는 경우 코드가 간단하면 괜찮지만 복잡한 코드라면 이해라기 어렵다.
- 한 메서드에는 오직 한 단계의 들여 쓰기만 지키도록 하기 위해서는 메서드의 내부를 더욱 작게 나누어야 한다.
class Person {
func eat() -> [Int] {
var something = [Int]()
for i in 0...10 {
a(somthing, i)
}
return something
}
func a(_ somthing: [Int], _ i: Int) {
for j in 0...10 {
something.append(i + j)
}
}
}
else문을 쓰지 않는다
func login(userName: String, password: String) {
if userRepository.checkValid(userName, password) {
print("Go homepage")
} else {
print("Failure Login)
}
}
- 대부분의 프로그래밍 언어에서는
if/else
를 지원한다. 기존 코드에 새로운 else를 추가하는 것이 조건을 추가하기 쉽지만 early return
문을 통해 다음과 같이 해결한다.
switch/case
구문 또한 분기 구문을 지양하여 코드를 간단 명료하게 만드는 것을 이야기 함
func login(userName: String, password: String) {
if userRepository.checkValid(userName, password) else {
print("Go homepage")
return
}
print("Failure Login \\(LoginError.invalidInfo)")
}
- 조건은
optimistic
(즉, 오류를 걸러내는 if 조건문이 있으면, 나머지 로직은 if문 이후의 기본 로직을 따르는 것)하거나, 또는 defensive
(기본 로직을 조건에 지정한 후 조건이 충족되지 않으면 오류 상태를 반환하는 것) 하게 접근할 수 있다. 바로 위의 코드는 checkValid로 타당성을 검증한 후, 타당하지 않으면 if문을 들어가지 않고 print
Error를 반환하니 defensive이다.
모든 원시 값과 문자열을 포장한다
- 간단하게 객체 내의 모든 원시 요소를 캡슐화하면 된다. 안티 패턴중 하나인 Primitive Obsession을 피하기 위해서 이다.
- 만약 사용하는 변수에 행동(behavior)이 포함된다면, 캡슐화 하여야 함
- 이런 것들을 **DDD(도메인 주도 개발)**에서는 특별히 VO(Value Object)라고 부른다.