객체 | 코틀린 입문 EP.1

@장태근· January 01, 2025 · 8 min read

  • 객체
  • 클래스
  • 프로퍼티
  • 생성자
  • 가시성 변경자
  • 패키지
  • 테스트
  • 코틀린은 왜 그럴까?

객체는 모든 곳에 존재한다

  • 클래스는 상태와 행동을 정의하여 사용자 정의 타입이 된다.
  • 멤버(member)란 객체에 소속된 프로퍼티, 함수를 의미한다.

    • 객체에 소속된 일원이다.
  • 인스턴스는 객체 생성을 통해 만들어진 결과물이다.
  • 멤버 함수 호출은 메시지를 보내는 행동과 같다.
  • 코틀린은 명시적으로 타입 변환이 필요하다.

    • 컴파일러가 임의의 타입을 변환할 때 생기는 혼란을 피하기 위해 내린 결정이다.
  • 이름 짓기는 여전히 중요하다. 이름을 신경 쓰면 이해하기 쉬운 코드에 한 걸음 다가갈 수 있다.

클래스 만들기

  • 필요한 개념만 표현하는 '객체'를 떠올리는 행동이 문제 해결의 시발점이다.
  • class 키워드를 사용하여 클래스를 선언한다.

    • 헤더와 본문은 선택 사항이다.
    • 복잡한 클래스 선언이 필요하면 본문을 구성한다.
  • 멤버 함수는 클래스에 속한 함수다. 최상위(top-level) 함수는 클래스에 속하지 않은 함수다.

    • 함수를 선언하기 위해 class가 필요한 자바와 달리 최상위에 선언할 수 있다.
  • 함수가 호출되는 동안 다른 멤버에 접근할 수 있다.
  • this 키워드가 존재한다. 하지만 가급적 불필요한 this 사용을 권장하지 않는다.

프로퍼티

프로퍼티(property)는 클래스에 속한 var, val이다.

  • 멤버 함수는 점 표기법 외에도 자신이 속한 객체의 프로퍼티에 접근할 수 있다.

    • this 키워드를 사용할 수 있지만 권장하지 않는다.
  • 가변(var, mutable) 최상위 프로퍼티 선언하기는 안티 패턴이다.

    • 프로그램이 복잡할수록 공유된 가변 상태를 추론하기 어렵다.
  • var를 사용하면 참조 대상을 다른 대상으로 변경할 수 있다.
  • val를 사용하면 참조 대상을 변경할 수 없다.
  • 가변성이란 내부 상태를 바꿀 수 있는 상태를 의미한다.

생성자

객체를 효과적으로 초기화하는 기본적인 방법

  • 클래스 본문 밖에서도 생성자 파라미터에 접근하기 위해서는 var, val 키워드를 사용해야 한다.

    • 식별자가 프로퍼티로 변경된다.
  • override는 이미 정의된 함수를 재정의 하겠다는 의도를 전달한다.

가시성 변경자

작성한 코드를 다시 보면 더 좋은 방법이 떠오른다.

  • 리팩터링(refactoring)을 하는 이유는 코드를 다듬어 유지 보수하기 좋은 코드를 작성하기 위해서다.
  • 소비자는 버전이 변경돼도 기능이 똑같이 동작하길 원한다. 새로운 코드를 작성하고 싶지 않다. 생산자도 마찬가지다. 변경하는 내용이 소비자에게 영향을 끼치지 않는다는 확신을 가지고 개선하고 싶다.

    • 확신을 주는 장치는 자동화된 테스트다.
  • 소프트웨어를 설계할 때 변경해야 하는 요소와 유지되어야 하는 요소를 분리해야 한다.
  • 가시성 변경자를 통해 영역을 분리한다.
  • private는 주로 클래스 멤버에 사용한다.
  • 필요한 함수와 클래스만 외부에 공개하고 가능한 많은 요소를 private로 선언한다.

    • 리모컨을 사용할 때 내부의 구조를 알지 못해도 사용할 수 있듯이 클라이언트에게 필요한 부분만 공개하고 내부 구현을 숨긴다.

패키지

DRY(Don't Repeat Yourself)

  • 같은 내용이 반복될 때 이를 수정, 개선하기 위해서는 더 많은 고통을 인내해야 한다.

    • 중복은 실수 할 여지가 크다.
  • import를 사용하여 코드를 재사용한다.
  • 패키지(package)는 연관 있는 코드를 모아둔 공간이다.
  • as 키워드를 사용하여 import 할 때 이름을 변경할 수 있다.
  • 패키지 이름은 소문자만 사용한다.

테스트

프로그램을 빠르게 개발하기 위해서는 지속적인 테스트가 필수다.

  • 코드의 동작을 검증할 때 println()은 부실한 방법이다. 매번 출력을 자세히 살펴보고 의식적으로 확인해야 한다.

    • 오류를 찾는데 시각적인 검사를 신뢰할 수 없다.
  • 테스트를 배우면 테스트가 포함되지 않은 코드를 보면 점점 불편해지고, 테스트가 없는 코드는 틀린 코드라고 정의하기도 한다.

테스트 프레임워크

  • JUnit: 자바에서 가장 널리 쓰인다. 코틀린에서도 유용하다.
  • Kotest: 코틀린 전용으로 설계됐다. 언어의 여러 기능을 살려 작성 가능하다.
  • Spek: 명세 테스트(specification test)라는 다른 형태의 테스트를 제공한다.

테스트는 프로그램의 일부분이다

  • 소프트웨어 개발 과정에 테스트가 포함되어 있어야 자연스럽고 효과적이다.

코틀린은 왜 그럴까?

사소하지만 왜 그럴지 나름의 근거로 추론한다.

  • Member function vs. Method
  • Visibility modifier vs. Access modifier
  • JUnit vs. Kotest

Member function vs. Method

클래스에 소속된 함수는 보통 메서드(method)라고 부른다. 하지만 코틀린 공식 문서는 '멤버 함수(member function)'라고 지칭한다.

코틀린은 class 없이도 최상위(top-level) 함수를 선언할 수 있다. 더불어 메서드도 사실 함수가 아닐까? 클래스에 소속된 함수는 멤버 함수, 소속되지 않은 함수는 함수라고 부르면 자연스럽다.

마치며

<참고 자료>

@장태근
개발자. 명료한 생각이 명료한 글이 된다.