IOS에서 POP, OOP 어떤것을 써야 하는가! 그것이 문제로다

요즘 모집공고의 우대 사항을 보면 UnitTest, 클린 아키텍쳐, TDD 이런게 꼭 한두가지씩은 들어가 있습니다. UnitTest와 TDD는 자바 스프링을 공부해 보신분이나 테스트 코드를 작성해 보신분을 알고 계시겠지만 TDD는 Test Driven Development로 테스트 주도 개발을 뜻합니다. IOS에서는 UnitTest를 통해 계속해서 테스트를 하면서 개발을 해나가는 것이지요. 말은 쉽지만 UnitTest를 하기 위해서는 각 기능을 분리시켜서 하나의 역할을 하게 코드를 구성해야 합니다. 하지만 마구잡이식으로 분리를 하다보면, 코드가 어지러워지고 가독성이 떨어질 수도 있고, 똑같은 기능을 하는 코드를 계속 다시 작성하는 경우도 있으며, 기능 하나 추가하는데 다른 기능의 소스코드를 수정해야 하거나, 각 클래스간의 의존성에 의해 오류가 이곳저곳에서 터지기 마련입니다. 이런 참사를 막기 위해 OOP, POP, FOP등등 여러가지 프로그래밍 패러다임이 존재 합니다. 그중에서도 가장 널리 쓰이는 OOP와 애플이 공식적으로 swift는 POP언어라고 말했으니 POP, 이 두가지에 대해 알아보도록 하겠습니다.

 

Swift가 POP(프로토콜 지향)인 이유

Swift는 protocol을 이용해 추상화를 합니다. 이는 자바의 interface와 비슷한 역할을 하죠. 하지만 Swift는 protocol을 extension으로 메소드또는 계산 프로퍼티를 구현해 해당 protocol을 채택을 하면 기본 구현을 제공 할 수 있습니다. extension으로 기본 구현을 제공을 하면, 해당 protocol을 채택한 class나 struct는 매번 같은 메소드나 프로퍼티 등등을 다시 구현 할 필요가 없습니다. 그렇다면 swift 에서는 어떤식으로 pop를 이용했는지 한번 살펴보겠습니다.

가장 많이 쓰이는 고차함수인 map의 소스코드와 map과 연관이 있을것 같은 flatMap의 소스코드를 살펴 보겠습니다.

Map.swift의 소스코드중 일부입니다. 

extension LazyMapSequence: LazySequenceProtocol {
  /// Returns an iterator over the elements of this sequence.
  ///
  /// - Complexity: O(1).
  @inlinable
  public __consuming func makeIterator() -> Iterator {
    return Iterator(_base: _base.makeIterator(), _transform: _transform)
  }

  /// A value less than or equal to the number of elements in the sequence,
  /// calculated nondestructively.
  ///
  /// The default implementation returns 0. If you provide your own
  /// implementation, make sure to compute the value nondestructively.
  ///
  /// - Complexity: O(1), except if the sequence also conforms to `Collection`.
  ///   In this case, see the documentation of `Collection.underestimatedCount`.
  @inlinable
  public var underestimatedCount: Int {
    return _base.underestimatedCount
  }
}
extension LazySequenceProtocol {
  /// Returns a `LazyMapSequence` over this `Sequence`.  The elements of
  /// the result are computed lazily, each time they are read, by
  /// calling `transform` function on a base element.
  @inlinable
  public func map<U>(
    _ transform: @escaping (Element) -> U
  ) -> LazyMapSequence<Elements, U> {
    return LazyMapSequence(_base: elements, transform: transform)
  }
}

LazySequenceProtocol을 확장하여 map을 구현을 하고 있는것을 볼 수 있습니다. 

이번에는 FlatMap.swift 소스코드를 한번 보겠습니다. 

extension LazySequenceProtocol {
  /// Returns the concatenated results of mapping the given transformation over
  /// this sequence.
  ///
  /// Use this method to receive a single-level sequence when your
  /// transformation produces a sequence or collection for each element.
  /// Calling `flatMap(_:)` on a sequence `s` is equivalent to calling
  /// `s.map(transform).joined()`.
  ///
  /// - Complexity: O(1)
  @inlinable // lazy-performance
  public func flatMap<SegmentOfResult>(
    _ transform: @escaping (Elements.Element) -> SegmentOfResult
  ) -> LazySequence<
    FlattenSequence<LazyMapSequence<Elements, SegmentOfResult>>> {
    return self.map(transform).joined()
  }

  /// Returns the non-`nil` results of mapping the given transformation over
  /// this sequence.
  ///
  /// Use this method to receive a sequence of non-optional values when your
  /// transformation produces an optional value.
  ///
  /// - Parameter transform: A closure that accepts an element of this sequence
  ///   as its argument and returns an optional value.
  ///
  /// - Complexity: O(1)
  @inlinable // lazy-performance
  public func compactMap<ElementOfResult>(
    _ transform: @escaping (Elements.Element) -> ElementOfResult?
  ) -> LazyMapSequence<
    LazyFilterSequence<
      LazyMapSequence<Elements, ElementOfResult?>>,
    ElementOfResult
  > {
    return self.map(transform).filter { $0 != nil }.map { $0! }
  }
}

FlatMap 역시 LazySequenceProtocol을 확장하여 구현한것을 보실수 있습니다. 이런식으로 공통적인 기능을 하나의 프로토콜에서 추상화 하고, extension을 통해 확장 및 기초구현을 하는것을 POP라고 합니다. 그리고 swift는 이런식으로 공통된 기능을 protocol로 묶어서 구현하고 extension으로 확장을 했기에 POP언어라고 한것 같네요.

 

OOP(객체지향)란?

자바를 하신 분이라면 누구나 한번쯤을 들어봤을만한 단어입니다. OOP의 핵심은 상속, 다형성, 추상화, 캡슐화를 통해 유지보수와 코드의 재사용성을 높인 프로그래밍 패러다임입니다. OOP에 대한 글은 워낙 깔끔하게 정리해주신 분들도 많으시고 자료도 많기에 이정도 까지만 해두겠습니다.

 

OOP 와 POP의 차이점

OOP와 POP의 차이점은 무엇이 있을까요? OOP에서는 클래스로 추상화를 진행하고 POP에서는 protocol로 추상화를 합니다. 또 OOP는 프로그램을 여러객체로 나누지만, POP는 프로그램을 기능으로 나눕니다. 즉 OOP는 객체를 강조하지만, POP는 기능을 강조합니다. 또 OOP는 상속을 통해 코드의 재사용성을 높이지만 POP는 protocol의 extension을 통해 재사용성을 높입니다. 즉 객체를 상속받지 않고 수평적으로 동일한 기능을 제공을 할 수 있습니다.

//OOP
class Animal {
    var name: String
    func bark(){
        print("짖습니다.")
    }
    
    init(name: String) {
        self.name = name
    }
}

class Cat: Animal {
    init() {
        super.init(name: "cat")
    }
}
//POP
protocol Barkable {
    func bark()
}

extension Barkable {
    func bark() {
        print("짖습니다.")
    }
}

class Cat: Barkable {
    var name: String
    init(name: String) {
        self.name = name
    }
}

 

언제 OOP를 사용하고, 언제 POP를 사용해야 할까?

이것에 대해서는 많은 사람들이 제각기 다른 생각을 가지고 있습니다.

https://forums.swift.org/t/comparing-pop-to-oop/1438/8

 

Comparing POP to OOP

Numerous tutorials that I have seen take a very Object-Oriented approach to the protocol-oriented programming (POP) paradigm. By this statement I mean that they tell us that with POP we should begin our design with the protocol rather than with the supercl

forums.swift.org

 

따로 정답은 없는것 같습니다. OOP는 OOP만의 장점이 있고 단점도 있고, POP역시 장점과 단점이 있습니다.

POP는 object-c로 작성된 프로토콜은 swift의 extension으로 기본 구현을 할 수가 없습니다. 즉 자주 사용되는 Delegate, DataSource등 플레임워크 프로토콜에서는 기본 구현이 불가능합니다. 

어느것이 더 우수하다고 비교하기보다는 두 패러다임의 장점을 모두 사용하는쪽으로 가는것이 좋지 않을까 싶네요. OOP와 POP는 상호배타적이지 않고, 서로의 단점을 보완할 수 있습니다. protocol의 extension을 이용하고, 또 상속을 통해 코드의 재사용성을 높이는 등 꼭 OOP는 extension을 쓰면 안되고 POP는 객체의 상속을 쓰면 안된다는 그런 것 없이 최대한 각 패러다임의 장점(상속과 프로토콜의 extension)을 사용하는게 더 좋을것 같습니다. 물론 SOLID 원칙은 준수해야겠지만요. 

 

 

 

참고 : https://www.appcoda.com/pop-vs-oop/, https://blog.yagom.net/531/,  https://github.com/apple/swift, https://pediaa.com/difference-between-oop-and-pop/

 

Difference Between OOP and POP - Pediaa.Com

The main difference between OOP and POP is that the OOP divides the program into multiple objects to solve the problem while the POP divides the program into multiple procedures or functions to solve the problem.

pediaa.com

 

GitHub - apple/swift: The Swift Programming Language

The Swift Programming Language. Contribute to apple/swift development by creating an account on GitHub.

github.com

 

POP vs OOP in Swift: Which one is better for iOS Programming?

We're going to talk in-depth about protocol-oriented programming (POP) using Swift and answer a question: Is POP is better than Object oriented programming?

www.appcoda.com

 

Swift - 프로토콜 지향 프로그래밍 - yagom's blog

yagom's blog Swift - 프로토콜 지향 프로그래밍

blog.yagom.net