도서/기술

[책] 데이터 지향 프로그래밍 - 3장 기본 데이터 조작

egg528 2024. 11. 30. 14:26
DOP 원리 2
데이터 개체를 범용 자료구조로 표현하라



범용 자료 구조로 데이터 표현하기


 DOP에서 데이터를 표현하는 방식에 대한 주장이 있다. 우선 데이터 개채들은 레코드로 표현되며 레코드 간의 관계는 순차 컬렉션과 색인으로 표현된다. 이때 중요한 건 레코드는 범용 자료구조로 표현되어야 한다는 점이다. 색인과 컬렉션이 어떤 방식으로 구현되어야 주장은 없다. (책에서는 컬렉션은 배열, 색인은 동종 맵을 활용해 구현한다.) 단, 레코드의 경우 동종 맵으로 표현되어야 한다고 말한다.

 

 대개 레코드를 표현하는 방식은 클래스의 인스턴스이고 각 필드는 클래스의 멤버 변수가 된다. 하지만 DOP에서 모든 레코드는 맵으로 표현되고 각 필드는 key - value 형태로 표현된다. 이 방식의 장점은 클래스를 만들 필요가 없고 동적으로 필드를 추가/수정/삭제할 수 있는 유연성이다. 반면 자유도를 얻은 만큼 안정성은 떨어지게 된다. (IDE의 자동 완성 기능 또한 잃는다..)

 

 레코드를 맵으로 표현하면 얻을 수 있는 장점이 또 있는데 직렬화가 편해진다. 모든 클래스를 Json 형태로 직렬화하는 모듈을 만드는 작업과 Map을 Json형태로 직렬화하는 모듈을 만드는 작업. 둘 중 당연히 후자가 편하지 않을까? (하지만 전자의 작업도 이미 구현된 모듈을 사용하면 되기 때문에 이 점이 엄청난 장점으로 느껴지지는 않았다.)

 

 

범용 함수를 사용한 데이터 조작


class Catalog {
  static authorNames(catalogData, book) {
    const authorIds = _.get(book, 'authorIds');
    const names = _.map(authorIds, (authorId) => {
      return _.get(catalogData, ['authorsById', authorId, 'name']);
    });
    
    return names;
  }
}

 

 레코드를 맵으로 표현하면 범용 함수로 데이터를 조작하는 작업이 편해진다. 책에서는 lodash를 사용하는데 범용 자료 구조인 맵을 사용했기 때문에 범용 함수(lodash)를 사용해 로직을 구현할 수 있게 됐다. 비슷한 메서드들을 만들다보면 몇 가지 장점들이 보인다.

  • 결과를 표현할 클래스를 만들 필요가 없다.
  • 로직이 구체적인 데이터 처리만 존재하고 추상적인 작업이 존재하지 않는다.
  • lodash를 활용하기 때문에 정보 경로가 일급 시민이다.
    • 변수에 저장하고 인자로 함수에 전달이 가능하다.

 

 

이종 자료형의 레코드 처리


var userManagementData = {
  "librariansByEmail": {
    "franck@gmail.com": {
      "email": "franck@gmail.com",
      "encryptedPassword": "bX]wYXNzd29yZA==" 
    }
  },
  "membersByEmail": {
    "samantha@gmail.com": {
      "email": "samantha@gmail.com",
      "encryptedPassword": "c2VjcmV0",
      "isBlocked": false,
      "bookLendings": [
        {
          "bookItemId": "book-item-1",
          "bookIsbn": "978-179501127",
          "lendingDate": "2020-04-23"
        }
      ]
    }
  }
};

 

 이전 작업에서 Librarian, Member, User 등의 관계가 복잡해지며 구조 또한 복잡해지는 과정을 경험했다. DOP에서는 기본적으로 레코드가 어떤 타입인지가 중요하지 않다. userManagementData의 2개의 색인 중 어떤 색인을 선택하느냐에 따라 데이터가 달라지기 때문이다.

 

 이처럼 레코드의 차이를 확인하는데 색인을 활용할 수도 있지만 필드를 추가할 수도 있다. 이전 요구 사항 중 Member의 경우 VIP인지 Super인지를 구분해야 하는 부분이 있었다. 이때 isVip, isSuper 필드를 추가해 boolean값을 가지게 한다면 Member의 속성을 더 쉽게 구분할 수 있다. 책을 읽으며 Type을 두면 되는 거 아닌가? 생각했지만 책에선 VIP이면서 Super인 경우를 가정했고 레코드가 지원하는 각 기능에 boolean 필드를 두는 것이 더 간단하다고 말한다. 또한 이런 필드를 특성 필드라고 부른다.

 

 

내 생각


 대다수의 선택에는 장 / 단이 있다. 레코드를 맵으로 표현하는 것 또한 장 / 단이 명확해 보인다. 특히 단점으로 보이는 부분은 정보 경로가 길어질 경우 어떻게 관리할 것인가? 하는 점이다. 그 이유는 레코드의 정확한 형태가 코드에 표현되지 않기 때문이다. 7장, 12장에서 이 부분을 보완할 방법을 알려준다니 좀 더 기다려 봐야겠다.