서론: 왜 이런 원칙이 필요할까요?
소프트웨어 개발을 하다 보면 이런 순간이 한두 번이 아닙니다. "이 코드 대체 왜 이렇게 꼬였지?", "이거 수정하려면 어디까지 손대야 하는 거야?" 같은 생각, 해보셨죠? 한 번 엉킨 코드 베이스는 풀기 어려워지고, 유지보수가 힘들어지면서 프로젝트가 산으로 갑니다.
그래서 오늘은 더 깔끔하고, 유지보수하기 편한 코드를 작성할 수 있도록 도와줄 세 가지 필수 원칙을 소개하려고 합니다. 바로 단일 책임 원칙(SRP), 개방-폐쇄 원칙(OCP), 그리고 **의존성 역전 원칙(DIP)**입니다. 각각이 무슨 의미인지, 실제 코드에서는 어떻게 적용할 수 있는지 쉽게 풀어볼게요. 자, 그럼 시작해볼까요? 🚀
원칙 1: 단일 책임 원칙(SRP)
SRP가 뭐냐면요...
쉽게 말해, 클래스 하나가 여러 역할을 동시에 하지 말자! 라는 원칙입니다. 기능이 너무 많으면 수정할 때 문제가 생기고, 코드가 금방 난장판이 될 수 있어요.
SRP를 안 지키면 벌어지는 일
이 코드 한번 볼까요?
class AuthService:
def login(self, username, password):
print("사용자 인증 완료")
self.log_event("사용자 로그인")
def log_event(self, event):
with open("log.txt", "a") as file:
file.write(event + "\n")
인증하는 코드랑 로그 기록하는 코드가 한 곳에 엉켜 있습니다. 나중에 로그 방식이 바뀌면? 인증 코드도 같이 수정해야 하는 불상사가 생길 수 있어요.
SRP를 지키면 이렇게 바뀝니다
class Logger:
def log(self, event):
with open("log.txt", "a") as file:
file.write(event + "\n")
class AuthService:
def __init__(self, logger):
self.logger = logger
def login(self, username, password):
print("사용자 인증 완료")
self.logger.log("사용자 로그인")
이제 인증과 로그 기록이 완전히 분리되었죠? 덕분에 로그인 관련 기능만 수정하고 싶을 때 로그 쪽은 신경 쓰지 않아도 됩니다! 😃
원칙 2: 개방-폐쇄 원칙(OCP)
OCP란?
새로운 기능을 추가할 때 기존 코드를 건드리지 않는 것, 바로 이게 개방-폐쇄 원칙입니다.
OCP를 안 지키면 벌어지는 일
class DiscountCalculator:
def calculate(self, price, discount_type):
if discount_type == "percentage":
return price * 0.9
elif discount_type == "fixed":
return price - 10
else:
return price
할인 방식이 추가될 때마다 이 코드 수정해야 합니다. 조건문이 늘어나면서 코드가 점점 지저분해지겠죠? 😨
OCP를 지키면 이렇게 바뀝니다
from abc import ABC, abstractmethod
class DiscountStrategy(ABC):
@abstractmethod
def apply_discount(self, price):
pass
class PercentageDiscount(DiscountStrategy):
def apply_discount(self, price):
return price * 0.9
class FixedDiscount(DiscountStrategy):
def apply_discount(self, price):
return price - 10
class DiscountCalculator:
def __init__(self, discount_strategy):
self.discount_strategy = discount_strategy
def calculate(self, price):
return self.discount_strategy.apply_discount(price)
이제 새로운 할인 정책을 추가할 때 기존 코드를 건드릴 필요가 없어요! 새로운 할인 클래스를 만들어 추가하기만 하면 되니까 훨씬 깔끔합니다. 👍
원칙 3: 의존성 역전 원칙(DIP)
DIP란?
핵심 기능이 세부 구현에 직접 의존하면 안 된다는 원칙입니다. 쉽게 말하면, 인터페이스를 통해 의존성을 관리하라는 뜻이에요.
DIP를 안 지키면 이런 일이 생깁니다
class EmailNotifier:
def send(self, message):
print(f"이메일 전송: {message}")
class UserService:
def __init__(self):
self.notifier = EmailNotifier()
def notify_user(self, message):
self.notifier.send(message)
UserService가 EmailNotifier에 직접 의존하고 있어요. 만약 알림 방식을 SMS로 바꾸려면? UserService까지 수정해야 합니다. 비효율적이죠.
DIP를 적용하면?
from abc import ABC, abstractmethod
class Notifier(ABC):
@abstractmethod
def send(self, message):
pass
class EmailNotifier(Notifier):
def send(self, message):
print(f"이메일 전송: {message}")
class SMSNotifier(Notifier):
def send(self, message):
print(f"SMS 전송: {message}")
class UserService:
def __init__(self, notifier):
self.notifier = notifier
def notify_user(self, message):
self.notifier.send(message)
이제 UserService는 Notifier 인터페이스에 의존하기 때문에, EmailNotifier든 SMSNotifier든 쉽게 바꿀 수 있습니다. 확장성도 좋아지고 유지보수도 쉬워지죠! 💡
결론: 이 원칙들, 왜 중요한 걸까요?
지금까지 SRP, OCP, DIP 원칙을 살펴봤어요. 이 원칙들을 잘 적용하면 코드가 훨씬 깔끔해지고, 유지보수도 쉬워지며, 확장도 편해집니다. 처음에는 귀찮을 수도 있지만, 장기적으로 보면 개발 속도가 빨라지고 코드가 더 탄탄해지는 걸 경험하게 될 거예요.
혹시 지금 코드가 너무 복잡해서 스트레스 받고 있다면, 이 원칙들을 하나씩 적용해 보세요. 결과적으로 더 유연하고 효율적인 소프트웨어 개발이 가능해질 겁니다. 😃
그럼, 즐거운 코딩 하세요! 🚀
'SW > 면접' 카테고리의 다른 글
개발자라면 꼭 알아야 할 Clean Code 작성법 5가지 꿀팁 (0) | 2025.04.18 |
---|---|
Fault Tolerance 시스템 쉽게 이해하기: 서비스가 멈추지 않도록 하는 법 (0) | 2025.04.09 |
Kafka란? 쉽게 이해하는 실시간 데이터 처리 시스템 (0) | 2025.04.06 |
가비지 컬렉션이란? 초보 개발자를 위한 쉬운 개념 정리 (0) | 2025.04.03 |
컴퓨터공학 학위를 활용해 실무 기술 쌓는 방법 (0) | 2025.03.22 |