안녕하세요 :)
이번 시간에는 객체 지향에서 인터페이스를 사용하는 이유에 대해서 학습을 해볼게요.
(유튜브로도 학습을 하실 수 있어요. -> 유튜브 링크 클릭)
파이썬이나 자바를 학습하시다 보면 상속이라는 개념까지는 알겠습니다. 아 부모로부터 기능들을 물려받는구나 싶어요.
하지만 인터페이스를 공부할 때는 이걸 어디다 쓰지 싶습니다.
인터페이스는 상속과 달리, "기능만을 명시해 놓고 필요하면 인터페이스를 구현해서 사용해"라고 만들어 놓은 문법입니다.
인터페이스를 문법책처럼 그냥 설명을 드리지 않고 객체지향의 중요한 개념과 함께 설명을 드려볼게요.
S (Sigle responsibility principle) - 단일 책임 원칙
O (Open/closed principle) - 개방 / 폐쇄 원칙
L (Liskov substituion principle) - 리스코프 치환 원칙
I (Interface segregation principle) - 인터페이스 분리 원칙
D (Dependency inversion principle) - 의존관계 역전 원칙
SOLID 원칙은 5개의 개념 중 앞글자만 따서 만든 용어예요.
SOLID 원칙이라는, 객체지향 언어에서 소스코드를 잘 작성할 수 있도록 도와주는 설계 원칙이 있습니다.
원칙 중 앞에 2가지 원칙을 설명을 드리면서 인터페이스의 용도를 학습하겠습니다.
면접에서도 정말 많이 물어보는 게 SOLID 원칙이에요. 비단 SOLID 원칙은 면접에서만 중요한 게 아니고, 개발을 하실 때 전반적으로 필요한 개념이에요.
프로그래밍을 처음 배울 때는 기능 개발을 할 때면 큰 생각 없이 그냥 코드를 작성하기 시작했습니다. 이게 나쁜 건 아니에요. 초기에는 정말 많은 코드를 작성을 해보셔야 됩니다. 그러다가 정체되는 느낌도 들고, 내가 잘 작성을 하고 있는지에 대한 의문이 생기기 시작합니다.
이때 우리에게 필요한 건, 한 걸음 더 나아가기 위한 개념이 SOLID 원칙이에요.
SOLID 원칙을 학습하시고 난 이후에는 코드를 작성하실 때 기준이 생기게 됩니다. 원칙을 적용하시면서 개발을 하신다면 개발 재미도 올라가고, 유지보수를 위한 추가적인 기능 개발도 더 쉬어지는데요.
이번 시간에는 2가지 원칙만 살펴보겠지만, 기회가 되신다면 5가지 모두 다시 한번 학습을 하셨으면 좋겠습니다.
1. Sigle responsibility principle - 단일 책임 원칙
첫 번째는 단일 책임 원칙입니다. "하나의 클래스는 하나의 책임만 맡는다"는 내용입니다. 지금 말씀만 듣고 나시면 "뭐 당연한 거 아니야?"라고 하시는 분들도 있으실 수 있어요. 정말 훌륭하신 분이에요. 저는 SOLID 원칙을 학습하기 전에는 그렇지 못했습니다.
예를 하나 보겠습니다.
내 통장의 입출금 데이터를 읽어 들여서 분석하는 프로그램을 만든다고 합니다. 그럼 SOLID 원칙을 배우기 전에는 이런 모습의 클래스를 작성을 하였습니다.
지금의 모습처럼 하나의 클래스에 모든 기능이 들어 있는 클래스를 god class라고 합니다.
여기서 입출금 데이터를 읽는 방식을 json 방식에서 파일로 변경을 한다고 하면 어느 부분을 수정 개발을 해야 될까요?
god 클래스 내의 데이터를 읽는 부분을 수정 개발을 하시면 되겠죠. 이 부분을 지우고 추가하고, 벌써부터 코드들이 복잡해지는 느낌이 들지 않나요? 하나의 클래스는 점점 거대 해질 거고, 테스트를 함에도 어려움이 있습니다.
읽는 부분만을 수정해도 god 클래스에서는 파싱, 결과 처리(집계), 레포트 기능까지 모두 수행이 되기 때문에 모든 부분이 영향범위에 포함이 되는 겁니다. 나는 데이터를 읽는 부분만 추가 개발을 하고 싶은데 영향범위는 이렇게 넓은 이 모습, 추가 기능을 붙일수록 점점 영향 범위가 커지는 걸 알 수 있습니다.
모든 기능이 포함된 god 클래스를 기능별로 클래스를 분리하겠습니다.
클래스를 기능별로 분리를 해놓으면 필요한 부분을 찾기도 쉽습니다.
main 클래스에서는 분리해놓은 클래스를 호출해서 사용을 해주시면 되겠습니다. 데이터를 읽는 부분만을 수정을 하신다 면 읽기 담당을 하는 클래스만 수정을 하기 때문에 영향범위는 읽기 클래스 내에만 국한이 되겠습니다. 읽기 클래스를 수정해도 다른 클래스들은 수정을 하지 않았기 때문이에요.
이렇게 하나의 클래스는 하나의 기능만을 책임지는 것이 단일 책임 원칙입니다.
다음으로 개방 / 폐쇄 원칙을 살펴볼게요.
2. Open/closed principle - 개방 / 폐쇄 원칙
개방 / 폐쇄 원칙은 "기능에 대한 추가 및 확장은 open(개방) 되어 있고, 기능을 사용하는 코드들은 closed(폐쇄) 되어 있다"는 내용입니다.
위의 이야기대로라면 "다른 코드는 건들지 않고, 기능 추가를 할 때는 기능 추가에 대한 코드만 작성"을 하면 된다는 원칙입니다. 처음 들을 때는 그럴 수가 있나요? 싶습니다.
개방 / 폐쇄 원칙은 앞에서의 단일 책임 원칙의 대한 연장선이에요. 결론부터 말씀을 드리자면 이 부분에서 인터페이스라는 기능을 사용하여 OCP를 지킬 수 있습니다.
통장의 입출금 데이터 프로그램에서 JSON 대신에 파일을 통해서 데이터를 읽어 들인다면, 파일로 읽어 드리는 클래스만을 개발 개발을 해주시면 돼요. JSON 읽기 클래스는 AccountRead 인터페이스를 구현하였습니다. 마찬가지로 파일로 읽는 FileRead 클래스도 AccountRead 인터페이스를 구현하겠습니다.
main 클래스에서는 AccountRead 타입형을 선언해주고, AccountRead를 구현한 FileRead 객체로 변경을 해주시면 되겠습니다. 그럼 main 함수 내에서는 다른 코드를 수정해야 될 게 있을까요? 전혀 없습니다. 이미 AccountRead 인터페이스 타입으로 기능들이 잘 돌아가고 있습니다.
만약 main 클래스 내에서 인터페이스를 사용하지 않고, JsonRead나 FileRead 같은 단독 클래스를 사용하셨더라면 인터페이스와 같은 정해진 명세가 없기 때문에 개발자마다 메서드 이름과 메서드 개수들이 다르게 만들어집니다. 그렇게 된다면 main 함수 내의 수정을 피할 수 없겠습니다.
하지만 인터페이스를 사용하게 되면,
인터페이스는 필요한 기능들을 미리 명세해놓고, main 함수 내에서는 AccountRead형으로 readData, readParsing 기능이 사용되어지고 있었습니다. 내부 구현은 상황에 맞춰서 json 형태로 읽든 파일로 읽든 개발자가 구현해주고, main 함수 내에서는 계좌 데이터를 읽는 것에 대해서 변함이 없는 거예요.
OCP 원칙을 볼 때 필요한 기능인 파일로 읽기 기능을 추가 개발하고 이게 open이고, main 함수 내에서 readData, readParsing 기능을 사용하는 다른 코드들은 수정하지 않는 closed 되어 있는 모습을 보실 수 있겠습니다.
인터페이스가 필요한 경우를 한 줄로 설명을 하자면,
지금의 기능이 이후에 확장이 필요할 것 같다면 인터페이스를 사용해서 개발을 해주셔야 돼요. 그래야 필요한 기능만을 개발하고 다른 코드는 건들지 않겠습니다.
도움이 되셨으면 하는 마음과 함께 인터페이스가 필요한 이유에 대해서 설명을 마치도록 할게요.
감사합니다.
'책 기록 > 책 서평' 카테고리의 다른 글
#2 리얼월드 HTTP - HTTP의 의미와 구성 요소 (0) | 2022.10.30 |
---|