Kim-Baek 개발자 이야기

Kotlin 기초 완벽 가이드 | Data Class, Named Parameters로 코드 가독성 3배 높이는 법 🚀 본문

개발/java basic

Kotlin 기초 완벽 가이드 | Data Class, Named Parameters로 코드 가독성 3배 높이는 법 🚀

김백개발자 2025. 11. 30. 22:22
반응형

이 글을 읽으면: Kotlin의 기본 문법인 Data Class, Named Parameters, Primary Constructor를 실전 예제와 함께 배울 수 있습니다. Java 개발자라면 특히 주목! 코드량을 50% 줄이는 마법을 경험하세요.


📌 목차

  1. Data Class란? - 10줄 코드를 1줄로
  2. Named Parameters로 가독성 높이기
  3. Primary Constructor 완벽 이해
  4. 실전 예제로 배우기
  5. Java vs Kotlin 비교

1. Data Class란? - 10줄 코드를 1줄로

😫 Java에서 DTO 만들 때 이런 경험 있으신가요?

// Java - 끔찍한 보일러플레이트 코드
public class User {
    private String name;
    private int age;
    private String email;
    
    public User(String name, int age, String email) {
        this.name = name;
        this.age = age;
        this.email = email;
    }
    
    // Getter 3개
    public String getName() { return name; }
    public int getAge() { return age; }
    public String getEmail() { return email; }
    
    // Setter 3개
    public void setName(String name) { this.name = name; }
    public void setAge(int age) { this.age = age; }
    public void setEmail(String email) { this.email = email; }
    
    // equals()
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return age == user.age &&
               Objects.equals(name, user.name) &&
               Objects.equals(email, user.email);
    }
    
    // hashCode()
    @Override
    public int hashCode() {
        return Objects.hash(name, age, email);
    }
    
    // toString()
    @Override
    public String toString() {
        return "User{" +
               "name='" + name + '\'' +
               ", age=" + age +
               ", email='" + email + '\'' +
               '}';
    }
}

코드 라인 수: 약 50줄 😱

✨ Kotlin Data Class로 단 1줄로 끝내기

data class User(
    val name: String,
    val age: Int,
    val email: String
)

코드 라인 수: 5줄 (98% 감소!) 🎉


2. Data Class의 놀라운 자동 생성 기능

2.1 자동으로 생성되는 메서드들

Data class 키워드 하나로 다음 메서드들이 자동 생성됩니다:

메서드 기능 Java 비교

equals() 객체 동등성 비교 직접 작성 필요
hashCode() 해시코드 생성 직접 작성 필요
toString() 객체 문자열 표현 직접 작성 필요
copy() 객체 복사 ❌ 없음
componentN() 구조 분해 선언 ❌ 없음

2.2 실전 예제 - 서비스 생성 요청 DTO

// 실무에서 자주 사용하는 Data Class 예제
data class ItgServiceCreateRequest(
    val name: String,                    // 서비스 이름
    val catalogPath: CatalogPath,        // 카탈로그 경로
    val description: String,             // 서비스 설명
    val planner: List<String>? = null,   // 기획자 목록 (선택)
    val admin: String,                   // 관리자
    val member: List<String>,            // 멤버 목록
    val recoveryPlanUrl: String? = null  // 복구 계획 URL (선택)
)

💡 이 코드의 장점

  1. 한눈에 파악 가능: 모든 필드가 생성자에 명시
  2. Null 안전성: ?로 null 가능 여부 명확히 표시
  3. 기본값 지원: = null로 선택적 파라미터 구현
  4. 불변성: val 사용으로 데이터 보호

3. Named Parameters로 가독성 높이기

3.1 문제 상황 - Java의 혼란스러운 생성자 호출

// Java - 이게 뭘 의미하는지 알 수 있나요?
User user = new User("김철수", 30, "kim@example.com");
// 🤔 30이 나이? 아니면 ID? 
// 🤔 세 번째 파라미터가 email이었나?

3.2 해결책 - Kotlin Named Parameters

// Kotlin - 명확하고 읽기 쉬운 코드!
val user = User(
    name = "김철수",
    age = 30,
    email = "kim@example.com"
)

✅ Named Parameters의 장점

  1. 가독성 향상: 파라미터 의미가 명확
  2. 순서 자유: 순서 바꿔도 OK
  3. 실수 방지: 잘못된 값 전달 위험 감소

3.3 실전 활용 - DTO 변환 함수

// 실무 코드 예제: Request를 DTO로 변환
fun toDto(catalogType: CatalogType) = ItgServiceCreateDto(
    catalogType = catalogType,
    name = name,
    description = description,
    parentId = catalogPath.depth2.id,
    planner = planner,
    admin = admin,
    member = member,
    recoveryPlanUrl = recoveryPlanUrl
)

왜 이렇게 쓰나요?

  • 각 파라미터가 무엇을 의미하는지 즉시 파악 가능
  • 나중에 파라미터 순서가 바뀌어도 코드 수정 불필요
  • 코드 리뷰가 쉬워짐

4. Default Parameters - 선택적 파라미터의 마법

4.1 Java의 불편함

// Java - 오버로딩 지옥
public User(String name, int age) {
    this(name, age, null);
}

public User(String name, int age, String email) {
    this(name, age, email, null);
}

public User(String name, int age, String email, String phone) {
    this.name = name;
    this.age = age;
    this.email = email;
    this.phone = phone;
}

4.2 Kotlin의 우아한 해결책

// Kotlin - 단 한 번의 정의로 모든 경우 처리
data class User(
    val name: String,
    val age: Int,
    val email: String? = null,
    val phone: String? = null
)

// 사용 예시
val user1 = User("김철수", 30)
val user2 = User("이영희", 25, email = "lee@example.com")
val user3 = User("박민수", 35, phone = "010-1234-5678")

💡 언제 사용하나요?

  • API 요청/응답 DTO: 선택적 필드가 많을 때
  • 설정 클래스: 기본값이 있는 설정 항목
  • Builder 패턴 대체: 복잡한 Builder 없이도 유연한 객체 생성

5. Primary Constructor - 생성자의 진화

5.1 기본 개념

// Primary Constructor - 클래스 선언과 동시에 정의
class ServiceController(
    private val serviceCatalogAppService: ServiceCatalogAppService,
    private val serviceValidation: ServiceValidation,
)

이것은 다음과 동일합니다:

// Java 동일 코드
public class ServiceController {
    private final ServiceCatalogAppService serviceCatalogAppService;
    private final ServiceValidation serviceValidation;
    
    public ServiceController(
        ServiceCatalogAppService serviceCatalogAppService,
        ServiceValidation serviceValidation
    ) {
        this.serviceCatalogAppService = serviceCatalogAppService;
        this.serviceValidation = serviceValidation;
    }
}

5.2 Spring Boot에서의 활용 - 의존성 주입

@RestController
@RequestMapping("/v1/services")
class ServiceController(
    private val serviceCatalogAppService: ServiceCatalogAppService,
    private val serviceValidation: ServiceValidation,
    private val securityService: SecurityService
) {
    
    @GetMapping
    fun getServices(): List<Service> {
        // serviceCatalogAppService 바로 사용 가능!
        return serviceCatalogAppService.getAllServices()
    }
}

✅ 장점

  1. 생성자 자동 생성: 필드 선언과 동시에 생성자 완성
  2. 불변성 보장: val로 선언하면 변경 불가
  3. DI 프레임워크와 완벽 호환: Spring, Dagger 등
  4. 코드 간결성: Java 대비 50% 이상 코드 감소

6. 실전 예제로 배우기

6.1 전체 흐름 이해하기 - 서비스 생성 프로세스

// 1단계: 클라이언트 요청 받기 (Data Class)
data class ItgServiceCreateRequest(
    val name: String,
    val catalogPath: CatalogPath,
    val description: String,
    val planner: List<String>? = null,  // Default Parameter
    val admin: String,
    val member: List<String>
) {
    // 2단계: DTO로 변환 (Named Parameters)
    fun toDto(catalogType: CatalogType) = ItgServiceCreateDto(
        catalogType = catalogType,
        name = name,
        description = description,
        parentId = catalogPath.depth2.id,
        planner = planner,
        admin = admin,
        member = member
    )
}

// 3단계: Controller에서 처리 (Primary Constructor)
@RestController
@RequestMapping("/v1/services")
class ServiceController(
    private val serviceCatalogAppService: ServiceCatalogAppService
) {
    
    @PostMapping
    fun createService(
        @RequestBody request: ItgServiceCreateRequest
    ): Response {
        // Named Parameters로 가독성 높은 호출
        return serviceCatalogAppService.createService(
            dto = request.toDto(CatalogType.TECH),
            userId = getCurrentUserId()
        )
    }
}

7. Java vs Kotlin 완벽 비교

7.1 코드량 비교

기능 Java 코드 라인 Kotlin 코드 라인 감소율

DTO 클래스 50줄 5줄 90% ↓
생성자 + DI 15줄 3줄 80% ↓
Builder 패턴 30줄 0줄 (불필요) 100% ↓

7.2 가독성 비교

Java 코드:

User user = new User("김철수", 30, "kim@example.com", null, null, true, 1, "서울");
// 🤔 각 파라미터가 무엇을 의미하는지 알 수 없음

Kotlin 코드:

val user = User(
    name = "김철수",
    age = 30,
    email = "kim@example.com",
    isActive = true,
    level = 1,
    city = "서울"
)
// ✅ 명확하고 읽기 쉬움!

8. 자주 하는 실수와 해결법

❌ 실수 1: Data Class에 로직 넣기

// 나쁜 예
data class User(val name: String, val age: Int) {
    fun validateAge() {
        if (age < 0) throw IllegalArgumentException("나이는 0 이상이어야 합니다")
    }
    
    fun sendEmail() {
        // 복잡한 비즈니스 로직...
    }
}

왜 안 좋나요?

  • Data class는 데이터를 담는 용도로만 사용
  • 비즈니스 로직은 Service 계층으로 분리

✅ 올바른 방법

// 좋은 예: Data Class는 데이터만
data class User(val name: String, val age: Int)

// 비즈니스 로직은 Service로
class UserService {
    fun validateAge(user: User) {
        if (user.age < 0) throw IllegalArgumentException("나이는 0 이상이어야 합니다")
    }
}

❌ 실수 2: 모든 곳에 Default Parameter 사용

// 나쁜 예: 너무 많은 기본값
data class User(
    val name: String = "",
    val age: Int = 0,
    val email: String = "",
    val phone: String = ""
)

val user = User()  // 🤔 이게 유효한 User 객체인가?

해결법:

  • 필수 값은 기본값 없이 선언
  • 선택적 값만 기본값 사용
// 좋은 예
data class User(
    val name: String,              // 필수
    val age: Int,                  // 필수
    val email: String? = null,     // 선택
    val phone: String? = null      // 선택
)

9. 성능 비교 - Kotlin이 느릴까?

🚀 결론: 성능 차이 없음!

Kotlin 코드는 컴파일 시 Java 바이트코드로 변환되므로:

  • 런타임 성능 동일
  • 메모리 사용량 동일
  • JVM 최적화 동일하게 적용

차이점:

  • 코드 작성 시간: Kotlin이 50% 빠름
  • 유지보수 시간: Kotlin이 30% 빠름
  • 버그 발생률: Kotlin이 40% 낮음 (Null 안전성 덕분)

💡 핵심 요약 (5초 복습)

// 1. Data Class - 데이터 담는 클래스
data class User(val name: String, val age: Int)

// 2. Named Parameters - 가독성 향상
val user = User(name = "김철수", age = 30)

// 3. Default Parameters - 선택적 파라미터
data class User(val name: String, val email: String? = null)

// 4. Primary Constructor - 생성자 자동 생성
class Controller(private val service: Service)

❓ FAQ (자주 묻는 질문)

Q1. Data Class와 일반 Class의 차이는?

Data Class는 equals(), hashCode(), toString(), copy() 메서드를 자동 생성합니다. 데이터를 담는 용도로만 사용하세요.

Q2. Named Parameters는 필수인가요?

필수는 아니지만, 파라미터가 3개 이상이면 사용을 강력 추천합니다. 가독성이 크게 향상됩니다.

Q3. Java에서 Kotlin Data Class 사용 가능한가요?

네! Kotlin 코드는 Java에서도 사용 가능합니다. 다만 Named Parameters는 Java에서 사용 불가합니다.

Q4. Primary Constructor vs Secondary Constructor?

대부분의 경우 Primary Constructor만으로 충분합니다. 복잡한 초기화 로직이 필요할 때만 Secondary Constructor를 사용하세요.


🎯 실전 과제

이 글을 다 읽으셨다면, 직접 해보세요!

과제 1: 간단한 Data Class 만들기

// TODO: 책(Book) Data Class 만들기
// - 제목(title): String
// - 저자(author): String
// - 가격(price): Int
// - ISBN(isbn): String (선택, 기본값 null)

과제 2: Named Parameters 연습

// TODO: 위에서 만든 Book 클래스로 객체 3개 생성하기
// - Named Parameters 사용
// - 하나는 ISBN 없이, 두 개는 ISBN 포함

과제 3: DTO 변환 함수 작성

// TODO: Book을 BookResponse로 변환하는 toResponse() 함수 작성
data class BookResponse(
    val title: String,
    val author: String,
    val displayPrice: String  // "10,000원" 형식
)

정답은 다음 글에서 공개합니다! 😊


📢 마치며

Kotlin의 기본 문법을 배우셨습니다!

이 글이 도움 되셨다면:

  • ⭐ 블로그 구독하기
  • 💬 댓글로 궁금한 점 남기기
  • 🔗 주변 개발자에게 공유하기

다음 글 예고: Kotlin Null Safety 완벽 가이드 - ?와 ?:의 모든 것 에서는 Kotlin의 최고 장점인 Null 안전성에 대해 심도있게 다룹니다.

궁금한 점은 댓글로 남겨주세요! 💬

반응형
Comments