ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • public, private은 언제 사용해야 할까?
    Java & Kotlin 2022. 4. 24. 18:19
    반응형

    1) 서론

    이번에 작성할 글은 단순히 고민의 흐름을 기록하는 글입니다.

     

    그리고 나름대로 생각을 정리했지만, 결론을 내리지는 않습니다. 오히려 같은 고민을 하는 분들의 댓글을 기다리는 글입니다.

     

    이 글에서 이루어지는 고민은 "public과 priavte은 언제 어떻게 사용해야 할까?"입니다.

     

    특정 기능을 개발하는데, 습관적으로 모든 함수를 private으로 작성하고 있는 제 자신을 발견했습니다. 그러다 보니 모든 기능의 테스트를 할 수 없었는데요.

     

    이러한 방식이"정말로 이게 맞을까?"라는 의문으로 시작된 고민입니다.


    2) 기본적인  public, private 개념의 차이

    대부분의 언어에서 public, private 개념과 사용법은 비슷할 것입니다. 이 글에서는 Kotlin을 예제로 사용합니다.

     

    public, private 키워드는 "접근 제어자(Access Modifier)"라고 불리는데요. 즉 "어디까지 접근을 허용하는지, 제어에 대한 키워드"입니다.

     

    아래와 같이 두 개의 파일이 있습니다.

     

    아래에서는 외부에서 접근이 가능한 public을 사용합니다.

    fun main() {
        val hello = Hello()
        print(hello.sayHelloToWorld()) // public function
    }
    class Hello {
        // public function
        fun sayHelloToWorld(): String {
            return "Hello World"
        }
    }

     

    아래에서는 sayHelloToWorld 함수를 private 키워드로 변경합니다.

    private 키워드는 같은 클래스에서만 접근할 수 있습니다. 당연히, 컴파일 오류가 발생합니다.

    class Hello { 
        // private function
        private fun sayHelloToWorld(): String {
            return "Hello World"
        }
    }

    컴파일 오류


    3) 그래서 무엇을, 어떻게 제어해야 하죠?

    가장 큰 고민입니다.

     

    기본적으로 객체지향은 절차 지향에서 벗어나, 객체들끼리 메시지를 주고받고 의사소통하는 방식입니다. 그리고 이때 의사소통을 할 수 있는 범위를 지정하는 것이 접근 제어자인데요.

     

    앞서 언급한, 접근 제어자라는 이름을 다시 생각해봅니다. 코딩을 하면 무심코 아무렇지 않게 사용하지만, 정말로 객체들끼리 의사소통의 "접근""제어"하는 목적으로 사용하고 있는 것인가, 의문이 생깁니다.

     

    그렇다면 무엇을, 어떻게 제어할 수 있을지 고민해봅니다. 즉, 이름에 맞게 어떤 함수나 비즈니스 로직을 외부에서 접근 허용하고, 비허용할 것인지 고민해봅니다.

    3. 1) 외부에 무엇을 공개할 것인가? 너의 역할은 무엇이냐?

    예를 들어 동일한 스크래핑을 하는 기능이 존재한다고 가정합니다. 해당 기능을 사용자에게 온디멘드(on demand)로 제공할 수도 있고, 스케줄링되어 주기적으로 동작할 수도 있습니다.

     

    동일한 동작을 하는 기능이 분리되어 존재할 필요는 없습니다. 공통적으로 받을 수 있는 파라미터를 정의하고, 이에 따라 다르게 사용하면 됩니다. 이때 기능뿐만 아니라, 사용될 파라미터도 외부에 공개되어야 합니다. 왜냐하면 해당 객체는 사용자와 직접적으로 대화를 해야 하는 "역할"을 가지고 있기 때문입니다.

     

    하지만 스크래핑 기능이 세부적으로 어떻게 동작하는지, 내부 로직을 공개할 필요는 없습니다. 만약 각각의 동작 흐름을 외부에 공개하고, 이를 사용한다면 동작하지 않을 확률이 높을 것입니다. 즉, 쉽게 동작하지 않을 수 있는 기능을 외부에 공개하는 것은 불안정하고 위험합니다. 만약 특정 경우에 스크래핑이 중단되는 로직이 있고, 이것만 외부에서 임의로 호출한다면 다른 기능에 영향을 미칠 수 있습니다.

     

    그리고 세부적인 로직은 이를 수행시켜주는 객체와 함수들끼리만 의사소통 하는 역할로 제한하게 됩니다.

     

    그렇기 때문에 trigger 역할을 할 수 있는 큰 함수는 public으로서 공개하고, 내부에서 서로 대화하는 작은 단위의 함수들은 private으로 감추기로 결정했습니다.

    3. 2) 그렇다면, 테스트는 어떻게 해야 하나요?

    당연하게도 private 함수는 테스트할 수 없습니다. 해당 함수는 동일한 클래스에 존재하지 않을 테니까요.

     

    물론 private 테스트를 지원하는 라이브러리도 존재하고, 임의로 public 함수로 감싸는 방법도 있습니다. 하지만 이것은 private 함수를 테스트하는 본질에서 벗어난 방법이라고 생각합니다. 애초에 외부에 공개하지 않고, 역할을 제한해서 사용되어야 하는 것을 임의로 드러내서 사용하는 것이기 때문입니다.

     

    TDD, 리팩토링으로 유명한 켄트 백(Kent Beck)은 private 함수 테스트에 대해 아래와 같이 말했습니다.

    should i test private methods
    답변 - NO!

     

    켄트 백은 private 함수는 테스트하지 말라고 합니다.

     

    그렇다면 수많은 private 함수는 테스트를 하지 말아야 할까요? 일단 돌려보고, 디버깅을 해보면 되는 걸까요?

     

    사실 이 부분에 대해 답을 내리지는 못 했는데요.

     

    나름대로 생각한 방법은, 진정한 의미의 TDD를 할 수 있어야 private 로직도 테스트 가능할 것 같다는 생각 합니다.

     

    (물론 TDD에 대한 정의도 사람마다 다르겠지만요)

     

    실제 함수를 호출해서 테스트하는 것이 아닌, 비즈니스 로직을 우선 작성하여 테스트합니다. 그리고 해당 로직의 테스트가 통과했을 때 실제 서비스 함수를 작성해야 하지 않을까 생각합니다. 즉, 우선 테스트 코드를 작성하고 실제 로직에 반영하는 방식입니다.

     

    물론 이렇게 하더라도 실제 함수 자체를 테스트하는것은 아닙니다. 다만 최소한 로직은 테스트할 수 있지 않을까 생각이 듭니다.


    4) 결론

    결론을 내보려고 매우 고민을 했습니다.

     

    하지만 제 스스로 정의를 내리고, 결론을 내리기엔 다양한 의견이 있을 것 같다는 생각을 했습니다.

     

    그럼에도 불구하고 public, private 키워드 사용에 대한 저의 생각은 이렇습니다.

    • 외부에 무엇을 공개할 것인가? 역할은 무엇인가?
    • 공개가 되었을 때 충분히 안정적인가?
    • private을 사용한다면, 테스트를 통과한 비즈니스 로직인가?

     

    다양한 의견 환영합니다!


    5) 참고 문헌

    https://bit.ly/3EW7xsZ

    https://jojoldu.tistory.com/588

    반응형

    댓글

Designed by Tistory.