다중 패러다임 언어는 OOP, 함수형, 스크립팅 스타일을 섞어 팀의 배포 속도를 높여줍니다. 언제 적합한지, 트레이드오프와 사례를 알아보세요.

다중 패러다임 언어는 간단히 말해 하나의 언어 안에서 여러 스타일로 문제를 풀 수 있게 해주는 언어입니다—항상 하나의 ‘정답’만 선택하라고 강요하지 않습니다.
“패러다임”은 코드를 조직하는 서로 다른 습관이라고 생각하세요:
다중 패러다임 언어는 팀이 이 접근들을 상황에 맞게 섞어 쓰도록 해줍니다. 도메인은 클래스(OOP)로 모델링하고, 데이터 변형은 map/filter 같은 함수형 기법으로 처리하며, 글루 코드는 간단한 스크립트 형태(절차형)로 유지할 수 있습니다—모두 같은 코드베이스에서요.
프로덕션 소프트웨어는 거의 단일한 깔끔한 퍼즐이 아닙니다. 팀은 기한, 레거시 시스템, 서드파티 라이브러리, 그리고 수년간의 유지보수를 고려해야 합니다. 어느 날은 기능을 배포하고, 다음 날은 프로덕션 이슈를 디버그하거나 결제 공급자를 통합하거나 위험한 모듈 하나만 다시 쓰는 상황이 생깁니다.
그런 환경에서는 유연성이 학문적 문제가 아니라 마찰을 줄이는 실무적 도구입니다. 여러 스타일을 지원하는 언어는 다음을 가능하게 합니다:
‘이긴다’는 것은 어느 패러다임이 도덕적으로 우월하다는 뜻이 아닙니다. 더 나은 결과를 낸다는 뜻입니다: 언어가 더 널리 채택되고, 팀이 안정적으로 배포하며, 개발자가 생산성을 유지하고, 요구사항 변화 속에서도 코드가 유지보수 가능해집니다. 다중 패러다임 언어는 작업에 적응하므로 종종 이깁니다—작업이 언어에 맞추도록 강요하지 않기 때문입니다.
프로젝트가 처음에는 명확한 선호(OOP, 함수형 등)로 시작하더라도 일상 업무는 곧 여러 관심사가 섞여 같은 틀에 모두 맞지 않게 됩니다.
대부분 애플리케이션은 단순한 ‘앱’ 하나가 아닙니다. 서로 다른 접근법이 유리한 여러 작업들의 묶음입니다:
한 패러다임만을 억지로 전체에 강요하면 시스템의 일부가 부자연스러워집니다. 예를 들어 모든 변환을 클래스 계층으로 모델링하면 보일러플레이트가 폭발하고, 모든 것을 순수 함수로만 작성하려 하면 캐시, DB, UI 이벤트 같은 상태ful 통합 지점이 어색하고 과하게 설계될 수 있습니다.
프로젝트는 진화합니다. 단순 CRUD 서비스에 백그라운드 잡, 실시간 업데이트, 분석, 두 번째 클라이언트 앱이 추가될 수 있습니다. 모듈마다 성능, 정확성, 빠른 반복 등 서로 다른 압력이 발생합니다. 다중 패러다임 언어는 팀이 전체 규칙을 매번 다시 쓰지 않고도 로컬하게 적응할 수 있게 해줍니다.
팀이 단일 패러다임을 너무 엄격하게 강제하면 다음과 같은 비용을 치릅니다:
다중 패러다임 프로그래밍은 실무 프로젝트가 여러 문제들로 이루어져 있고 실용적 설계가 작업을 따르기 때문에 효과적입니다.
다중 패러다임 언어가 작동하는 이유는 대부분의 소프트웨어가 ‘한 형태’가 아니기 때문입니다. 하나의 제품 안에 장기 유지되는 도메인 모델, 짧은 데이터 처리 단계, 글루 코드, 설정처럼 보이는 규칙 등이 공존할 수 있습니다. 서로 다른 패러다임이 서로 다른 부분에서 뛰어납니다.
OOP는 상태와 행동을 가지고 시간이 지나며 진화하는 엔티티를 표현할 때 빛을 발합니다.
예: 쇼핑 카트, 사용자 계정, 주문 워크플로우, 디바이스 연결. 이런 것들은 규칙이 붙은 ‘명사’이고 OOP의 클래스/객체는 그 논리를 조직하고 찾아보기 쉽게 유지하는 데 도움을 줍니다.
함수형 스타일은 파이프라인에 적합합니다: 입력을 받고 변환을 적용해 출력을 만듭니다. 불변 데이터와 순수-ish 함수를 선호하기 때문에 테스트와 추론이 쉽습니다.
예: 이벤트 파싱, 합계 계산, API 응답을 UI 준비 형태로 매핑, 입력 검증, 데이터 내보내기 빌드.
절차형 코드는 ‘이것을 하고, 그다음 이것을 한다’ 접근입니다. 글루 코드, 오케스트레이션, 작은 작업에 종종 가장 명확한 옵션입니다.
예: 마이그레이션 스크립트, CLI 명령, 세 서비스를 순서대로 호출하는 백그라운드 잡, 일회성 어드민 도구.
선언형 스타일은 무엇을 원하는지에 집중하고 어떻게는 프레임워크나 런타임에 맡깁니다.
예: UI 레이아웃, 데이터베이스 쿼리, 라우팅 규칙, 빌드 파이프라인, 구성 기반 검증.
패러다임은 도구일 뿐 신앙이 아닙니다. 목표는 ‘편을 가르는 것’이 아니라 문제에 맞는 스타일을 선택해 코드가 명확하고 테스트 가능하며 팀이 확장하기 쉬운 상태를 유지하는 것입니다.
팀은 드물게 언어를 ‘순수해서’ 선택합니다. 대부분은 업무가 다양한 형태로 도착하기 때문에 언어를 선택합니다: 빠른 프로토타입, 장기 서비스, 데이터 중심 기능, UI 코드, 통합, 그리고 불가피한 버그 수정. 다중 패러다임 언어는 팀이 작업에 맞는 가장 단순한 접근을 사용할 수 있게 하여 작업이 바뀔 때마다 아키텍처를 다시 써야 하는 상황을 피하게 해줍니다.
스타일을 섞을 수 있으면 빠르게 움직일 수 있습니다:
승리는 한 패러다임이 더 우월해서가 아니라, 오늘의 문제에 맞는 ‘올바른’ 패러다임이 어제와 다를 때도 막히지 않는다는 점입니다.
대부분 팀은 모두 같은 방식으로 배운 개발자들로 구성되지 않습니다. 어떤 사람은 객체로 사고하는 데 익숙하고, 어떤 사람은 함수와 불변성을 선호하며, 많은 사람은 그 중간 어딘가에 있습니다. 여러 패러다임을 지원하는 언어는 새로운 입사자가 익숙한 패턴으로 즉시 생산적이 될 수 있게 해주고, 점차 팀의 선호 스타일을 배우게 해 마찰을 줄입니다.
실제 코드베이스는 진화합니다. 다중 패러다임 언어는 순수 함수, 불변성, 합성 가능한 변환 같은 함수형 아이디어를 작은 위험으로 채택할 수 있게 해줍니다. 모듈 하나, 핫패스 하나, 복잡한 비즈니스 로직 한 부분씩 리팩터링하면 되지 전체를 ‘다시 시작’할 필요가 없습니다.
라이브러리와 프레임워크는 특정 스타일을 가정하는 경우가 많습니다. UI 프레임워크는 컴포넌트 객체에 기울고, 데이터 라이브러리는 함수형 합성을 권장하곤 합니다. TypeScript(및 JavaScript), Kotlin(및 Java), 또는 현대적 Java 자체 같은 언어는 이러한 생태계와 매끄럽게 통합되므로, 제품을 만들 때 가정과 싸우느라 시간을 허비하지 않게 해줍니다.
대부분 팀은 OOP와 FP를 철학적으로 선택하지 않습니다. 제품의 서로 다른 부분이 서로 다른 요구를 가지므로 둘을 섞습니다.
OOP는 수년간 진화할 도메인을 모델링할 때 탁월합니다: 주문, 인보이스, 구독, 권한, 워크플로우.
클래스와 인터페이스는 특정 행위의 명확한 소유권(“이 객체가 상태 검증을 책임진다”)과 확장성(“다음 분기에 새로운 결제 수단을 추가할 것이다”)이 필요할 때 유용합니다. 장기 시스템에서는 코드가 비즈니스 사고 방식을 반영하므로 변경이 더 안전해질 수 있습니다.
FP는 자연스럽게 ‘데이터 입력 → 데이터 출력’인 영역에서 강합니다: API 응답 변환, 이벤트 필터링, 합계 계산, 파이프라인 구성.
불변성과 순수-ish 함수는 숨겨진 부작용을 줄여 동시성 처리와 테스트를 더 간단하게 만듭니다. UI 앱에서도 FP 스타일 합성은 상태를 뷰로 매핑하고 논리를 예측 가능하게 유지하는 데 유용합니다.
실제 코드베이스에서는 도메인 모델에는 OOP를 쓰고 데이터 흐름에는 FP를 쓰고 싶을 때가 많습니다—언어를 바꾸거나 전체를 다시 쓰지 않고도. 다중 패러다임 언어는 동일한 툴링, 라이브러리, 배포 파이프라인을 유지하면서 모듈별로 최적의 스타일을 선택하게 해줍니다.
개념이 안정적이고 행위가 함께 속하는 경계에서는 OOP를 사용하세요(도메인 객체, 서비스 인터페이스). 계산과 변환이 지배하는 내부에는 FP를 사용하세요(순수 함수, 불변 데이터, 합성 파이프라인).
대부분의 문제는 동일 레이어 내에서 스타일이 섞일 때 시작됩니다. 영역별 기본값을 정하고 예외는 개인적 취향이 아니라 의도된 설계 결정으로 취급하세요.
다중 패러다임 언어가 이기는 이유 중 하나는 ‘안전한’ 선택을 쉽게 만든다는 점입니다. 언어의 기본 동작, 컴파일러 메시지, 에디터 지원이 명확한 코드를 향해 부드럽게 유도하면 팀은 스타일을 두고 덜 싸우고 피할 수 있는 이슈를 덜 디버그하게 됩니다.
성공의 구덩이는 저항이 적은 길이 올바르고 유지보수 가능한 코드를 낳는 경우입니다. 예를 들어:
TypeScript가 단순한 예입니다: 느슨하게 시작하더라도 툴링이 점진적으로 타입을 강화하도록 권장하고, 타이핑 중 실시간 피드백을 제공합니다.
정적 타이핑은 잘못된 데이터 유형을 일찍 잡아내지만, 현대 언어는 타입 추론으로 ‘의식적 주석 노동’을 줄입니다—그래서 모든 것을 주석으로 달지 않아도 이점을 얻을 수 있습니다.
널 안전성도 큰 가드레일입니다. Kotlin의 nullable 타입(및 적절히 사용된 Java의 Optional 패턴)은 ‘값이 없을 수도 있다’는 사실을 코드로 명시하게 하여 런타임에서만 발생하던 오류 범주를 줄입니다.
열거형은 닫힌 집합(“Pending / Paid / Failed”)을 모델링하게 해 주어 문자열 오타 문제를 방지합니다.
패턴 매칭(여러 현대 언어에서 지원되며 확장 중)은 그 옵션들을 명확히 처리하게 도와줍니다. 총괄 검사와 결합하면 새로운 변형을 추가할 때 케이스를 잊기 어렵습니다.
다중 패러다임 기능은 스타일을 늘릴 수 있습니다: 일부 코드는 매우 객체지향적이고, 일부는 깊이 함수형일 수 있으며, 프로젝트는 여러 팀이 쓴 것처럼 보일 수 있습니다.
혼란을 피하려면 규약에 합의하세요: 불변성이 선호되는 곳, 오류를 표현하는 방식, 언제 클래스를 쓰고 언제 단순 데이터 구조를 쓸지 등을 정합니다. 언어가 안내해줄 순 있지만 팀의 공유된 플레이북도 필요합니다.
종이 위에서 완벽해 보이는 언어도 현실 조직에 맞지 않으면 실패할 수 있습니다. 대부분 팀은 격리되어 개발하지 않으며 기존 시스템, 기한, 제약에 배포해야 합니다.
일반적 현실은 레거시 통합(오래된 DB, SOAP 서비스, JVM/.NET 스택), 규정 준수(감사, 접근 제어, 데이터 보존), 그리고 수년간 이해하기 쉬워야 하는 긴 지원 주기 등을 포함합니다.
다중 패러다임 언어는 이러한 제약을 더 잘 처리하는 경향이 있습니다. 기존 프레임워크에 맞는 객체지향 구조는 유지하면서, 위험을 줄이는 곳에는 점진적으로 함수형 패턴(불변성, 순수 변환)을 도입할 수 있기 때문입니다.
가장 큰 생산성 이득은 보통 라이브러리와 툴링에서 옵니다: 인증 패키지, PDF 생성기, 메시지 큐, 관측성, 테스트 프레임워크, 성숙한 빌드 시스템 등.
Java/Kotlin이나 JavaScript/TypeScript 같은 언어는 단지 여러 패러다임을 지원하는 것뿐 아니라 “지루한 것들”이 이미 해결된 생태계 위에 서 있습니다. 따라서 기존 인프라와 통합하기 쉬워 맞춤형 플러밍을 만들 필요가 줄어듭니다.
주류 다중 패러다임 언어는 종종 더 큰 인재 풀을 가집니다. 팀을 확장하거나 계약자를 대체하거나 서비스를 다른 그룹에 인계할 때 중요합니다. 많은 개발자가 이미 언어(또는 유사 언어)를 알고 있다면 온보딩이 빨라지고 교육 비용이 줄어듭니다.
자동완성, 리팩터링 도구, 린터, 포매터, CI 템플릿은 팀이 일관되게 전달하는 방식을 조용히 결정합니다. 이러한 도구들이 강력할수록 팀은 스타일 논쟁보다 제품 배포에 시간을 더 쓸 수 있습니다. 많은 조직에서 진짜 경쟁 우위는 ‘완벽한’ 패러다임이 아니라 완비된 생태계입니다.
많은 팀이 ‘다중 패러다임 프로그래밍’을 전략적으로 채택하는 대신 실용적인 언어를 고를 뿐이며, 그 언어가 자연스럽게 여러 사고 방식을 지원합니다.
TypeScript는 웹 앱과 툴링에서 스크립트 글루로 자주 사용되면서도 구조를 제공해줍니다.
배열에 대한 map/filter/reduce 같은 FP 스타일 변환과 클래스, 인터페이스, 의존성 주입 같은 OOP 스타일 구조가 공존합니다. 같은 날 작은 마이그레이션 스크립트를 쓰고, 잘 타입된 도메인 모델을 작성하는 일이 가능합니다.
Kotlin은 Java 스타일 OOP를 유지하면서도 도움이 되는 함수형 패턴을 추가할 수 있게 해줍니다.
예: 불변 데이터 클래스, when 표현식, 컬렉션 파이프라인(map, flatMap)을 데이터 성형에 사용하고, 경계와 라이프사이클(컨트롤러, 레포지토리 등)에는 클래스를 활용합니다.
C#은 전형적으로 OOP 중심(클래스, 인터페이스, 접근 제어자)이지만, FP 친화적 도구도 많습니다.
LINQ는 필터링과 프로젝션을 명확히 표현하게 하며, API, 백그라운드 잡, UI 레이어에는 객체지향 아키텍처를 유지합니다.
Swift는 일상 앱 개발에서 패러다임을 혼합합니다.
팀은 능력 정의를 위해 프로토콜을 사용하고(상속보다 조합), 안전한 모델을 위해 **값 타입(struct)**을 사용하며, UI 상태 업데이트와 데이터 변환에 고차 함수를 사용합니다—참조 의미가 필요할 때는 클래스를 씁니다.
심지어 Java도 더 다중 패러다임화되었습니다: 람다, 스트림, 레코드로 보다 함수형·데이터 지향 스타일을 지원합니다.
실무에서는 핵심 구조(패키지, 서비스)에는 OOP를 유지하면서 파싱, 검증, 리포팅 같은 ‘파이프라인’ 변환에는 스트림을 활용합니다.
다중 패러다임 언어는 여러 방식으로 문제를 풀 수 있게 해주므로 강력합니다. 단점은 ‘여러 방식’이 동일 레포지토리 안에서 ‘여러 코드베이스’로 바뀔 수 있다는 점입니다.
한 팀은 모든 것을 클래스와 가변 객체로 작성하고 다른 팀은 순수 함수와 불변성을 선호하면 프로젝트는 여러 방언을 가진 것처럼 느껴질 수 있습니다. 심지어 이름 규칙, 오류 처리, 파일 조직 같은 단순한 작업도 각 모듈이 다른 규칙을 가질 때 더 어려워집니다.
이 비용은 온보딩과 코드 리뷰에서 드러납니다: 사람들이 비즈니스 로직을 이해하기보다 스타일을 해독하는 데 시간을 씁니다.
언어가 많은 패러다임을 지원하면 ‘영리한’ 추상화도 많아집니다. 그 결과:
좋은 휴리스틱은 팀이 빠르게 설명할 수 있는 가장 단순한 접근을 선택하고, 고급 패턴은 반복을 제거하거나 버그를 실제로 줄일 때만 사용하는 것입니다.
어떤 관용구는 더 많은 객체를 할당하거나 중간 컬렉션을 만들거나 겉보기에 작은 표현 뒤에 비싼 작업을 숨길 수 있습니다—특히 함수형 중심 코드에서. 이는 함수형 기법에 반대하는 주장이 아니라, 핫패스를 측정하고 일반 헬퍼가 내부에서 무엇을 하는지 이해하라는 상기입니다.
유연성은 팀이 가드레일에 합의했을 때 다시 장점이 됩니다:
이 가드레일들이 있으면 언어는 유연하지만 코드가 통일된 느낌을 유지합니다.
다중 패러다임 언어를 선택하는 것은 ‘가장 강력한’ 옵션을 고르는 것이 아닙니다. 팀과 제약에 맞는 도구를 고르되 성장 여지는 남겨두는 것입니다.
문법에 반하지 말고 이 체크리스트를 사용하세요:
비슷한 선택지(예: TypeScript vs JavaScript, Kotlin과 Java)를 비교할 때는 실제 결과를 바꿀 요소—타입 안전성, 툴링 품질, 선호 아키텍처 지원 정도—를 우선하세요.
전체 리팩터 대신 작은 파일럿을 실행하세요:
이렇게 하면 언어 선택이 의견이 아니라 증거에 기반하게 됩니다.
다중 패러다임의 힘은 안내 없이는 불일치로 이어지므로 기본 패턴을 레이어별로 정하세요:
팀 플레이북으로 ‘골든 패스’ 예제를 레이어별로 한두 개만 작성하세요—사람들이 복사해서 쓸 수 있는 짧은 스니펫이 철학 문서보다 일관성에 더 큰 효과를 줍니다.
유지보수성을 포기하지 않고 더 빠르게 움직이려면 ‘작업에 맞는 도구’라는 마인드를 존중하는 툴을 고르는 것이 도움이 됩니다.
예를 들어, Koder.ai는 채팅 인터페이스로 웹, 백엔드, 모바일 앱을 만들 수 있는 바이브 코딩 플랫폼입니다—원할 때 소스 코드를 내보내고 일반 코드베이스처럼 발전시킬 수 있습니다. 실제로 팀들은 React UI, Go 백엔드, PostgreSQL 데이터 모델을 빠르게 프로토타이핑한 다음 이 글의 다중 패러다임 가이드라인(명확한 OOP 경계, 함수형 변환, 절차형 오케스트레이션)을 적용해 프로젝트를 단단히 다듬습니다.
플래닝 모드, 스냅샷, 롤백 같은 기능은 ‘완전 전환 전에 파일럿을 돌려라’ 접근과도 잘 맞습니다: 반복하고 결과를 비교하며 변경을 되돌릴 수 있습니다.
다중 패러다임 언어는 팀에 선택지를 주지만, 선택지에는 경계가 필요합니다. 목표는 스타일을 금지하는 것이 아니라 선택을 예측 가능하게 만들어 다음 사람이 읽고 변경하고 안전하게 배포할 수 있게 하는 것입니다.
짧은 PARADIGMS.md(또는 README 섹션)를 추가해: 무엇이 어디에 가는지 답하세요.
한 페이지로 유지하세요. 사람들이 외우지 못하면 너무 깁니다.
Result/Error 타입, *Service, *Repository 같은 접미사 규칙 합의.검토자에게 다음을 요청하세요:
팀 간 실천을 표준화한다면 더 많은 지침을 /blog에 두고 지원/계획 기대치를 /pricing에 포함하세요.
다중 패러다임 언어가 실무에서 이기는 이유는 실무 프로젝트 자체가 기본적으로 혼합되어 있기 때문입니다. 하나의 코드베이스에는 데이터 처리, UI 작업, 통합, 동시성, 장기 도메인 로직이 모두 포함되며 기한, 인력 변화, 요구 변화가 따릅니다. 언어가 여러 프로그래밍 스타일을 지원하면 팀은 문제의 각 부분에 가장 단순한 접근을 사용할 수 있고 모든 것을 하나의 모델로 억지로 밀어넣지 않아도 됩니다.
단점은 유연성이 불일치로 바뀔 수 있다는 점입니다. 팀의 절반이 모든 것을 클래스만으로 작성하고 나머지 절반이 모두 함수 파이프라인으로 작성하면 코드베이스는 여러 작은 프로젝트가 이어진 것처럼 느껴질 수 있습니다. 이것은 언어 문제가 아니라 조정 문제입니다.
좋은 다중 패러다임 코드베이스는 대개 다음을 갖습니다:
언어를 고르거나 재평가할 때는 이념에서 시작하지 말고 고통 지점에서 시작하세요. 버그가 반복되는 곳은? 온보딩이 지체되는 곳은? 변경에 저항하는 코드는 어디인가?
그다음 작은 시험을 실행하세요: 한 개의 독립된 기능이나 서비스로 구현해보고 명시적 규약을 적용해 리뷰 시간, 결함률, 수정 용이성 같은 결과를 측정하세요.
도구, 트레이드오프, 팀 실천에 대한 더 실용적인 안내가 필요하면 /blog의 관련 글들을 참고하세요.
다중 패러다임 언어는 동일한 코드베이스에서 여러 프로그래밍 스타일(일반적으로 객체지향, 함수형, 절차형, 때로는 선언형)을 지원합니다. 실무적으로는 도메인을 클래스들로 모델링하고, 데이터 변환은 함수 파이프라인으로 작성하며, 오케스트레이션은 단계별 절차형 코드로 유지하는 등 언어와 싸우지 않고 작업할 수 있다는 뜻입니다.
현실 시스템은 다양한 성격의 작업들을 포함하기 때문입니다:
여러 스타일을 지원하는 언어는 모듈별로 가장 명확한 도구를 선택하게 해 주므로, 한 가지 방식만 강제하는 것보다 실무에 더 잘 맞습니다.
실용적인 분할은 다음과 같습니다:
이렇게 하면 상태가 필요한 부분이 한곳에 모이고, 대부분의 로직은 테스트하기 쉽고 이해하기 쉬운 상태로 유지됩니다.
오케스트레이션이 주 목적일 때는 절차형 코드를 유지하세요:
의미 있는 이름의 작은 함수들을 사용하고, 일관성을 위해 억지로 클래스 계층을 만들지 마세요. 스크립트가 커지면 재사용 가능한 로직을 순수 함수나 작은 서비스 객체로 추출하면 됩니다.
반복되는 마찰과 일관성 없음을 나타내는 신호들이 있습니다. 예를 들어:
해결책은 짧은 플레이북(e.g., PARADIGMS.md), CI에 포매터/린터 추가, 사람들이 복사해 쓸 수 있는 ‘골든 패스’ 예제들입니다.
도구 체계가 “성공의 구덩이(pit of success)”를 현실로 만듭니다:
실무에서는 강력한 툴링이 방지 가능한 버그를 줄이고 개발 중 피드백 루프를 단축합니다.
왜냐하면 조직적 마찰을 줄여주기 때문입니다:
옵션을 평가할 때는 이데올로기적 순수성보다 생태계 적합성과 운영 현실을 우선하세요.
예—특히 핫패스에서는 성능 문제가 생길 수 있습니다. 주의할 점:
FP가 정확성이나 테스트 용이성을 개선한다면 사용하되, 성능이 중요한 코드에서는 프로파일링으로 병목을 확인하고 최적화하세요.
따르기 쉬운 가드레일을 만드세요:
Result 타입)짧게 문서화하고 예제 모듈을 가리키면, 일관성은 수동 감독이 아니라 자동화로 유지될 수 있습니다.
토론 대신 작은 파일럿을 실행하세요:
이렇게 하면 언어 선택이 주장 기반이 아니라 증거 기반이 됩니다. 관련 실무 지침은 내부 문서에 남기고 /blog의 참고 기사를 연결하세요.