ISP

안녕하세요 Jercy입니다. 오늘은 ISP(인터페이스 분리 원칙)에 대해 알아보겠습니다.
ISP는 "클라이언트가 자신이 이용하지 않는 메서드에 의존하지 않아야 한다"는 원칙입니다. 여기서 클라이언트는 코드를 사용하는 쪽, 서버는 코드를 제공하는 쪽을 의미합니다.
쉽게 말해, 클래스가 프로토콜을 채택할 때 불필요한 메서드까지 구현하게 되는 상황을 피하자는 것이 ISP의 핵심입니다. 이는 클라이언트가 사용하지 않는 메서드에 의존하게 되는 문제를 야기합니다.
ISP를 위반하게 되면 다음과 같은 문제가 발생할 수 있습니다:
1.
클라이언트가 사용하지 않는 메서드의 선언을 강제하게 됩니다.
2.
사용하지 않는 메서드를 빈 구현으로 채워야 하는 등 불필요한 코드가 늘어납니다.
3.
상속받은 클래스에서 불필요한 메서드를 오버라이딩 해야할 수도 있습니다.
4.
프로토콜을 채택한 타입들이 의도치 않게 동작할 가능성이 높아집니다.
이를 해결하기 위해선 프로토콜을 작은 단위로 쪼개서 구성하고, 꼭 필요한 메서드만 포함시켜야 합니다. Swift의 프로토콜은 이런 방식을 적극 권장하고 있습니다. Hashable, Equatable, Comparable 등 단 하나의 메서드만 요구하는 프로토콜이 대표적인 예시입니다.
iOS에서도 UITableViewDataSource와 UITableViewDelegate를 분리해 사용하는 것이 ISP를 잘 적용한 사례입니다. 두 프로토콜의 역할은 다르지만, 하나로 합쳐져 있다면 불필요한 메서드 구현을 강제하게 될 것입니다.
서버 클래스를 잘게 분해하고 인터페이스를 그룹짓는 것이 클라이언트와의 결합도를 낮추는 핵심입니다. 이는 코드의 복잡도를 높일 수 있지만, Swift의 프로토콜 지향 프로그래밍(Protocol Oriented Programming) 철학과도 잘 어울립니다.
결국 POP는 ISP에서 비롯된 개념이며, ISP를 잘 이해하고 습관화하는 것이 POP의 기반이 됩니다.
ISP는 인터페이스를 명확한 목적별로 분리하고, 인터페이스 기준으로 코딩하는 것입니다. 이는 SOLID 원칙 중 하나로, 프로토콜과 같은 개념으로 볼 수 있습니다.
예시로 10개의 문이 있고, 터치하면 문이 열리며, 문이 5초 이상 열려있으면 경보가 울리는 앱을 만든다고 가정해봅시다. 이 앱에서 ISP를 적용하기 위해 타이머 클라이언트라는 프로토콜을 만들고, 타이머와 관련된 기능을 분리합니다.
그런데 모든 문이 타이머 기능을 필요로 하는 것은 아닙니다. 이 경우 도어 클래스와 타이머 클라이언트 프로토콜 사이에 강한 커플링이 생기게 됩니다. 이는 ISP 위반이며, 인터페이스 오염이 발생한 상황입니다.
이를 해결하기 위해 어댑터 패턴을 사용하거나, 타이머 기능이 필요한 문은 타이머 클라이언트 프로토콜을 채택하도록 하는 방법 등이 있습니다. 이렇게 하면 도어 클래스와 타이머 클라이언트 프로토콜 간의 커플링을 제거할 수 있습니다.
하지만 항상 프로토콜을 만드는 것이 최선은 아닙니다. 상황에 따라 판단이 필요한데, 예를 들어 UITableViewCell과 모델 간의 관계에서 모델을 셀에 직접 넣는 것이 문제가 없다면 굳이 프로토콜을 만들 필요는 없습니다. 하지만 셀과 모델 사이를 어느 정도 분리하고 싶다면 뷰모델 등을 활용할 수 있습니다.
결국 ISP의 핵심은 인터페이스를 목적에 따라 분리해서 사용하는 것입니다. 클래스 간 인터페이스가 비대해진 경우, 필요한 부분만 프로토콜로 분리해 클래스 간 직접적인 의존성을 제거할 수 있습니다. 이를 통해 코드의 유연성이 크게 증가할 수 있습니다.
iOS 개발에서도 ISP를 적극 활용하면 좋습니다. 예를 들어 앱의 설정 화면에서 여러 종류의 설정 항목이 있다면, 각 설정 항목을 프로토콜로 분리하고 이를 채택하는 뷰 컨트롤러를 만들 수 있습니다. 이렇게 하면 설정 항목이 추가되거나 변경되어도 다른 부분의 코드에 영향을 주지 않아 유지보수가 용이해집니다.
이상으로 Swift에서의 ISP에 대해 알아보았습니다.
생각해볼 점:
1.
내가 만드는 앱에서 ISP를 적용할 만한 부분은 어디일까요?
2.
프로토콜을 사용할 때 어떤 기준으로 분리하는 것이 좋을까요?
3.
ISP를 적용했을 때의 장단점은 무엇일까요?
제 생각은 다음과 같습니다:
1.
앱의 여러 모듈 간 의존성이 강한 부분이 ISP를 적용하기 좋은 것 같습니다. 예를 들어 데이터 관련 모듈과 UI 모듈 사이의 의존성을 프로토콜로 분리하면 좋겠네요.
2.
프로토콜은 각 모듈의 역할과 책임을 기준으로 분리하는 것이 좋습니다. 한 프로토콜이 여러 역할을 갖기보다는 단일 책임 원칙을 지키는 것이 유지보수에 유리합니다.
3.
ISP 적용의 장점은 모듈 간 결합도를 낮추고 유연성과 확장성을 높일 수 있다는 점이고, 단점은 프로토콜이 너무 많아지면 관리가 힘들어질 수 있다는 점인 것 같아요. 적절한 수준에서 ISP를 활용하는 것이 중요할 것 같네요.