SOLID๋ผ๋ ์ฉ์ด๋ ๊ฐ์ฒด ์ค๊ณ์ ํ์ํ 5๊ฐ์ง ์์น์ ์ฝ์๋ก, ์ ์ง๋ณด์๊ฐ ์ฝ๊ณ , ์ ์ฐํ๊ณ , ํ์ฅ์ด ์ฌ์ด ์ํํธ์จ์ด๋ฅผ ๋ง๋๋๊ฒ์ ๋ชฉ์ ์ผ๋ก ํ๋ค.
Clean Agile
, Clean Achitecture
, Clean Code
, Clean Software
๋ฑ์ ํด๋ฆฐ์ฝ๋์ ๋ํ ์ฑ
์ ๋ง์ด ์ฐ์ ๋ก๋ฒํธ C.๋งํด(aka. Uncle Bob)์ด 2000๋
์ ๋
ผ๋ฌธ "Design Principles and Design Patterns"์์ ๋ฐํํ ๋ด์ฉ์ด๋ค.
์์ ์ค๋ช ํ๋๋ก SOLID๋ ์ฝ์ด์ธ๋ฐ, ๊ฐ S๋ ๋จ์ผ ์ฑ ์ ์์น(Single Responsibility Principle), O๋ ๊ฐ๋ฐฉ-ํ์ ์์น(Open-Closed Principle), L์ ๋ฆฌ์ค์ฝํ ์นํ ์์น(Liscov Substitution Principle), I๋ ์ธํฐํ์ด์ค ๋ถ๋ฆฌ ์์น(Interface Segregation Principle), D๋ ์์กด์ฑ ์ญ์ ์์น(Dependency Inversion Principle)์ ์๋ฏธํ๋ค.
๋จ์ผ ์ฑ ์ ์์น์ "ํด๋์ค๋ฅผ ๋ณ๊ฒฝํด์ผ ํ ์ด์ ๋ ๊ณ ์ ํด์ผ ํ๋ค. ์ฆ, ํด๋์ค๋ ํ๋์ ์ฑ ์์ ๊ฐ์ ธ์ผ ํ๋ค๋ ๋ป์ด๋ค." ๋ผ๊ณ ๋งํ๋ค. ์ฌ๊ธฐ์ ๋งํ๋ ์ฑ ์์ด๋ ๋ณ๊ฒฝ์ ์ด์ ๋ฅผ ๋ปํ๋ค. ํ๋์ ํด๋์ค๋ฅผ ๋ณ๊ฒฝํด์ผ ํ๋ ์ด์ ๊ฐ ์ฌ๋ฌ๊ฐ ๋ ์ค๋ฅธ๋ค๋ฉด ์ด ํด๋์ค๋ ์ฌ๋ฌ ์ฑ ์์ ๊ฐ์ง๊ณ ์๋ค๋๊ฒ๊ณผ ๊ฐ์ ๋ป์ด๋ค. ๋, ํ๋์ ์ฑ ์์ ์ฌ๋ฌ ํด๋์ค์ ๋๋ ๋๋๊ฒ๋ ์๋๋ฉฐ ์ด๊ฒ๋ค์ ์งํค์ง ์์ผ๋ฉด ์ฝ๋์ ๋ณํ๋ฅผ ์ค์ผ ํ ๋ ์ฌ๋ฌ๊ณณ์ ์์ ํด์ผํ๋ ์ํฉ์ด ๋ฐ์ํ๊ธฐ ๋๋ฌธ์ ์ ์ง๋ณด์๊ฐ ๋งค์ฐ ๋นํจ์จ์ ์ด๊ฒ ๋๋ค.
/// Before
class Factory {
public func excute() {
let responseData = self.requestData()
let parsingData = self.parse(data: responseData)
self.save(item: parsingData)
}
private func requestData() -> Data {
/// Request Data And Wait Response
}
private func parse(data: Data) -> [String] {
/// Parsing Responsed Data
}
private func save(item: [String]) {
/// Save Item at Local DataBase
}
}
/**
ํ๋์ ํด๋์ค๊ฐ ์ฌ๋ฌ๊ฐ์ ์ฑ
์(private์ผ๋ก ์ ๊ทผ์ ํ ๋ ๋ค์ํ ๋ฉ์๋๋ค)์ ๊ฐ์ง๊ณ ์๋ค.
*/
/// After
class Factory {
let requester = Requester()
let converter = Converter()
let database = Database()
public func excute() {
let responseData = self.requester.getData()
let parsingData = self.converter.convert(to: responseData)
self.database.save(item: parsingData)
}
}
class Requester {
internal func getData() -> Data {
/// Request Data And Wait Response
}
}
class Converter {
private func convert(to data: Data) -> [String] {
/// Parsing Responsed Data
}
}
class Database {
private func save(item: [String]) {
/// Save Item at Local DataBase
}
}
/**
ํ๋์ ํด๋์ค๊ฐ ์ฑ
์์ ํ๋์ฉ๋ง ๊ฐ์ง๊ณ ์๋ค.
*/
๊ฐ๋ฐฉ-ํ์ ์์น์ "์ํํธ์จ์ด ์ํฐํฐ(ํด๋์ค, ๋ชจ๋, ๊ธฐ๋ฅ ๋ฑ)๋ ํ์ฅ์๋ ์ด๋ ค ์์ด์ผ ํ์ง๋ง ๋ณ๊ฒฝ์๋ ๋ซํ์์ด์ผ ํ๋ค" ๊ณ ๋งํ๋ค.
ํ์ฅ์ ์ด๋ ค์๋ค๋ ๊ฒ์ ์ํฐํฐ๋ฅผ ํ์ฅํ ๋ ์ฝ๊ฒ ํด์ผ ํ๋ค๋ ๊ฒ์ด๋ฉฐ, ๋ณ๊ฒฝ์ ๋ซํ์๋ค๋ ๊ฒ์ ์ํฐํฐ๋ฅผ ํ์ฅํ ๋ ์ฝ๋๋ฅผ ๋ณ๊ฒฝ ํ์ง ์๊ณ ๋ ๊ฐ๋ฅํด์ผ ํ๋ค๋๊ฒ์ ์๋ฏธํ๋ค. ์ฆ, ๊ธฐ์กด์ ์ฝ๋๋ฅผ ๋ณ๊ฒฝํ์ง ์๊ณ ๊ธฐ๋ฅ์ ์์ ํ๊ฑฐ๋ ์ถ๊ฐํ ์ ์๋๋ก ์ค๊ณํด์ผ ํ๋ ์์น์ด๋ค.
์ด๋ค ๋ชจ๋์ด๋ ๊ธฐ๋ฅ์ ํ๋ ์์ ํ ๋, ๊ทธ ์ํฐํฐ๋ฅผ ์ด์ฉํ๋ ๋ค๋ฅธ ์ํฐํฐ ์ญ์ ์ค์ค์ด ๊ณ ์ณ์ผ ํ๋ค๋ฉด ์ ์ง๋ณด์๊ฐ ๋ณต์กํ ๊ฒ์ด๋ค. ๋ฐ๋ผ์ ๊ฐ๋ฐฉ-ํ์ ์์น์ ์ ์ ์ฉํ์ฌ ๊ธฐ์กด ์ฝ๋๋ฅผ ๋ณ๊ฒฝํ์ง ์์๋ ๊ธฐ๋ฅ์ ์๋กญ๊ฒ ๋ง๋ค๊ฑฐ๋ ๋ณ๊ฒฝํ ์ ์๋๋ก ํด์ผ ํ๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ๊ฐ์ฒด์งํฅ ํ๋ก๊ทธ๋๋ฐ์ ๊ฐ์ฅ ํฐ ์ฅ์ ์ธ ์ ์ฐ์ฑ
, ์ฌ์ฌ์ฉ์ฑ
, ์ ์ง๋ณด์์ฑ
๋ฑ์ ๋ชจ๋ ์์ด๋ฒ๋ฆฌ๋ ์
์ด๊ณ , OOP๋ฅผ ์ฌ์ฉํ๋ ์๋ฏธ๊ฐ ์ฌ๋ผ์ง๊ฒ ๋๋ค.
OCP ๋ ์ถ์ํ (์ธํฐํ์ด์ค) ์ ์์ (๋คํ์ฑ) ๋ฑ์ ํตํด ๊ตฌํํด๋ผ ์ ์๋ค. ์์ฃผ ๋ณํํ๋ ๋ถ๋ถ์ ์ถ์ํํจ์ผ๋ก์จ ๊ธฐ์กด ์ฝ๋๋ฅผ ์์ ํ์ง ์๊ณ ๋ ๊ธฐ๋ฅ์ ํ์ฅํ ์ ์๋๋ก ํจ์ผ๋ก์จ ์ ์ฐํจ์ ๋์ด๋ ๊ฒ์ด ํต์ฌ์ด๋ค.
/**
์บ๋ฆญํฐ๋ฅผ ํ๋ ์ถ๊ฐํ๋ค๊ณ ํ ๋, ๊ฐ๊ฐ์ ์บ๋ฆญํฐ๊ฐ ์์ง์์ด ๋ค๋ฅผ ๊ฒฝ์ฐ ์์ง์์ ํจํด ๊ตฌํ์ ํ์ ํด๋์ค์ ๋งก๊ธด๋ค๋ฉด
์บ๋ฆญํฐ ํด๋์ค์ ์์ ์ ํ์๊ฐ์๊ณ (Closed) ์์ง์์ ํจํด๋ง ์ฌ์ ์ ํ๋ฉด(Open) ๋๋ค.
*/
/// Before
enum Country {
case korea
case japan
case usa
}
class Flag {
let country: [Country]
func name(_ country: Country) {
switch country {
case korea:
print("ํ๊ตญ")
case japan:
print("์ผ๋ณธ")
case usa:
print("๋ฏธ๊ตญ")
}
}
}
/**
Country ์ด๊ฑฐํ์ case๋ฅผ ์ถ๊ฐํ๋ฉด name(_:) ํจ์๋ ์์ ํด์ผ ํ๋ค.
๊ฒฐํฉ๋์ ์์กด์ฑ์ด ๋๊ณ , ์ ์ง๋ณด์๊ฐ ํ๋ค๋ค.
*/
/// After
protocol Country {
var name: String
}
struct Korea: Country {
var name = "ํ๊ตญ"
}
struct Japan: Country {
var name = "์ผ๋ณธ"
}
struct USA: Country {
var name = "๋ฏธ๊ตญ"
}
class Flag {
var country: [Country]
func name(_ country: Country) {
print(country.name)
}
}
/**
๋๋ผ๋ฅผ ์ถ๊ฐํ๊ณ ์ถ๋ค๋ฉด Country๋ฅผ ์ฑํํ๋ ๊ตฌ์กฐ์ฒด๋ฅผ ๋ง๋ค๊ธฐ๋ง ํ๋ฉด ๋๋ค.
๊ฒฐํฉ๋๊ฐ ๋ฎ๊ณ , ์์ง๋๊ฐ ๋์ ์ ์ง๋ณด์์ ์ฉ์ดํ๋ค
*/
๋ฆฌ์ค์ฝํ ์นํ ์์น์ "์์ ํด๋์ค๋ ์ธ์ ๋ ์์ ์ ๋ถ๋ชจ ํด๋์ค๋ฅผ ๋์ฒดํ ์ ์์ด์ผ ํ๋ค." ๊ณ ๋งํ๋ค. ์๋ฅผ ๋ค์ด C๋ผ๋ ํด๋์ค์์ A๋ผ๋ ๋ถ๋ชจ ํด๋์ค๋ฅผ ์ฌ์ฉํ๋๋ฐ B๋ผ๋ A๋ฅผ ์์๋ฐ์ ์์ ํด๋์ค๋ก ๋์ฒดํด๋ C๋ผ๋ ํด๋์ค์์๋ ์๋ฌด๋ฐ ์ํฅ์์ด ์ ์์ ์ผ๋ก ๊ฐ์ ๋์์ํด์ผ ํ๋ค๋ ๊ฒ์ด๋ค.
/// Before
class Rectangle {
var width: Int
var height: Int
var area: Int {
return width * height
}
init(width: Int, height: Int) {
self.width = width
self.height = height
}
}
class Square: Rectangle {
override var width: Int {
didSet {
super.height = width
}
}
override var height: Int {
didSet {
super.width = height
}
}
}
let sqaure = Sqaure(width: 10, height: 10)
self.checkArea(of: sqaure)
func checkArea(of item: Rectangle) {
item.width = 9
item.height = 3
print(item.area)
}
/**
ํจ์ ๋ด์์ ์ง์ฌ๊ฐํ์ ๋ฉด์ ์ด 9*3์ ์์ํ๊ฒ ์ง๋ง, ์ค์ ๋ก 3*3์ด ์ถ๋ ฅ๋๋ค.
์ด๋ ์๋ชป๋ ๋์์ ์คํํ ๊ฒ์ด๊ณ , ์๋ธํด๋์ค๊ฐ ์ํผํด๋์ค ๋์ ์ฌ์ฉ๋๋ ๊ฐ์ ๋์์ ํ๋ค๊ณ ๋ณด๊ธฐ ์ด๋ ต๋ค.
*/
/// After
protocol Geometrics {
var area: Int
}
class Rectangle: Geometrics {
var width: Int
var height: Int
var area: Int {
return width * height
}
init(width: Int, height: Int) {
self.width = width
self.height = height
}
}
class Square: Geometrics {
var edge: Int
var area: Int {
return edge * edge
}
init(edge: Int) {
self.edge = edge
}
}
// print -> 50
let geometric1: Geometrics = Rectangle(width: 10, height: 5)
print(geometric1.area)
// print -> 25
let geometric2: Geometrics = Sqaure(edge: 5)
print(geometric2.area)
/**
์์ ํด๋์ค๊ฐ ๋ฐ๋์ด๋ ๊ฐ์ ๋์์ ํด๋ธ๋ค.
๋ ํด๋์ค๊ฐ ๊ฐ์ ธ์ผ ํ ๋์ผํ ๊ฐ์ ํ๋กํ ์ฝ์ ์์๋ฐ๋ ๊ฒ์ผ๋ก ๋ณด์ฅํ๋ค.
์ด๋ ๊ฒ ํ๋ฉด ํ์ํ ๊ฐ์ด๋ ๋์๋ง ์ฌ์ฉํ ์ ์๋๋ก ๋ณด์ฅํ ์ ์๊ธฐ ๋๋ฌธ์
์์ ๊ฐ๋ฅํ ์๋๋ฆฌ์ค๋ฅผ ๋ง๋ค ์ ์๋ค.
*/
์ธํฐํ์ด์ค ๋ถ๋ฆฌ ์์น์ "ํด๋ผ์ด์ธํธ๋ ๋ถํ์ํ ์ธํฐํ์ด์ค์ ์์กดํ๋ฉด ์๋๋ค. ์ฆ, ์ฌ์ฉํ์ง ์๋ ์ธํฐํ์ด์ค๋ ๊ตฌํํ์ง ๋ง์์ผ ํ๋ค." ๊ณ ๋งํ๋ค. Uncle Bob์ด ๋ ผ๋ฌธ์์ ์์ฃผ ์ฌ์ฉํ๋ ์ฉ์ด๋ก Fat Interface๊ฐ ์๋ค. ์ด๋ฌํ ์ธํฐํ์ด์ค(Swift - Protocol)๋ ์์ง๋ ฅ์ด ์๋ค๊ณ ๊ฐ์ฃผ๋๋ค. ์ฝ๊ฒ ๋งํด ํด๋ผ์ด์ธํธ๊ฐ ํ์๋ก ํ๋ ๊ฒ๋ณด๋ค ๋ ๋ง์ ๋ฉ์๋/๊ธฐ๋ฅ์ ๊ฐ์ง ์ ์๊ณ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ฑ๋ฑํ ์ธํฐํ์ด์ค๋ ISP ์์น์ ๋ฐ๋ฅด์ง ์๋ ์ธํฐํ์ด์ค์ด๋ค.
๋ฑ๋ฑํ ์ธํฐํ์ด์ค๋ฅผ ๋ณ๊ฒฝํด์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ์๊ธด๋ค๋ฉด ํด๋น ์ธํฐํ์ด์ค๋ฅผ ์์ํ๋ ๋ชจ๋ ํด๋์ค๋ฅผ ๋ชจ๋ ๋ณ๊ฒฝํ๊ณ ๋ค์ ํ ์คํธํด์ผํ๋ ์ผ์ด ์๊ฒจ ํ ์คํธ๊ฐ ๋ ์ด๋ ค์์ง๊ณ ๋ถํ์ํ ๋ฆฌํํฐ๋ง์ด ์๊ธฐ๋ ๋ฌธ์ ๋ค์ด ๋ฐ์ํ๊ฒ ๋๋ค.
/// Before
protocol Animal {
func run()
func swim()
func fly()
}
class Dolphin: Animal {
func swim()
/// NOT USED
func run() { }
func fly() { }
}
class Dog: Animal {
func run() { }
func swim() { }
/// NOT USED
func fly() { }
}
class Duck: Animal {
func fly() { }
func run() { }
func swim() { }
}
/**
Duck์ ๋ชจ๋ ์ฌ์ฉํ์ง๋ง Dog, Dolphin์ ์ฌ์ฉํ์ง ์๋ ํจ์๋ค์ด ์กด์ฌํ๋ค.
*/
/// After
protocol Runable {
func run()
}
protocol Swimable {
func swim()
}
protocol Flyable {
func fly()
}
class Dolphin: Swimable {
func swim() { }
}
class Dog: Runable, Swimable {
func run() { }
func swim() { }
}
class Duck: Runable, Swimable, Flyable {
func fly() { }
func run() { }
func swim() { }
}
/**
ํ๋กํ ์ฝ์ ๋ถ๋ฆฌํจ์ผ๋ก์จ ํ์ํ ํ๋กํ ์ฝ๋ง ์์๋ฐ์ ์ฌ์ฉํ์ง ์๋ ํจ์๋ ์ ๊ฑฐํ๋๋ก ํ๋ค.
*/
์์กด ์ญ์ ์์น์ "์์ ๋ ๋ฒจ ๋ชจ๋์ ํ์ ๋ ๋ฒจ ๋ชจ๋์ ์์กดํ๋ฉด ์๋๋ค. ๋ ๋ค ์ถ์ํ์ ์์กดํด์ผ ํ๋ค." ๋ผ๊ณ ๋งํ๋ค. ์ฆ, ๊ตฌ์ฒดํ๋ ํด๋์ค์ ์์กดํ๊ธฐ ๋ณด๋จ ์ถ์์ ์ธ ์ธํฐํ์ด์ค๋ ์ถ์ํด๋์ค์ ์์กดํด์ผ ํ๋ค๋ ๋ง์ด๋ค. ์ ์์ค์ ๋ชจ๋์ด ๋ณ๊ฒฝ๋์ด๋ ๊ณ ์์ค์ ๋ชจ๋์ ๋ณ๊ฒฝ์ด ํ์์๋ ํํ๊ฐ ๊ฐ์ฅ ์ด์์ ์ด๋ค.
DIP์ ๋ํด ์กฐ๊ธ ๋ ์์ธํ ์ดํด๋ณด๊ธฐ ์ ์ ๊ฐ๋ฐ์ ์ธ๊ณ์์ ํํ ๋ค์ ์ ์๋ Bad Design์ ๋ํด ๊ฐ๋จํ ์์๋ณด๋๋ก ํ์.
* Design Smells๋ผ๊ณ ๋ถ๋ฆฌ๊ธฐ๋ ํ๋ค.
๋ถ๋ ์ค๊ณ๋ ์ํํธ์จ์ด๋ ํ๋ก์ ํธ ์ ์ฒด๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์ค๊ณ๋์ง ์์ ๊ฒฝ์ฐ์ ๋ฐ์ํ๋ ์ํ๋ฅผ ๋ปํ๋ค. ๋๋ก๋ ์ข์ ๋ฐฉ์์ผ๋ก ์ค๊ณ๊ฐ ๋์์ง๋ง ์๊ฐ์ด ์ง๋๊ณ ์ฌ๋ฌ ์ฌ๋์ ๊ฑฐ์น๋ฉด์ ์๋ชป ์ค๊ณ๋ ์ํํธ์จ์ด๊ฐ ๋๋ ์ผ๋ ์๋ค. ๊ทธ๋ ๋ค๋ฉด ์ฌ๋ฐ๋ฅด๊ฒ ์ค๊ณ๋ ์ํํธ์จ์ด์ธ์ง ์๋์ง ๊ตฌ๋ถ์ ์ด๋ป๊ฒ ํ ๊น? ์ํํธ์จ์ด๊ฐ ์ ์์ ์ผ๋ก ์๋ํ๋๋ผ๋ ๋ค์ ํน์ฑ ์ค ์ผ๋ถ๋ฅผ ํฌํจํ๊ณ ์๋ค๋ฉด ์๋ชป ์ค๊ณ๋ ๊ฒ์ผ๋ก ๋ถ๋ฅ ๋ ์ ์๋ค.
๊ทธ๋ฐ๋ฐ ์ฝ๋ค๋ณด๋ ์ ์ด๊ฒ์ ๋ํด ์ด์ผ๊ธฐ ํ๊ณ ์๋์ง DIP์ ๋ฌด์จ ๊ด๋ จ์ด ์๋์ง ์๋ฌธ์ด ๋ค๊ฒ์ด๊ณ ๊ทธ๊ฒ ๋น์ฐํ๋ค. ๋ต์ ๊ฐ๋จํ๋ค DIP๋ ์ข์ ๋์์ธ์ ์ ๋น๋กํ๊ธฐ ๋๋ฌธ์ด๋ค. ์ฆ, ์ด ์์น์ ์ค์ํ ๋ ๊ฐ๋ฐ๋ ์ํํธ์จ์ด๋ ์ทจ์ฝํ์ง ์๊ณ , ๊ฒฝ์ง๋์ง ์์์ผ๋ฉฐ ๊ฒฐํฉ๋๊ฐ ๋ฎ์ ๊ฒฝํฅ์ด ์๋ค. DIP๋ฅผ ์ค์ํ๋ฉด ๋ถ๋์ค๊ณ๋ฅผ ํ๊ฒ๋ ํ๋ฅ ์ด ์ค์ด๋ ๋ค๋ ๋ป์ด๋ค.
์ฐ๋ฆฌ๋ ๋ฐฉ๊ธ ๋ถ๋ ์ค๊ณ์ ํน์ง๋ค์ ๋ํด์ ์๊ธฐํ๋ค. ์ด์ ๋ ๊ฐ ์์ธ๋ค์ด ๋ฌด์์ธ์ง ์์๋ณด์.
WA! ๋ค์ DIP ์ ์๋ก ๋์๊ฐ๋ณด์. ์ง๊ธ๊น์ง ๋ถ๋ ์ค๊ณ์์ ๋ฐ๋ณต์ ์ผ๋ก ๋ํ๋๋ ์ด ๋ฌธ๊ตฌ๋ DIP๋ฅผ ์ญ์ผ๋ก ์ค๋ช ํ ์ ์๋ ๋ฌธ๊ตฌ์ด๋ค.
์ถ์ํ์ ์์กดํ์ง ์๊ณ ๋ค๋ฅธ ๊ตฌ์กฐ์ ์์กดํ๋ ๊ฒฝ์ฐ.
๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ์ด ์์น์ด ์ข์ ์ค๊ณ์ ์ ๋น๋กํ๋ค๋ ๊ฒ์ด๊ณ , ์ด ์์น์ ๋ฐ๋ฅด์ง ์์ผ๋ฉด ๊ฒฝ์ง์ฑ, ์ทจ์ฝ์ฑ์ด ์ฌ๋ผ๊ฐ๊ณ ๊ฒฐํฉ๋๊ฐ ๋์ ์ํํธ์จ์ด๋ฅผ ์ค๊ณํ๊ฒ ๋๋ค. ์ด๊ฒ์ ๋งค์ฐ ์๋ชป ์ค๊ณ๋ ์ํํธ์จ์ด๋ผ๊ณ ํ ์ ์๋ค.
๋จผ์ ์งง๊ฒ ์ค๋ช ํ์๋ฉด DIP๋ OCP์ LSP์ ๊ฒฐ๊ณผ์ด๋ค. OCP์ LSP๋ฅผ ๋ฌด์ํ๋ ๊ณผ์ ์์ ๋ฐ์ํ๋ ๋ฌธ์ ๋ค์ ๋ชจ๋ ์ถ์ํ๋ก ํด๊ฒฐํ๊ธฐ ๋๋ฌธ์ด๋ค. ์์์ OCP์ LSP๋ฅผ ํด๊ฒฐํ๋ ์์๋ฅผ ๋ณด๋ฉด ๋ชจ๋ ์ถ์ํ๋ก ํด๊ฒฐํ๋ค. ํด๋์ค๋ ๋ค๋ฅธ ํด๋์ค๊ฐ ์๋ ์ถ์ํ(ํ๋กํ ์ฝ)์ ์์กดํ๊ฒ ํ๊ณ , ์ด๋ฅผ ์ํด ์ธ๋ถํ(ํด๋์ค) ๋ํ ์ถ์ํ์ ์์กดํ๊ฒ ํ๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก OCP์ LSP๋ฅผ ๋ฐ๋ฅด๊ธฐ ์ํด DIP๋ฅผ ๋ฐ๋ผ์ผ ํ๋ค.
class Order {
let menu = Menu(price: 5000)
}
class Menu {
var price: Int
init(price: Int) {
self.price = price
}
}
let order = Order()
print(order.menu.price) // 5000
/**
์ด๋ ๊ฒ ํด๋์ค ๋ด๋ถ์์ ์ธ์คํด์ค๋ฅผ ์์ฑํ๋ฉด ํด๋น ํด๋์ค์ ์์กดํ๊ฒ ๋๋ ๊ฒฐ๊ณผ๊ฐ ์๊ธด๋ค.
*/
/// ์์กด์ฑ ์ฃผ์
, Dependency Injection
class Order {
let menu: Menu
init(menu: Menu) {
self.menu = menu
}
}
class Menu {
var price: Int
init(price: Int) {
self.price = price
}
}
let menu = Menu(price: 7000)
let order = Order(menu: menu)
print(order.menu.price) // 7000
/**
์ด๋ ๊ฒ ์ธ๋ถ์์ ์ธ์คํด์ค๋ฅผ ์์ฑ ํ ๋ฃ์ด์ฃผ๋๊ฒ์ ์์กด์ฑ ์ฃผ์
์ด๋ผ๊ณ ํ๋ค.
ํ์ง๋ง, ์์ง ์ถ์ํ์ ์์กดํ์ง ์์๊ธฐ ๋๋ฌธ์ ๊ฒฐํฉ๋๊ฐ ๋์ ์ ์ง๋ณด์๋ฅผ ํ๋๋ฐ ๋ถ๋ฆฌํ๋ค.
*/
/// ์์กด์ฑ ์ญ์ ์์น, Dependency Iversion Principle
protocol Menu {
var price: Int
}
class Order {
let menu: Menu
init(menu: Menu) {
self.menu = menu
}
}
class Toast: Menu {
var price: Int
init(price: Int) {
self.price = price
}
}
let toast = Toast(price: 3000)
let order = Order(menu: toast)
print(order.menu.price) // 3000
/**
๋ ํด๋์ค ๋ชจ๋ ์ถ์ํ๋ ํ๋กํ ์ฝ์ ์์กดํ๊ฒ ๋๋ฉด์ ์๋ก๊ฐ์ ์์กด์ฑ์ ๋
๋ฆฝ์ ์ด๊ฒ ๋๋ค.
์ด๋ ๊ฒ ๋๋ฉด ๊ฒฐํฉ๋๊ฐ ๋ฎ์์ ธ Toast์ ์ฝ๋๋ฅผ ๋ณ๊ฒฝํด๋ Order์๋ ์ํฅ์ด ์์ด ์ ์ง๋ณด์์ ์ ๋ฆฌํ๋ค.
*/
์ค๋ ๋ฐฐ์ด ๋ด์ฉ๋ค์ ์ ๋ฆฌํด๋ณด์.
SRP์ ISP๋ ๊ฐ์ฒด๊ฐ ์ปค์ง๋๊ฒ์ ๋ฐฉ์งํด์ค๋ค. SRP๋ ๋จ์ผ ์ฑ ์์ ๋ถ์ฌํด ๊ฐ์ฒด๊ฐ ๋๋๋๋ก ํ๊ณ ISP๋ ํด๋ผ์ด์ธํธ๋ง๋ค ํนํ๋ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๊ฒ ํจ์ผ๋ก์จ ํ ๊ธฐ๋ฅ์ ๋ณ๊ฒฝ์ด ๋ค๋ฅธ๊ณณ์ ๋ฏธ์น๋ ์ํฅ์ ์ต์ํ ํ๊ณ , ์ด๋ ๊ธฐ๋ฅ ์ถ๊ฐ ๋ฐ ๋ณ๊ฒฝ์ ์ฉ์ดํ๋๋ก ํ๋ค.
LSP์ DIP๋ OCP๋ฅผ ์ํฌํธํ๋ค. OCP ๋ ์์ฃผ ๋ณํ๋๋ ๋ถ๋ถ์ ์ถ์ํํ๊ณ ๋คํ์ฑ์ ์ด์ฉํจ์ผ๋ก์จ ๊ธฐ๋ฅ ํ์ฅ์๋ ์ฉ์ดํ๋ ๊ธฐ์กด ์ฝ๋์ ๋ณํ์๋ ๋ณด์์ ์ด๋๋ก ๋ง๋ค์ด ์ค๋ค. ์ฌ๊ธฐ์ ๋ณํ๋๋ ๋ถ๋ถ์ ์ถ์ํํ ์ ์๋๋ก ๋์์ฃผ๋ ์์น์ด DIP ์ด๊ณ , ๋คํ์ฑ ๊ตฌํ์ ๋์์ฃผ๋ ์์น์ด LSP ์ธ ๊ฒ์ด๋ค.
Clean Architecture์ ์ด์ด์ SOLID 5์์น์ ๋ํด์๋ ๊ณต๋ถ๋ฅผ ํ๊ฒ ๋์๋๋ฐ, ์ฒ์์๋ Clean Architecture๋ง์ผ๋ก๋ ๋จธ๋ฆฟ์์ ์ ๋ฆฌํ๋ ค๋ ์์ด ๊น๊นํ์๋ค. ํ์ง๋ง Clean Architecture๋ฅผ ๋ฐฐ์ฐ๋ ๋ ๊น๊ฒ ๊ณต๋ถํ๊ณ ์ถ์ด์ก๊ณ ๊ทธ๋์ SOLID 5์์น ๊น์ง ๊ณต๋ถํ๊ฒ ๋๋ค.
์ด๊ฒ๋ค์ ๋จธ๋ฆฟ์์ ์ ๋ฆฌํ๊ณ ๋ด ํ๋ก์ ํธ์ ์ง์ ์ ์ฉํ๊ฒ ๋๋ฉด ์์ฐ์ค๋ ์ข์ ํ์ง์ ์ฝ๋๋ฅผ ์์ฑํ ์ ์์๊ฑฐ๋ผ ์๊ฐ์ด ๋ ๋ค. ๋, ์ข์ ํ์ง์ ์ฝ๋๋ฅผ ๊พธ์คํ ์์ฑํ๋๊ฒ์ ์ข์ ๊ฐ๋ฐ์๋ก ๊ฑฐ๋ญ๋๊ธฐ ์ํ ๊ณผ์ ์ด๋ผ๊ณ ์๊ฐํ๊ธฐ ๋๋ฌธ์ ๋ ๋ง์ ํ์ต์ ํตํด ์ข์ ํ์ง์ ์ฝ๋๋ฅผ ์ ์งํ ์ ์๋๋ก ํด์ผ๊ฒ ๋ค.