함수
SPR : 함수의 역할은 하나만 할당한다.
하나의 함수에 역할이 많아지면 오류 발생 가능성이 커지고, 가독성이 떨어지며 테스트를 진행하기 어렵다.
따라서 하나의 함수에 많은 로직을 넣지 말자.
// as-is
func createUser(email, password) -> Bool {
if email.contains("@") || password.contains("@") {
//error
return false
}
var user = User()
user.email = email
user.password = password
database.add(user)
emailClient = EmailClient()
emailClient.setConfig()
emailClient.send(email, "회원가입이 완료되었습니다")
return true
}
// to-be
func createUser(email: String, password: String) -> Bool { // 주요 로직 실행 함수
validateCreateUser(email, password)
user = BuildUser(email, password)
saveUser(user)
sendEmail(email)
return true
}
// 역할 별로 함수를 작성한다.
func validateCreateUser(_ email: String, _ password: String) { }
func Builduser() { }
func saveUser(_ user: User) { }
DRY (Don’t repeat yourself) : 반복하지 말자
반복되는 코드가 많아지면, 전체 코드가 많아진다.
특정 부분에 변경사항이 생기면, 공통적인 모든 부분을 변경해줘야한다.
이에 관심사를 잘 분리하고 의존성을 줄이기 위해 반복되는 코드를 하나의 함수로 만들어서 사용하자.
// as-is
func createUser(email: String, password: String) {
if email.contains("@") || password.contains("@") {
//error
return false
}
// code...
}
func updateUser(email: String, password: String) {
if email.contains("@") || password.contains("@") {
//error
return false
}
// code...
}
// to-be
func validateCreateUser(_ email: String, _ password: String) -> Bool {
if email.contains("@") || password.contains("@") {
//error
return false
}
}
func createUser(email, password) {
guard validateCreateUser(email, password) else { ... }
// code..
}
func updateUser(email, password) {
guard validateCreateUser(email, password) else { ... }
// code..
}
파라미터 수는 적게 유지하자
// as-is
func saveUser(userName: String, email: String, password: String, createAt: Int) {
...
}
// to-be
func saveUser(user: User) {
...
}
사이드 이펙트를 잘 핸들링하자
사이드 이펙트란? (Side Effect)
함수가 실행되었을 때, 함수 이외의 어떤 것들에 변화를 주는 것을 의미한다.
이를 잘 다루지 못하면 예측하지 못하는 문제가 발생할 수 있다.
A, B, C, D라는 함수가 있을 때, A 실행시 B또는 C함수에도 영향을 주는 경우가 Side Effect라고 한다.
// 사이드 이펙트가 없는 경우 func getUser(email, password) -> User { let user = User(email, password) return user } // 사이드 이펙트가 있는 경우 func updateUser(user) { var user = getUser(user.email, user.password) user.eail = "newEmail" // 인자로 받은 user 객체를 업데이트한다 return user } // 사이드 이펙트가 있는 경우 func createUser(email, password) { let user = User(email, password) dbSession() // 외부 DB 세션에 변화를 준다. }
사이드 이펙트 핸들링하는 방법
코드를 통해 사이드이펙트를 예측할 수 있도록 네이밍을 잘 해야한다.
update, set 등 직관적인 prefix를 붙여 암시한다.
함수의 사이드 이펙트가 있는 부분과 없는 부분으로 나누어 관리한다.
명령과 조회를 분리하는 CQRS 방식이 존재한다.
명령(Command) : 사이드이펙트가 존재
조회(Read) : 사이드 이펙트가 없다
하나의 함수에 명령과 조회 모두가 실행된다면, 사이드이펙트 덩어리가 된다. 이를 함수나 클래스로 영역을 나누어 분리시킨다.
순수함수 형태로 사용하여 직관적으로 표현하고, 에러를 방지한다.
update 함수를 남발하지 않는다.
// as-is var carts = [Cart]() // 사이드이펙트 발생 func addCart(product: Cart) { casts.append(product) // 외부에 있는 carts의 변경 } product = Product() addCart(product: product)
// to-be var carts = [Cart]() // 사이드이펙트가 없는 순수함수 func getAddCart(product: Cart) -> [Cart] { return carts + product } carts = getAddCart(product) // carts를 재선언한다.
Last updated