OOP와 DOP 어떤 방식이 맞을까?

작은선생·2023년 11월 28일
post-thumbnail

객체지향 프로그래밍은 우리가 개발하면서 지겹도록 듣는 단어이다.

클래스를 통해 데이터와 어떠한 기능 & 행위를 묶어 관리하는 프로그래밍 패러다임이다.

객체지향 프로그래밍은 널리 사용되는 패러다임으로써, 클래스를 통해 데이터와 기능 & 행위를 구조화하는 것을 뜻한다.

비교적 최근 데이터 지향 프로그래밍 (Data Oriented Programming)이란 새로운 개념이 등장하게 되었고, 과연 객체지향 프로그래밍과 DOP는 어떤 차이가 있는지 그리고 어떤 연관을 지을 수 있을지 살펴보는 것이 글의 목적이다.

객체지향 프로그래밍 (OOP)

OOP은 다들 알다시피 캡슐화, 상속, 추상화, 다형성 등의 특징을 가진다.

클래스 단위로 기능을 구성하고, 해당 객체를 통해 프로그램을 구성하는 것이 객체지향의 본질이라고 할 수 있다.

  • 객체, 캡슐화, 추상화 개념 강조
  • 데이터 - 데이터에서 작동하는 메서드는 클래스 내에 캡슐화
  • 실제 객체를 동작이 있는 객체로 모델링하는데 중점

데이터 지향 프로그래밍 (DOP)

중요한 점은 성능 최적화에 집중한다는 것이다. 캐시 효율성을 높여 연산 속도를 빠르게하고, 병렬처리를 통해 다중 스레드 프로세스의 성능을 극대화할 수 있다.

  • 데이터 구조화 → 데이터를 물리적으로 가까운 위치에 저장하여 메모리 접근 속도를 높이고 캐시 효율성 개선
  • 데이터 변환 → 프로그램을 데이터 변환 단계로 분해해 각 단계에서 데이터를 처리하는데 필요한 최소한의 정보만 사용
  • 메모리 접근 최적화 → 데이터를 연속적인 메모리 블록에 저장하여 캐시 지역성을 개선, 메모리 접근을 최소화해 메모리에 효율적으로 접근
  • 병렬성 고려 → 데이터를 독립적으로 처리할 수 있는 작은 단위로 분할하여 병렬 처리를 용이하게하고, 다중 코어 및 다중 스레드 프로세서의 성능을 최대한 활용.

데이터 지향 설계가 가지는 의미.

위에 설명한 특징을 토대로 결론을 내리자면 결국 성능차이다. 예제를 살펴보자.

임의의 서점을 운영하고, 판매된 책이 100만권이라고 가정하고 가장 많이 매출이 남은 책의 가격은 얼마인지 계산해보는 시나리오다. (원할한 비교를 위해 책의 가격과 수량은 임의로 배정)

/**
 * OOP 예제
 */
class Item {
    public String Book;
    public int price;
    public int number;

    public Item(String book, int price, int number) {
        Book = book;
        this.price = price;
        this.number = number;
    }

    public int SellingBooks() {
        return this.price * this.number;
    }

}
  • 객체지향프로그래밍의 예제이다. Item이란 클래스는 책 정보를 명시할 클래스다. 데이터들은 모두 Item 클래스에 캡슐화되어있다. 또한, 판매가격을 계산하는 메소드도 제공된다. 객체의 속성과 행동이 명확하게 명시되어있어 가독성이 좋다.
/**
 * DOP 예제
 */
class DataItem {
    private static final int IDX = 1000000;
    private int currentIndex = 0;

    public String[] book = new String[IDX];
    public int[] price = new int[IDX];
    public int[] number = new int[IDX];

    public void add (String book, int price, int number) {
        this.book[currentIndex] = book;
        this.price[currentIndex] = price;
        this.number[currentIndex] = number;

        currentIndex++;
    }

    public int getMaxSellingBooks() {

        int maxPrice = 0;

        for (int i = 0; i < this.currentIndex; i++) {
            if (maxPrice <= this.price[i] * this.number[i]) {
                maxPrice = this.price[i] * this.number[i];
            }
        }

        return maxPrice;
    }
}
  • 데이터중심지향 설계의 예제이다.
    • 배열사용
      • 인접 메모리 사용으로 오버헤드 방지 데이터 오버헤드를 방지하고 효율성을 높일 수 있게 배열형태로 지정하여 메모리 효율을 높였다. 객체는 연관된 추가 메타데이터와 포인터가 있는 반면, 배열은 간단한 데이터 구조이기 때문이다. 배열 요소는 인접한 메모리 위치에 저장되어 캐시 지역성을 향상하고 메모리 조각화가 줄어들 수 있다.
      • 직접 인덱싱 배열 요소에 직접 인덱싱함으로써 빠른 엑세스가 가능하다.
    • 효율적인 데이터조작
      • 배열의 최대값 지정과 인덱스 설정 최대값과 인덱스를 지정해줌으로써, add() 메소드 호출시 효과적으로 인덱스를 찾아 데이터를 가공할 수 있다.
      • 일괄처리 배열 기반으로 각 인덱스에 위치한 데이터를 중심으로 일괄작업이 가능하다.

결국은 DOP가 빠르다.

실제로 어느정도 차이가 있을까.

OOP time : 10067958
DOP time : 4782375

위 예제에서 DOP 방식이 약 2배정도 빠르다는 것을 확인할 수 있다.

그럼 왜 아직도 우린 OOP 중심 개발을 할까?

일단, 웹&앱 개발에서 나노초 단위까지 성능문제를 다룰 일이 극히 적은 것이 원인으로 생각된다.

큰 차이를 체감할 수 없기 때문에 객체지향이 가지는 가독성과 유지보수의 편리함을 더 중요하게 생각하는 것이 더 효율적인 것이다.

참고자료

https://yozm.wishket.com/magazine/detail/2157/

0개의 댓글