💻 프로그래밍

덕 타이핑

Duck Typing

"오리처럼 걷고 꽥꽥거리면 오리다" - 객체의 타입보다 메서드와 속성으로 판단하는 동적 타이핑.

📖 상세 설명

덕 타이핑(Duck Typing)은 "오리처럼 걷고 오리처럼 꽥꽥거리면, 그것은 오리다(If it walks like a duck and quacks like a duck, it's a duck)"라는 격언에서 유래한 프로그래밍 개념입니다. 객체의 실제 타입보다 그 객체가 어떤 메서드와 속성을 가지고 있는지로 적합성을 판단합니다.

정적 타이핑 언어(Java, C++)에서는 명시적 인터페이스나 상속을 통해 타입을 정의하지만, 덕 타이핑을 지원하는 언어(Python, JavaScript, Ruby)에서는 필요한 메서드만 구현되어 있으면 어떤 객체든 사용할 수 있습니다. 이는 유연성을 크게 높여주지만, 런타임 에러의 위험도 있습니다.

Python에서 덕 타이핑은 핵심 철학입니다. `for` 문은 `__iter__` 메서드를 가진 모든 객체를 순회할 수 있고, `len()` 함수는 `__len__`을 구현한 모든 객체에 작동합니다. 이런 "프로토콜" 기반 접근은 상속 없이도 다형성을 구현할 수 있게 해줍니다.

TypeScript의 구조적 타이핑(Structural Typing)은 덕 타이핑의 정적 타입 버전으로 볼 수 있습니다. 명시적으로 인터페이스를 구현하지 않아도 필요한 속성과 메서드를 가지면 해당 타입으로 인정됩니다. 이는 Java의 명목적 타이핑(Nominal Typing)과 대조됩니다.

💻 코드 예제

# Python에서의 덕 타이핑 예제
class Duck:
    def walk(self):
        return "뒤뚱뒤뚱"

    def quack(self):
        return "꽥꽥!"

class Person:
    def walk(self):
        return "걷는다"

    def quack(self):
        return "꽥꽥 흉내"

class Robot:
    def walk(self):
        return "삐빅 이동"

    def quack(self):
        return "QUACK 출력"

# 덕 타이핑: 타입이 아닌 메서드 존재 여부로 판단
def make_it_quack(duck_like):
    """walk와 quack 메서드만 있으면 어떤 객체든 OK"""
    print(f"걷기: {duck_like.walk()}")
    print(f"울음: {duck_like.quack()}")

# 모두 작동! 타입 상속 없이도 다형성 구현
for obj in [Duck(), Person(), Robot()]:
    make_it_quack(obj)
    print("---")

# 프로토콜 기반 덕 타이핑 (Python 표준)
class FilelikeObject:
    """read() 메서드만 있으면 파일처럼 사용 가능"""
    def __init__(self, data):
        self.data = data
        self.position = 0

    def read(self, size=-1):
        if size == -1:
            result = self.data[self.position:]
            self.position = len(self.data)
        else:
            result = self.data[self.position:self.position + size]
            self.position += size
        return result

# 실제 파일이 아니어도 read()가 있으면 동작
import json
fake_file = FilelikeObject('{"name": "duck", "type": "bird"}')
data = json.load(fake_file)  # 파일처럼 사용됨
print(data)  # {'name': 'duck', 'type': 'bird'}

🗣️ 실무 대화 예시

파이썬 코드 리뷰에서

"이 함수가 리스트만 받을 필요 없어요. `__iter__`만 있으면 되니까 타입 힌트를 `Iterable[str]`로 바꾸면 제너레이터나 튜플도 받을 수 있습니다. 덕 타이핑의 장점을 살리면 더 유연한 API가 됩니다."

타입스크립트 마이그레이션 논의 중

"TypeScript의 구조적 타이핑 덕분에 기존 JavaScript 코드를 점진적으로 마이그레이션할 수 있어요. 인터페이스를 implements로 명시 안 해도 구조만 맞으면 타입 체크가 통과해서, 레거시 코드와의 호환성이 좋습니다."

테스트 코드 작성 중

"목(Mock) 객체 만들 때 덕 타이핑이 편해요. 전체 클래스를 상속받지 않고 테스트에 필요한 메서드만 가진 객체를 만들면 됩니다. Python의 MagicMock이 이걸 잘 활용하고 있죠."

📊 타이핑 방식 비교

방식 언어 특징 체크 시점
덕 타이핑 Python, Ruby, JS 메서드 존재 여부로 판단 런타임
구조적 타이핑 TypeScript, Go 구조(shape)로 호환성 판단 컴파일 타임
명목적 타이핑 Java, C#, C++ 명시적 상속/구현 필요 컴파일 타임

💡 실무 팁: Python에서 타입 안전성이 필요하면 Protocol (PEP 544)을 사용하세요. 런타임 덕 타이핑의 유연성과 정적 타입 체크의 안전성을 모두 얻을 수 있습니다.

⚠️ 주의사항

1
런타임 에러 위험

덕 타이핑은 컴파일 타임에 타입 오류를 잡지 못합니다. 필요한 메서드가 없는 객체를 전달하면 런타임에서야 AttributeError가 발생합니다. 중요한 코드에는 타입 힌트와 런타임 체크를 함께 사용하세요.

2
암묵적 인터페이스의 문서화

덕 타이핑에서 "어떤 메서드가 필요한지"가 암묵적이 되기 쉽습니다. Protocol 타입 힌트나 docstring으로 기대하는 인터페이스를 명확히 문서화하세요. 그렇지 않으면 유지보수가 어려워집니다.

3
메서드 이름 충돌

같은 이름의 메서드가 다른 의미로 사용될 수 있습니다. `close()`가 파일 닫기인지, UI 창 닫기인지, 연결 종료인지 문맥에 따라 다릅니다. 의미적 호환성까지 고려해야 합니다.

🔗 관련 용어

📚 더 배우기