스터디 정리!

코드 다듬기 : 로컬 함수와 확장

SeongukHeo11 2024. 3. 19. 17:23

이번주 스터디 시간에선 Kotlin in Action의 3-6 부분인 로컬 함수와 확장에 대해 공부를 했습니다!

처음엔 이해하기 어려웠지만 발표를 하며 다른 팀원들에게 설명을 해야하다보니 

좀 더 철저히 공부를 하게 되었고 어느정도 이해를 할 수 있게 되었습니다!(TMI,,,ㅎ)

 

우선 로컬 함수가 뭔지 먼저 알아보겠습니다!

 

 

로컬 함수란?

 

로컬 함수는 자신이 속한 바깥 함수의 모든 파라미터와 변수를 사용할 수 있는 함수입니다

그렇기 때문에 불 필요한 파라미터들을 없애 줄 수 있습니다!

 

이렇게만 보시면 저게 무슨 말이지..? 왜 써야하는거지? 싶으실 수도 있습니다

저 역시도 그랬구요,,

그렇다면 문제를 하나 내겠습니다! 

많은 개발자들이 말하는 좋은 코드란 어떤 코드일까요~?

 

 

정답은 바로 중복이 없는 코드입니다!

사실 좋은 코드에는 여러가지가 있겠지만 오늘 배운 로컬 함수를 사용하면

중복이 없는 코드를 만들 수가 있기 때문에 정답으로 뽑았습니다!

 

 

 

DRY 원칙이란?

 

이러한 이유로 로컬 함수에는 DRY원칙 이라는 이름도 붙어져 있는데 

이는 Don't Repeat YourSelf의 약자로써

반복하지 말아라! 라는 의미를 가지고 있습니다.

 

만약 제가 자바를 이용해서 개발을 한다면 이러한 DRY 원칙을 피하기는 쉽지 않습니다

왜냐하면 

 

메서드 추출 리팩토링을 적용하여 긴 메서드를 부분부분 나눠서 각 부분을 재활용하는 방법을 사용할 수 있지만

그렇게 코드를 리팩토링하면 클래스 안에 작은 메서드가 많아지고

각 메서드 사이의 관계를 파악하기 힘들어서 코드를 이해하기 더 어려워질 수 있기 때문입니다.

 

하지만!!!!!!!

저는 지금 코틀린을 배우고 있고 코틀린에는 더 깔끔한 해법이 있습니다

코틀린에서는 함수에서 추출한 함수를 원 함수 내부에 중첩 시킬 수 있습니다

이렇게 한다면 문법적인 부가 비용을 들이지 않고도 깔끔하게 코드를 조직할 수 있습니다!!

 

이제 예문을 통해 봐보겠습니다

 

 

 

예문!


1, 코드의 중복을 보여주는 예제

//코드의 중복을 보여주는 예제
class User(val id:Int, val name:String, val address:String)

fun saveUser(user:User){
    if (user.name.isEmpty()){
        throw IllegalArgumentException(
            "${user.id}님 이름 입력 오류입니다"
        )
    }
    if (user.address.isEmpty()){
        throw IllegalArgumentException(
            "${user.id}님 주소 입력 오류입니다"
        )
    }
    saveUser(User(1, "", ""))
    
}

 

이 코드의 경우 유효성 검사가 2번 밖에 없기 때문에 비교적 코드 중복이 많지 않지만

만약 10가지의 항목에 대해 검증이 필요할 경우 중복되는 코드가 넘쳐 나는 걸 보실 수 있습니다.

 

 

 

2, 로컬 함수를 사용해 코드 중복 줄이기

 

//로컬 함수를 사용해 코드 중복 줄이기
class User(val id:Int, val name:String, val address:String)

fun saveUser(user:User){
//한 필드를 정의하는 로컬 함수를 정의한다
    fun validate(user: User, value:String ,fieldName:String){
        if (value.isEmpty()){
            throw IllegalArgumentException(
                "${user.id}"
            )
        }
        //로컬 함수를 호출해서 각 필드를 검증한다
        validate(user, user.name, "Name")
        validate(user, user.address, "Address")
    }

}

 

처음 보여드린 코드보단 훨씬 간단해진 느낌이 듭니다 !

하지만 아직 User 객체를 로컬 함수에게 하나하나 전달해야 한다는 점이 아쉽긴 합니다,,

그래서 여기서 로컬 함수의 특성을 사용해보겠습니다

로컬 함수는 자신이 속한 바깥 함수의 모든 파라미터와 변수를 사용할 수 있기 때문에

이러한 성질을 이용해 불필요한 User파라미터를 없애보겠습니다!

 

 

 

3, 로컬 함수에서 바깥 함수의 파라미터로 접근하기

 

//로컬 함수를 사용해 코드 중복 줄이기
class User(val id:Int, val name:String, val address:String)

fun saveUser(user:User){
    fun validate(value:String, fieldName:String){
        if (value.isEmpty()){
            throw IllegalArgumentException(
                "Can't save user ${user.id} : empty $fieldName")
        }
    }

    validate(user.name, "Name")
    validate(user.address, "Address")

}

 

2번 예제와 비교했을 때 User 파라미터를 제거했음에도

잘 동작하는 걸 보실 수 있습니다!

 

 

 

 

 

4, 검증 로직을 확장함수로 추출하기

//검증 로직을 확장 함수로 추출하기
class User(val id:Int, val name:String, val address:String)

fun User.validatrBeforesave(){
    fun validate(value:String, fieldName:String){
        if (value.isEmpty()){
            throw IllegalArgumentException(
                "Can't save user ${user.id} : empty $fieldName")
        }
    }

    validate(name, "Name")
    validate(address, "Address")
}



fun saveUser(user:User){
    user.validatrBeforesave()
    
    //user를 데이터베이스에 저장한다

}

위에 코드 보시면 User를 확장 함수로 만들어서 검증 로직을 구현해봤습니다!

저번 스터디 시간 때 확장 함수에 대해 발표를 했었는데

여기서 복습을 다시 해보니 확실히 이해가 잘됐습니다!

 

 

최종 정리

 

주로 코틀린에서 로컬 함수를 사용하는 이유는

1, 코드 가독성 향상 : 로컬 함수를 사용하게 되면 해당 함수가 사용되는 범위를 한정할 수 있기 때문에

함수가 어디에서 호출되는지 명확하게 파악할 수 있습니다!

 

2, 코드 재사용성 : 로컬 함수는 외부에서 접근할 필요가 없는 경우에 사용됩니다.

따라서 해당 함수가 다른 곳에서 사용되지 않고 특정 범위 내에서만 필요한 경우에 로컬 함수를 활용하여

코드를 모듈화하고 재사용성을 높일 수 있습니다.

 

하지만 중첩된 함수의 깊이가 깊어지면 코드를 읽기 어려워질 수 있으므로(오히려 가독성이 나빠진다),

일반적으로 한 단계의 중첩만을 권장합니다!!

 

 

느낀점

 

오늘까지 해서 Kotlin in Action을 활용한 스터디가 3주차인데 3번의 발표를 준비하다보니

문득 사람들은 더 깔끔한 코드, 다른 사람이 읽기 쉬운 코드를 만들기 위해 정말 많이 노력한다는 걸 깨닫게 되었습니다.

처음 앱 스쿨을 시작할 때만 해도 굳이 깔끔한 코드를 짜야해? 그냥 기능이 잘 동작만 하면 되는 거 아니야? 라고

생각했었는데 이제 슬슬 다른 분들과의 협업을 준비하다 보니

이런 내용 하나하나 내가 어떻게 사용할 수 있는 지를 생각하게 되는 거 같습니다.

아직도 많이 어렵고 발표 준비의 절반 이상을 구글링으로 찾아보는 거 같은데

점점 더 발전할 수 있도록 노력해야 할 거 같습니다!