inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

SOLID의 모든 원칙은 결국 "추상화"로 수렴한다.

service
0

1주일 동안의 강의 내용

결론부터 말하자면 SOLID원칙 모두 구체적인 구현에 의존하지말고 추상화를 통해 유연한 설계를 하라는 점에서 공통된다.

1⃣ OCP (개방-폐쇄 원칙: Open-Closed Principle)

“확장은 가능하지만, 기존 코드는 수정하지 말것”

새로운 기능을 추가할 때 기존 코드를 변경하지 않고, 새로운 기능을 담당하는 객체를 생성하고 새로운 기능과, 기존 기능을 확장할 수 있도록 인터페이스를 활용하여 설계를 가능하게 해야한다.

추상화 적용 → Shape 인터페이스를 만들고 Circle, Rectangle 등이 이를 구현하면 Shape을 확장해도 기존 코드 변경 없이 새로운 도형을 추가할 수 있음.

interface Shape {
    double area();
}

class Circle implements Shape {
    private double radius;
    public Circle(double radius) { this.radius = radius; }
    public double area() { return Math.PI * radius * radius; }
}

class Rectangle implements Shape {
    private double width, height;
    public Rectangle(double width, double height) { this.width = width; this.height = height; }
    public double area() { return width * height; }
}

// 기존 코드 수정 없이 새로운 도형 추가 가능

해당 부분에서 Triangle과 같은 새로운 기능이 추가 되어도, 기존의 코드를 수정하는 것이 아닌 Shape를 구현할 수 있게 해주면 된다.

2⃣ ISP (인터페이스 분리 원칙: Interface Segregation Principle)

“인터페이스는 클라이언트가 사용하지 않는 기능을 강요해서는 안된다”

하나의 거대한 인터페이스, 즉 하나의 개념에 대해서 그 개념을 모두 통괄할 수 있는 인터페이스를 만드는 것이 아닌 역할별로 분리된 작은 인터페이스를 설계해야 한다.

interface Bird {
	void fly();
}

class ButterFly implements Bird {
	void fly() {
	 System.out.println("fly");
  }
}

class Penguin implements Bird {
	 void fly() {
		 	 System.out.println("can't fly...only walk");
	 }
}

✅ 현재 Penguin은 날지 못하지만 Bird란 추상적인에 속해 fly를 강요받는다…

추상화 적용 → 여러 개의 인터페이스로 분리하여 불필요한 의존성을 줄이고, 유연한 설계 가능.

interface Fly {
 void fly();
}
interface Walk {
	void walk();
}

이렇게 기능을 작은 단위의 인터페이스로 쪼개서 사용하면 된다.

3⃣ LSP (리스코프 치환 원칙: Liskov Substitution Principle)

“하위 클래스는 상위 클래스의 기능을 대체할 수 있어야 한다”

상위 클래스 타입으로 하위 클래스를 사용해도 정상적으로 동작해야 한다. 이를 위해 추상화된 부모 클래스를 만들고 이를 확장하는 하위 클래스 들이 부모의 행위를 그대로 유지해야 한다.

추상화 적용 → 하위 클래스는 상위 클래스의 동작을 유지해야 함.

class Bird {
    void fly() { System.out.println("Flying..."); }
}

class Sparrow extends Bird { } // 정상적으로 동작

class Ostrich extends Bird {
    @Override
    void fly() { throw new UnsupportedOperationException("I can't fly!"); } // LSP 위반
}

✅ Ostrich는 Bird이지만 날 수 없음 → fly()를 강제하는 구조 자체가 잘못됨

이를 해결하려면 Flyable 인터페이스를 분리하여, 날 수 있는 새만 이를 구현하도록 해야 함

4⃣ DIP (의존성 역전 원칙: Dependency Inversion Principle)

“상위 모듈이 하위 모듈에 의존하는 것이 아니라 둘 다 추상화(인터페이스)에 의존해야 한다.”

즉 구체적인 클래스가 아니라 인터페이스나 추상 클래스를 사용하여 의존성을 주입받아야 한다.

interface Repository {
		void save();
}
class MySQLRepository implements Repository{
		void save() {
			System.out.println("MySQL Save Processing");
		}
}
class JPARepository implements Repository {
		void save();
}

Repository라는 추상화를 적용시켜서 이를 구현한 구현체로 MySQL, JPA, MongoDB… 새로운 DB가 추가 되어도 구현체에 직접 의존하는 것이 아닌 상위 모듈을 의존성 주입받아 런타임에 구현체를 동적으로 변경할 수 있도록 구현한다.

결론: 모든 원칙이 “추상화”로 수렴한다.

📌 OCP (개방-폐쇄 원칙)추상화(인터페이스)를 이용하면 기존 코드를 수정하지 않고도 확장 가능

📌 ISP (인터페이스 분리 원칙)불필요한 의존성을 제거하고, 필요한 기능만 제공하는 인터페이스 설계

📌 LSP (리스코프 치환 원칙)추상화를 잘못하면 하위 클래스가 부모 클래스를 대체하지 못함 → 올바른 추상화가 중요

📌 DIP (의존성 역전 원칙)구체적인 구현이 아니라 추상화(인터페이스)에 의존해야 함.

📌 SRP (단일 책임 원칙)클래스는 단 하나의 책임만을 가지고 있어야 하고, 해당 클래스가 변경될 경우 그 이유는 오로지 책임에 의한 것이어야 함. → SRP 또한 각 클래스가 하나의 역할만 수행하므로 자연스럽게 추상화가 이루어지고, 다른 SOLID 원칙들고 적용하기 쉬워진다.


1주일 동안의 회고

깊은 내공이 느껴지는 강의를 듣고 과연 나의 코드는 읽기 좋은 코드는 못 될지 언정 과연 읽을만 한가?라고 생각하며 여태 했던 개인프로젝트들과 팀 프로젝트의 코드들을 살펴보았고, 이번 일주일 동안 강의에서 배운 SOLID원칙을 활용한 추상과 구체, 논리와 사고의 흐름 및 사고의 깊이 줄이기 같은 요소들을 하나둘씩 살펴보았다.

 

긴 시간은 투자하지 못했지만 OCP와 DIP, SRP 원칙만큼은 쉽게 눈에 보이는 레벨에서 고쳐나갈 수 있다고 생각하고 나름 만족할 만큼 적용했다고 생각한다.

 

나는 개인적으로 객체지향이라는 개념 자체가 너무 추상화되어있는 표현 혹은 단어라고 생각한다. 이것에 대한 개념에 대해서 알고있어도 초보자 레벨에서 이를 적용시키기란 매우 어렵고, 사람마다 그 기준이 너무나도 다르기 때문에 정답은 없는 것 같다라는 생각이 든다. 정답은 없지만 정답에 가까운 그런 방식은 있을 것이라고 생각한다.

 

나는 사실 내가 객체지향을 초보자 레벨에서는 나름 잘 적용해왔다고 생각해 왔었다. 그 이유는 우테코 프리코스를 2번이나 해보면서(2번 다 떨어졌다…) 그리고 실제로 친한 중고등학교 친구가 배민에서 개발자로 일하기 때문에 친구가 일주일에 한번씩 코드리뷰도 해주었었다.(많이 혼났었지만…) 나름 객체지향이라는 개념과 SRP, OCP, DIP라는 개념은 실무에서도 실제로 가장 강력한 무기가 될 수 있기에 잘 지켜왔었다고 생각한다.

 

결론은 “추상화”가 가장 중요한데.. 이부분이 제일 어렵다.

 

그래서 코드를 작성할 때 이 부분만큼은 옆에 메모장에 띄워놓고 익숙해질 때까지 해야한다 라고 생각한다.

1. 코드는 적절한 수준에서 추상화되어야 한다.

2.논리와 사고의 흐름

3. 사고의 깊이 줄이기

결론

적절한 추상화 → 코드가 마치 살아있고 객체지향적인 코드가 나타난다. 이는 코드의 유연성을 높인다.

논리적인 흐름 → 코드를 읽을 때 직관적인 이해를 돕기 때문에 유지보수하기 편하고, 소프트웨어의 품질을 높일 수 있다.

사고의 깊이 줄이기 → 코드를 한번에 쉽게 파악할 수 있도록 만들기 때문에 유지 보수 및 기능 추가 등등의 비용을 줄일 수 있다.


Day2, Day4 미션에 대한 회고

Day2 주제 : 추상과 구체에 대한 예시 3~5문장으로 정리하기.

[해결 과정]

[접근 방식]

Day4 주제 : 코드 리팩토링, SOLID에 대한 자기만의 언어로 정리.

[해결과정]

[접근 방식]

백엔드 워밍업클럽3기BE

답변 0