JavaScript와 TypeScript를 위한 빠르고 쉬운 객체 매핑
새로운 라이브러리를 소개합니다. 사실 여러 명이 함께 만든 프로젝트이고, 그중 제가 Node.js 버전을 담당했습니다. 여러분의 관심을 받을 만한 멋진 결과물이라고 자부하며, 소개하게 되어 무척 기쁩니다. 바로 Node.js용 Redis OM입니다.
Redis OM이란 무엇일까요? Redis OM은 Redis 데이터 구조를 코드에 직접 매핑하여 Redis를 손쉽게 사용할 수 있게 해주는 라이브러리입니다. 이름의 'OM'은 객체 매핑(object mapping)을 의미하지만, 앞으로 더 다양한 기능을 추가할 계획입니다.
자세한 내용을 하나씩 살펴보겠습니다.
빠르기보다 더 빠른 성능
Redis가 얼마나 빠른지는 이미 잘 알고 계실 겁니다. Redis는 해시(hash), 리스트(list), 셋(set)처럼 프로그램이 다루는 데이터 구조를 저장합니다. 프로그래머 입장에서 이런 구조들은 익숙하고 자연스럽습니다. Redis를 처음 접하는 개발자에게 설명할 때 저는 이렇게 말합니다. "Redis는 대학에서 배운 그 데이터 구조들 앞에 와이어 프로토콜을 얹어 놓은 것"이라고요.
모듈은 Redis를 한층 더 강력하게 만듭니다. 프로그램이 활용할 수 있는 새로운 데이터 구조를 도입하기 때문입니다. RedisBloom은 블룸 필터와 커쿠 필터 같은 확률적 데이터 구조를 추가하고, RedisGraph는 Cypher를 이용해 그래프를 저장하고 조회할 수 있게 하며, RedisAI는 놀라운 AI 작업을 위한 텐서를 제공합니다. 모두 실무에 유용한 기능들입니다.
가장 강력한 모듈 조합
그중에서도 특히 두 가지 모듈이 Redis를 모든 프로그래머가 원하는 강력한 인메모리 데이터베이스로 만들어 줍니다. 바로 RedisJSON과 RediSearch입니다.
RedisJSON은 계층 구조를 지원합니다. 해시도 훌륭하지만, 해시 안에 또 다른 해시를 중첩하고 싶다면 어떨까요? RedisJSON은 JSON 문서 형태로 계층적 데이터를 저장할 수 있게 해줍니다.
한편 RediSearch는 원하는 데이터 구조를 찾아내는 기능을 제공합니다. 물론 셋(set)으로 수동 인덱스를 만들 수도 있지만, 그 방식은 한계가 많고 번거롭습니다. RediSearch를 사용하면 쿼리를 작성해 원하는 데이터에 곧바로 접근할 수 있습니다.
RediSearch와 RedisJSON을 결합하면 Redis는 상당히 매력적인 문서 데이터베이스가 됩니다. 원하는 계층 구조와 그 안에서 필요한 데이터를 찾는 능력을 동시에 얻을 수 있는 것이죠. 일석이조인 셈입니다.
실제로 이 조합이 너무 훌륭하다고 판단한 나머지, 두 모듈을 통합하고 RedisJSON이라는 이름 하나로 부르기로 했습니다.
Node.js용 Redis OM
RediSearch의 쿼리 언어는 무척 강력합니다. Redis 안의 해시와 JSON 문서를 다양하고 정교한 방식으로 검색할 수 있습니다. 그런 강력한 기능이 필요할 때는 정말 좋습니다. 하지만 때로는 그 정도의 기능이 필요 없을 때도 있습니다. 그리고 저는 게으른 개발자라서, 최대한 쉽게(그 이상은 아니더라도) 작업하고 싶습니다.
Node.js용 Redis OM을 작성하면서 목표로 한 것이 바로 '최대한의 편의성'이었습니다. Redis OM은 해시와 JSON 문서를 직접 정의한 클래스에 매핑함으로써 Node.js 애플리케이션에 Redis를 간단히 추가할 수 있게 해줍니다. 복잡한 명령어는 필요 없고, 유연한 인터페이스(fluent interface)를 갖춘 순수한 코드만 있으면 됩니다. 예시를 살펴보겠습니다.
먼저 엔티티를 정의합니다:
새 엔티티를 생성하고 저장합니다:
조건에 일치하는 엔티티를 검색합니다:
직접 이 라이브러리를 만든 사람으로서 상당히 편향된 시선일 수 있지만, 정말 꽤 멋지지 않나요? 이제 이 문법을 좀 더 자세히 살펴보며 동작 방식을 알아보겠습니다.
동작 방식
Node.js용 Redis OM에서 알아야 할 핵심 클래스는 네 가지입니다. Entity, Schema, Client, Repository입니다.
Entity(엔티티)는 실제로 다루게 될 클래스입니다. 생성, 조회, 수정, 삭제(CRUD)의 대상이자 검색의 대상이죠. Entity를 상속하는 모든 클래스가 엔티티입니다. 보통 한 줄의 코드로 정의하지만, 필요하다면 커스텀 로직을 추가할 수도 있습니다:
Schema(스키마)는 엔티티의 필드, 타입, 그리고 Redis 내부 매핑 방식을 정의합니다. 기본적으로 엔티티는 Redis의 해시에 매핑되지만, JSON 문서에 매핑할 수도 있습니다:
Schema를 생성하면 전달받은 Entity가 수정되어, 정의한 프로퍼티에 대한 getter와 setter가 자동으로 추가됩니다. 이 getter와 setter가 받아들이고 반환하는 타입은 type 속성으로 결정됩니다.
Client(클라이언트)는 Redis에 연결해 주는 역할을 합니다. Client에는 Redis 연결을 열고(open), 닫고(close), 원시 명령을 실행하는 메서드가 있습니다. 주로 open과 close를 사용하게 됩니다:
Repository를 인스턴스화하려면 Schema와 Client가 필요합니다. Repository(레포지토리)는 엔티티를 읽고, 쓰고, 삭제하는 수단을 제공하며, 검색 기능도 함께 제공합니다:
Repository가 준비되면 이를 통해 엔티티를 생성, 조회, 수정, 삭제할 수 있습니다. 아래는 제가 좋아하는 Mushroomhead의 앨범으로 CRUD 작업을 수행하는 예입니다:
물론 엔티티 검색에도 활용할 수 있습니다:
복사해서 붙여넣기 편하도록 위 예제를 하나의 코드 블록으로 정리했습니다:
이것이 Node.js용 Redis OM의 전체 모습입니다. 흔히 말하는 '핵심 요약'이죠.
마무리
지금까지 Node.js용 Redis OM으로 무엇을 할 수 있는지 간략히 살펴봤습니다. 더 알고 싶다면 Redis OM으로 간단한 서비스를 만드는 과정을 단계별로 안내하는 튜토리얼이 준비되어 있습니다. 더 깊이 들어가고 싶다면, 당연히 들어가야겠죠, GitHub의 README와 API 문서를 확인해 보세요.
물론 이것은 아직 실전에서 검증되지 않은 새로운 소프트웨어입니다. 바로 여러분이 그 '실전'입니다. 꼭 사용해 보세요. 시험 삼아 돌려보고, 일부러 망가뜨려 보세요. 무엇이 있는지, 무엇이 더 있으면 좋을지 살펴보세요. 버그를 발견하거나 좋은 기능 아이디어가 떠오르면 이슈를 등록하거나 풀 리퀘스트를 보내 알려주세요. Redis OM을 더 좋게 만드는 데 도움을 주신다면 진심으로 감사하겠습니다. 감사합니다!