개발 지식 책

클린 아키텍처 도서 리뷰: 견고하고 유지보수 가능한 소프트웨어 설계 원칙

강코의 코딩 일기 2026. 6. 26. 13:23
반응형

로버트 C. 마틴의 '클린 아키텍처'를 통해 견고하고 유지보수하기 쉬운 소프트웨어를 설계하는 핵심 원칙들을 파헤쳐 봅니다. 개발자라면 꼭 알아야 할 아키텍처 지식을 친근하게 설명해 드릴게요.

클린 아키텍처 도서 리뷰: 견고하고 유지보수 가능한 소프트웨어 설계 원칙 - safety, yards, bob, yard safety, project, worker, child labour, design, architecture, ok, safety, safety, safety, safety, safety, worker, child labour, child labour, child labour, child labour

Image by eroyka on Pixabay

소프트웨어 아키텍처, 왜 중요할까요?

혹시 이런 경험 있으신가요? 처음에는 깔끔했던 프로젝트가 시간이 지날수록 점점 복잡해지고, 작은 기능 하나 추가하는 데도 온갖 코드를 건드려야 하는 상황 말이에요. 마치 실타래처럼 엉켜버린 코드를 보면 한숨부터 나오게 되죠? 😱

이런 상황을 스파게티 코드라고도 부르는데요. 기능 추가는 물론이고 버그 수정도 어려워져서 개발자들의 생산성을 뚝 떨어뜨리고, 결국 서비스의 성장까지 방해하게 된답니다. 이런 문제는 대부분 소프트웨어 아키텍처에 대한 고민이 부족했기 때문에 발생하곤 해요.

아키텍처는 건물의 뼈대와 같다고 생각하시면 이해하기 쉬울 거예요. 튼튼하고 효율적인 건물을 지으려면 설계 단계부터 꼼꼼하게 구조를 잡아야 하는 것처럼, 소프트웨어 역시 마찬가지거든요. 좋은 아키텍처는 개발의 생산성을 높이고, 유지보수를 용이하게 하며, 변화에 유연하게 대응할 수 있도록 도와줍니다. 그래서 개발자라면 누구나 한 번쯤은 "어떻게 하면 견고하고 유지보수 가능한 소프트웨어를 만들 수 있을까?" 하는 질문을 던지게 되죠.

이 질문에 대한 답을 명쾌하게 제시해주는 책이 바로 로버트 C. 마틴(Robert C. Martin), 일명 엉클 밥(Uncle Bob)이 쓴 『클린 아키텍처(Clean Architecture)』입니다. 이 책은 단순히 코드를 예쁘게 짜는 방법을 넘어, 시스템 전체를 어떻게 설계해야 하는지에 대한 깊이 있는 통찰을 제공해주거든요. 함께 클린 아키텍처의 세계로 떠나볼까요?

'클린 아키텍처'는 어떤 책인가요? 엉클 밥의 지혜

『클린 아키텍처』는 소프트웨어 개발 분야의 거장인 엉클 밥이 수십 년간 쌓아온 경험과 지혜를 집대성한 책이에요. 이 책은 특정 프로그래밍 언어나 프레임워크에 얽매이지 않고, 소프트웨어 설계의 본질적인 원칙들을 다루고 있답니다. 그래서 자바 개발자든, 파이썬 개발자든, 프론트엔드 개발자든 누구나 공감하고 배울 수 있는 내용으로 가득하죠.

엉클 밥은 이 책에서 소프트웨어 아키텍처의 궁극적인 목표가 "개발 비용을 최소화하고, 수명 주기를 연장하는 것"이라고 말합니다. 이를 위해 그는 독립성(Independence)을 강조하는데요, UI, 데이터베이스, 웹 프레임워크 등 외부 기술 스택으로부터 핵심 비즈니스 로직을 독립시켜야 한다는 거예요. 이렇게 하면 특정 기술이 바뀌어도 핵심 로직은 그대로 유지할 수 있어서 시스템 전체의 안정성과 유연성이 크게 향상되거든요.

이 책은 크게 세 가지 주요 개념을 중심으로 이야기를 풀어나갑니다.

  1. 설계의 중요성: 왜 좋은 설계가 필요한지, 나쁜 설계가 어떤 문제를 일으키는지 상세히 설명해요.
  2. SOLID 원칙: 객체 지향 설계의 다섯 가지 핵심 원칙인 SOLID를 통해 견고한 코드를 작성하는 방법을 알려줍니다.
  3. 계층형 아키텍처: 클린 아키텍처가 제시하는 동심원 구조를 통해 시스템의 각 부분을 어떻게 분리하고 조직해야 하는지 구체적인 청사진을 보여주죠.

한마디로, 『클린 아키텍처』는 당장 눈앞의 코딩 스킬을 알려주기보다는, 오래도록 살아남을 수 있는 소프트웨어를 만드는 근본적인 사고방식을 심어주는 책이라고 할 수 있어요. 그래서 처음 읽을 때는 조금 어렵게 느껴질 수도 있지만, 곱씹어 읽을수록 깊은 깨달음을 주는 마법 같은 책이랍니다.

클린 아키텍처의 핵심 원칙: SOLID를 중심으로

클린 아키텍처를 이해하려면 SOLID 원칙을 빼놓을 수 없어요. SOLID는 객체 지향 설계의 다섯 가지 기본 원칙을 나타내는 약자로, 엉클 밥이 주창한 개념이거든요. 이 원칙들을 잘 지키면 유연하고 유지보수하기 쉬운 시스템을 만들 수 있답니다.

하나씩 간단히 살펴볼까요?

  • S: 단일 책임 원칙 (Single Responsibility Principle, SRP)
    하나의 클래스는 하나의 책임만 가져야 한다는 원칙이에요. 예를 들어, 사용자 인증과 사용자 정보 저장을 모두 담당하는 클래스가 있다면, 인증 로직이 바뀌거나 저장 방식이 바뀌었을 때 둘 다 영향을 받게 되겠죠? SRP에 따르면 이 두 가지 책임은 별개의 클래스로 분리해야 합니다. 이렇게 하면 변경에 대한 파급 효과를 최소화할 수 있어요. 클린 아키텍처의 핵심 계층 분리도 결국 SRP의 확장판이라고 볼 수 있답니다.
  • O: 개방-폐쇄 원칙 (Open-Closed Principle, OCP)
    소프트웨어 개체(클래스, 모듈, 함수 등)는 확장에는 열려 있어야 하지만, 변경에는 닫혀 있어야 한다는 원칙이에요. 새로운 기능을 추가할 때 기존 코드를 수정하는 대신, 확장을 통해 기능을 추가하라는 의미인데요. 인터페이스나 추상 클래스를 활용해서 구현 클래스를 쉽게 교체하거나 추가할 수 있도록 설계하는 것이 좋은 예시죠. 예를 들어, 새로운 결제 수단이 추가될 때마다 기존 결제 로직을 수정하는 것이 아니라, 새로운 결제 모듈을 추가하여 확장하는 방식이에요.
  • L: 리스코프 치환 원칙 (Liskov Substitution Principle, LSP)
    부모 클래스(타입)를 사용하는 곳에서 자식 클래스(타입)를 문제없이 사용할 수 있어야 한다는 원칙입니다. 즉, 자식 클래스는 부모 클래스의 계약(contract)을 위반해서는 안 된다는 건데요. 만약 부모 클래스 자리에 자식 클래스를 넣었을 때 예상치 못한 동작이 발생한다면 LSP를 위반한 것이죠. 이 원칙은 다형성(Polymorphism)을 올바르게 활용하는 데 매우 중요하답니다.
  • I: 인터페이스 분리 원칙 (Interface Segregation Principle, ISP)
    클라이언트는 자신이 사용하지 않는 인터페이스에 의존해서는 안 된다는 원칙이에요. 너무 거대한 인터페이스 하나를 만들어서 여러 클라이언트가 사용하게 되면, 클라이언트는 자신이 필요 없는 메서드까지 구현해야 하는 부담을 안게 되거든요. 대신 작고 구체적인 여러 인터페이스로 분리하여, 각 클라이언트가 필요한 인터페이스만 사용하도록 해야 합니다. 예를 들어, '개발자'라는 거대한 인터페이스 대신 '백엔드 개발자', '프론트엔드 개발자'처럼 세분화하는 것이죠.
  • D: 의존성 역전 원칙 (Dependency Inversion Principle, DIP)
    추상화된 것은 구체적인 것에 의존해서는 안 되고, 구체적인 것은 추상화된 것에 의존해야 한다는 원칙입니다. 즉, 고수준 모듈은 저수준 모듈에 의존해서는 안 된다는 말인데요. 일반적으로는 고수준 모듈(비즈니스 로직)이 저수준 모듈(데이터베이스, UI 등)을 직접 사용하는 경우가 많지만, DIP는 그 반대로 가라는 거예요. 중간에 추상화된 인터페이스를 두어서 고수준 모듈이 이 인터페이스에 의존하고, 저수준 모듈이 이 인터페이스를 구현하도록 만드는 것이죠. 클린 아키텍처의 핵심인 '의존성 규칙'이 바로 이 DIP를 기반으로 합니다.

이 SOLID 원칙들은 서로 유기적으로 연결되어 있어요. 이 원칙들을 잘 지키면 코드가 더욱 유연하고 확장 가능하며, 테스트하기 쉬워진답니다. 클린 아키텍처는 이러한 SOLID 원칙들을 시스템 전체 아키텍처 레벨로 확장하여 적용한 것이라고 이해하시면 돼요.

클린 아키텍처 도서 리뷰: 견고하고 유지보수 가능한 소프트웨어 설계 원칙 - books, shelves, book store, library, education, shelf, bookshelf, study, knowledge, reading, read, library, library, library, library, library, education, education, education, bookshelf, study, study

Image by T_Tide on Pixabay

클린 아키텍처의 계층 구조 파헤치기

『클린 아키텍처』에서 가장 시각적이고 핵심적인 개념은 바로 동심원(Concentric Circles) 구조입니다. 이 구조는 시스템을 네 개의 주요 계층으로 나누고, 각 계층 간의 의존성 방향을 명확히 정의하죠.

중요한 것은 바로 의존성 규칙(Dependency Rule)인데요. 이 규칙은 "안쪽 원은 바깥쪽 원에 대해 아무것도 몰라야 한다"는 것입니다. 즉, 의존성은 항상 바깥쪽에서 안쪽으로만 향해야 한다는 의미예요. 바깥쪽 계층은 안쪽 계층의 추상화를 사용하지만, 안쪽 계층은 바깥쪽 계층에 대해 전혀 알지 못하도록 설계하는 것이 핵심이죠. 이렇게 되면 안쪽 계층(핵심 비즈니스 로직)은 외부 기술 스택(UI, DB, 프레임워크)으로부터 완벽하게 독립될 수 있습니다.

네 개의 계층을 안쪽부터 바깥쪽으로 살펴볼까요?

  1. 엔티티 (Entities):가장 안쪽에 위치하며, 전사적인 핵심 비즈니스 규칙을 담고 있습니다. 예를 들어, '주문'이나 '고객' 같은 핵심 도메인 객체와 이들이 지켜야 할 규칙들이 여기에 속하죠. 이 계층은 시스템의 가장 본질적인 부분이며, UI나 데이터베이스, 심지어 애플리케이션 자체의 변경에도 영향을 받지 않아야 합니다.
  2. 유스케이스 (Use Cases):애플리케이션 특화 비즈니스 규칙을 담고 있습니다. 엔티티를 활용하여 사용자의 특정 목표를 달성하는 방법을 정의하는 곳이죠. 예를 들어, '상품 주문하기', '회원 가입하기'와 같은 기능들이 유스케이스에 해당해요. 유스케이스는 엔티티 계층에만 의존하며, 바깥쪽 계층(웹, DB 등)에 대해서는 알지 못합니다.
  3. 인터페이스 어댑터 (Interface Adapters):이 계층은 안쪽 계층(엔티티, 유스케이스)과 바깥쪽 계층(웹, DB, UI 등) 사이의 데이터 변환을 담당합니다. 웹 프레임워크의 컨트롤러, 데이터베이스 접근 객체(DAO), DTO(Data Transfer Object) 등이 여기에 속하죠. 예를 들어, 웹 요청으로 들어온 데이터를 유스케이스가 이해할 수 있는 형태로 변환하거나, 유스케이스의 결과를 웹 응답 형태로 변환하는 역할을 수행합니다.
  4. 프레임워크와 드라이버 (Frameworks and Drivers):가장 바깥쪽 계층으로, 데이터베이스, 웹 프레임워크, UI 프레임워크, 외부 장치 드라이버 등 외부 기술 스택이 위치합니다. 이 계층은 안쪽 계층에게 필요한 기능을 제공하지만, 안쪽 계층은 이 계층의 구체적인 구현을 직접 의존하지 않아요. 대신 인터페이스 어댑터를 통해 추상화된 형태로 소통하죠.

이러한 계층 구조와 의존성 규칙을 통해, 핵심 비즈니스 로직은 UI나 데이터베이스, 웹 프레임워크의 변화로부터 완벽하게 보호받을 수 있습니다. 예를 들어, MySQL을 사용하다가 PostgreSQL로 데이터베이스를 변경해도, 엔티티와 유스케이스 계층은 아무런 영향을 받지 않아요. 단지 인터페이스 어댑터 계층의 데이터베이스 관련 코드만 수정하면 되는 것이죠. 이는 시스템의 유연성과 유지보수성을 극대화하는 강력한 방법이랍니다.

전통적인 계층형 아키텍처와의 비교

클린 아키텍처의 계층 구조가 전통적인 3계층(프레젠테이션, 비즈니스, 데이터) 아키텍처와 어떻게 다른지 비교해 볼까요?

특징 전통적인 3계층 아키텍처 클린 아키텍처
계층 구성 프레젠테이션(UI), 비즈니스 로직, 데이터 접근(DB) 엔티티, 유스케이스, 인터페이스 어댑터, 프레임워크/드라이버
의존성 방향 상위 계층이 하위 계층을 직접 의존 (UI -> 비즈니스 -> DB) 항상 안쪽으로만 의존 (바깥쪽 -> 안쪽)
중심 데이터베이스 또는 UI 중심인 경우가 많음 비즈니스 로직(엔티티, 유스케이스) 중심
기술 의존성 비즈니스 로직이 DB나 UI 프레임워크에 강하게 의존 가능 비즈니스 로직이 외부 기술로부터 완벽하게 분리, DIP 활용
변경 유연성 외부 기술 변경 시 핵심 로직도 영향받기 쉬움 외부 기술 변경에 매우 유연하게 대응 가능

표에서 보듯이, 클린 아키텍처는 비즈니스 로직을 시스템의 가장 중요한 부분으로 간주하고, 이를 외부 기술로부터 철저히 보호하려는 철학을 가지고 있습니다. 이는 장기적으로 소프트웨어의 안정성과 유지보수성을 크게 높여주는 결정적인 차이점이죠.

'클린 아키텍처'를 실제 프로젝트에 적용하려면?

클린 아키텍처의 이론을 이해하는 것도 중요하지만, 실제 프로젝트에 어떻게 적용해야 할지 막막하게 느껴질 때가 많을 거예요. 저도 그랬거든요! 하지만 몇 가지 핵심 원칙을 가지고 접근하면 생각보다 어렵지 않게 시작할 수 있답니다.

1. Use Case 중심으로 생각하기

클린 아키텍처를 적용할 때 가장 먼저 해야 할 일은 시스템이 제공해야 할 유스케이스(Use Case)를 명확히 정의하는 것입니다. "사용자가 무엇을 하고 싶은가?"에 초점을 맞춰보세요. 예를 들어, '상품을 장바구니에 담는다', '주문을 생성한다', '회원 정보를 수정한다'와 같은 것들이죠. 각 유스케이스는 독립적인 비즈니스 시나리오를 나타내며, 클린 아키텍처의 유스케이스 계층의 핵심이 됩니다.

예를 들어, '회원 가입' 유스케이스를 생각해볼까요? 다음과 같은 의사 코드로 표현해볼 수 있습니다.


// Use Case 인터페이스 (고수준 모듈)
interface RegisterUserUseCase {
    execute(request: RegisterUserRequest): RegisterUserResponse;
}

// User Repository 인터페이스 (고수준 모듈이 의존할 추상화)
interface UserRepository {
    existsByEmail(email: string): boolean;
    save(user: User): User;
}

// RegisterUserUseCaseImpl (유스케이스 계층)
class RegisterUserUseCaseImpl implements RegisterUserUseCase {
    private userRepository: UserRepository; // DIP 적용: 구체적인 구현이 아닌 인터페이스에 의존

    constructor(userRepository: UserRepository) {
        this.userRepository = userRepository;
    }

    execute(request: RegisterUserRequest): RegisterUserResponse {
        if (this.userRepository.existsByEmail(request.email)) {
            throw new Error("이미 존재하는 이메일입니다.");
        }
        const newUser = User.create(request.email, request.password); // 엔티티 계층
        const savedUser = this.userRepository.save(newUser);
        return new RegisterUserResponse(savedUser.id, savedUser.email);
    }
}
    

여기서 RegisterUserUseCaseImplUserRepository라는 인터페이스에만 의존하고 있죠? UserRepository의 구체적인 구현(예: JpaUserRepository, MongoUserRepository)은 알 필요가 없습니다. 이것이 바로 의존성 역전 원칙(DIP)을 통한 클린 아키텍처의 핵심이에요.

2. 경계(Boundary) 설정과 데이터 변환

클린 아키텍처는 시스템의 각 계층 간의 경계를 명확히 정의하는 데 중점을 둡니다. 이 경계는 대부분 인터페이스로 표현되죠. 예를 들어, 유스케이스 계층은 데이터베이스 계층에 직접 의존하지 않고, UserRepository와 같은 인터페이스에 의존합니다. 이 인터페이스는 인터페이스 어댑터 계층에서 구체적으로 구현되죠.

각 계층을 넘나들 때는 데이터 변환이 필수적입니다. 웹 요청으로 들어온 데이터는 유스케이스가 이해할 수 있는 형태(Request DTO)로, 유스케이스의 결과는 웹 응답에 적합한 형태(Response DTO)로 변환되어야 해요. 이는 인터페이스 어댑터 계층의 역할입니다. 이 과정을 통해 각 계층은 서로의 내부 구현에 대해 알 필요 없이, 정의된 데이터 형식으로만 소통하게 됩니다.

3. 점진적인 적용과 유연한 사고

클린 아키텍처는 이상적인 목표를 제시하지만, 모든 프로젝트에 처음부터 완벽하게 적용하기는 어려울 수 있습니다. 특히 작은 프로젝트나 스타트업에서는 과도한 설계가 오히려 개발 속도를 저해할 수도 있거든요. 따라서 점진적으로 적용하거나, 프로젝트의 규모와 특성에 맞춰 유연하게 변형하는 지혜가 필요합니다.

예를 들어, 처음에는 유스케이스와 엔티티 계층을 명확히 분리하는 것에 집중하고, 데이터베이스나 UI 어댑터는 최소한의 추상화로 시작할 수 있습니다. 시스템이 성장하면서 복잡성이 증가할 때, 필요에 따라 점진적으로 클린 아키텍처의 원칙들을 더 깊이 적용해나가는 것이 현명한 방법일 수 있어요.

중요한 것은 "왜 이렇게 설계해야 하는가?"라는 원칙과 철학을 이해하는 것입니다. 단순히 엉클 밥이 이렇게 하라고 했으니까 따르는 것이 아니라, 각 원칙이 어떤 문제를 해결하고 어떤 이점을 가져다주는지 깊이 고민해보는 것이죠. 이 과정을 통해 여러분은 클린 아키텍처를 여러분의 프로젝트에 최적화된 방식으로 적용할 수 있는 통찰력을 얻게 될 거예요.

클린 아키텍처 도서 리뷰: 견고하고 유지보수 가능한 소프트웨어 설계 원칙 - library, architecture, books, interior, interior design, stairs, bookshelves, bookcase, knowledge, reading, modern design, modern architecture, building, europe, modern, stuttgart, library, library, library, library, library, knowledge

Image by olivergotting on Pixabay

이 책, 어떤 개발자에게 추천할까요?

『클린 아키텍처』는 모든 개발자가 한 번쯤은 읽어봐야 할 필독서라고 감히 말씀드릴 수 있어요. 하지만 특히 이런 분들께 강력하게 추천합니다!

  • 잦은 변경과 유지보수로 고통받는 개발자:"왜 이 코드는 건드릴 때마다 다른 곳에서 문제가 터질까?" "새로운 기능 추가가 너무 힘들어!" 이런 고민을 하고 있다면, 이 책은 문제의 근본적인 원인과 해결책을 제시해 줄 거예요. 견고하고 유연한 시스템을 만드는 방법을 배우고 싶다면 꼭 읽어보세요.
  • 소프트웨어 아키텍처에 대한 갈증이 있는 시니어 개발자 및 아키텍트:특정 기술 스택에 대한 지식은 풍부하지만, 시스템 전체를 아우르는 설계 원칙과 철학에 대한 고민이 깊어지고 있다면 이 책은 좋은 길잡이가 될 겁니다. 추상적인 아키텍처 개념을 구체적인 그림으로 보여주며, 깊이 있는 통찰을 제공해주거든요.
  • 객체 지향 설계 원칙(SOLID)을 실제에 적용하기 어려운 개발자:SOLID 원칙을 이론적으로는 알지만, 실제 코드에 어떻게 녹여내야 할지 막막한 경우가 많죠. 이 책은 SOLID 원칙이 클린 아키텍처의 각 계층과 어떻게 연결되고, 시스템 전체의 유연성을 어떻게 높이는지 명확하게 보여줍니다. 이론과 실제의 간극을 줄여주는 역할을 해줄 거예요.
  • 새로운 프로젝트를 시작하려는 팀 리더 또는 개발자:프로젝트 초기에 아키텍처를 어떻게 잡느냐에 따라 프로젝트의 성패가 갈릴 수 있습니다. 이 책은 장기적으로 지속 가능한 아키텍처를 설계하는 데 필요한 기준과 방향성을 제시해 줄 거예요. 시작부터 제대로 된 뼈대를 세우고 싶다면 이 책을 참고해보세요.

물론, 막 개발을 시작한 주니어 개발자에게는 조금 어렵게 느껴질 수도 있어요. 하지만 꾸준히 개발 경험을 쌓아가면서 다시 읽어보면, 매번 새로운 깨달음을 얻게 될 겁니다. 이 책은 한 번 읽고 끝내는 것이 아니라, 개발자 커리어 내내 곁에 두고 참고할 만한 가치 있는 지침서라고 할 수 있어요.

마무리하며: 아키텍처는 여정입니다

로버트 C. 마틴의 『클린 아키텍처』는 단순히 특정 기술이나 패턴을 나열하는 책이 아니에요. 오히려 소프트웨어 개발의 본질과 철학에 대해 깊이 있는 질문을 던지고, 오랜 시간 동안 살아남을 수 있는 견고한 시스템을 만드는 원칙을 제시하는 책이랍니다.

우리는 매일같이 새로운 기술과 프레임워크가 쏟아져 나오는 시대에 살고 있잖아요? 하지만 그 어떤 기술도 변하지 않는 설계 원칙의 중요성을 대체할 수는 없습니다. 클린 아키텍처는 바로 그 변하지 않는 가치에 집중하고, 변화무쌍한 환경 속에서도 흔들리지 않는 시스템의 뼈대를 세우는 방법을 알려주죠.

이 책을 통해 SOLID 원칙을 다시 한번 되새기고, 계층형 아키텍처의 핵심인 의존성 규칙을 이해하며, 비즈니스 로직을 외부 기술로부터 독립시키는 방법을 고민해볼 수 있었으면 좋겠어요. 처음에는 조금 어렵고 추상적으로 느껴질지라도, 꾸준히 고민하고 실제 프로젝트에 적용해보려는 노력이 여러분을 더 나은 개발자로 성장시키는 데 큰 도움이 될 것이라고 확신합니다.

소프트웨어 아키텍처는 한 번의 완벽한 설계로 끝나는 것이 아니라, 끊임없이 배우고 개선해나가는 여정과 같습니다. 『클린 아키텍처』가 여러분의 그 여정에 든든한 동반자가 되어줄 거예요.

여러분은 『클린 아키텍처』를 읽으면서 어떤 부분이 가장 인상 깊었나요? 혹은 이 책을 통해 얻은 가장 큰 깨달음은 무엇이었나요? 댓글로 함께 이야기를 나눠주시면 좋겠습니다! 👇

📌 함께 읽으면 좋은 글

  • [개발 책 리뷰] 실용주의 프로그래머 리뷰: 개발자의 성장을 위한 핵심 원칙과 실천 전략
  • [튜토리얼] Node.js Apollo Server GraphQL API 구축: 개발자를 위한 실전 가이드
  • [개발 책 리뷰] 클린 아키텍처 도서 리뷰: 견고하고 유연한 소프트웨어 시스템 설계 원칙과 적용 가이드

이 글이 도움이 되셨다면 공감(♥)댓글로 응원해 주세요!
궁금한 점이나 다루었으면 하는 주제가 있다면 댓글로 남겨주세요.

반응형