데이터 중심 애플리케이션이 뭘까?

2024년 10월 24일

데이터 시스템은 무엇일까?

데이터 시스템은 무엇일까? 단순하게 생각해보면 데이터를 다루는 도구들을 데이터 시스템으로 생각을 할 수 있을 것이다. 예를 들어 데이터베이스, 메세지 큐, 캐시 등의 도구들을 대표적으로 생각해볼 수 있을 것이다. 그렇다면 앞서 설명한 도구들이 각각 하나의 데이터 시스템으로 구분이 되는 것일까?
우선 이에 대한 대답은 아니라고 할 수 있다. 이러한 이유는 오늘 날의 현대 앱들은 앞서 설명한 단일 도구들을 사용하는 것으로는 문제를 해결할 수 있지 않기 때문이다. 이러한 말의 의미를 알기 위해서는 시스템을 구분하는 기준에 대해서 이야기할 필요가 있다.
하나의 시스템을 구분하는 기준은 주로 시스템이 어떤 범위 내에서 작동을 하는 지 어떤 구성요소를 사용하는지를 기준으로 구분이 된다. 하지만 오늘 날의 데이터 시스템은 각각의 구성요소의 경계가 모호한 점이 있다.
예를 들어 메세지 큐로 사용하는 데이터 스토어(datastore)인 레디스(Redis)를 생각해볼 수 있다. 레디스의 초기 목적은 인메모리 키 값 저장소로서 사용이 되며 주로 캐싱 시스템으로써 사용이 되었다. 하지만 레디스는 오늘 날 다양한 데이터 구조를 지원하고 실시간 분석, 세션 관리 등 기존의 기능들과 경계를 넘어서 더욱 다양한 활용이 가능해졌다.
이는 레디스 뿐만이 아니라 메시지 큐인 아파치 카프카(Apache Kafka) 등 여러 유명한 도구들에서 일어나고 있는 일이다. 그렇기 때문에 데이터 시스템을 데이터베이스, 큐, 캐시 등의 도구들을 묶는 포괄적인 용어라고 정의할 수는 없다.
그렇다면 데이터 시스템은 뭐라고 정의해야 할까? 데이터 시스템은 단일 도구로 정의되지 않고 다양한 도구들을 조화롭게 사용하여 데이터를 수집, 저장, 처리, 전달, 분석하는 것을 목적으로 하며 이를 통해 신뢰할 수 있고 확장이 가능하며 유지보수가 가능한 구조로 이루어진 시스템을 데이터 시스템이라고 정의할 수 있을 것이다.

신뢰성

하드웨어나 소프트웨어의 결함 심지어 인적 오류 같은 역경에 직면하더라도 시스템은 지속적으로 올바르게 동작해야 한다.

확장성

시스템의 데이터 양, 트래픽 양, 복잡도가 증가하면서 이를 처리할 수 있는 적절한 방법이 있어야 한다.

유지보수성

시간이 지남에 따라 여러 다양한 사람들이 시스템 상에서 작업할 것이기 때문에 모든 사용자가 시스템 상에서 생산적으로 작업할 수 있게 해야 한다.

데이터 모델과 질의 언어

소프트웨어를 구축한다는 의미에서 데이터베이스의 설계하는 것은 더 없이 중요하다고 할 수 있다. 데이터베이스의 설계는 문제를 어떻게 해결할 것인가? 에 대한 의문에 대한 대답으로 이어질 수 있는 중요한 문제이기 때문이다.
예를 들어 생각을 해보자. todo 앱을 설계하려고 하는데 이 때 todo 앱에는 각각의 오늘 할 일에 한 주제가 나뉘어져 있다. 예를 들어 오늘 할 일, 해야 하는 일, 완료한 일 을 구분하여 데이터를 추가하고 이에 대한 기록과 사용자에 따른 기록을 구분하여 추적하려고 한다고 가정할 경우 해당 문제를 어떻게 해결해야 할까요?
이러한 문제를 해결하기 위해 먼저 구상해야 하는 것은 데이터베이스를 구상하는 것이 가장 우선되는 것이 편하다. 왜냐하면 todo 앱의 가장 중심으로 다루어지는 것은 어떤 일을 해야 하는지, 할 것인지, 완료 했는 지를 구분하는 데이터가 중심이 되기 때문이다.
그렇기 때문에 데이터베이스에 대해서 제대로 파악하고 활용하고 사용할 줄 아는 것이 무엇보다 중요하다고 할 수 있다. 하지만 데이터베이스를 제대로 활용하고 설계하는 것은 결코 쉬운일이 아니고 한 번에 이루어 낼 수 있는 것이 아니기 때문에 어떤 특징을 갖고 어떤 것을 고려하여야 하는 지에 대한 지식을 바탕으로 많은 실습을 해보는 것이 중요할 것이다.

데이터 모델의 종류

오늘날 대표적인 데이터 모델의 종류는 관계형 모델(relational model)문서 모델(document model) 으로 구분할 수 있다. 이 외에 네트워크 모델도 있었지만 희미하게 잊혀지고 결국 살아남은 것은 앞 서 설명했던 두 종류의 데이터 모델이다.

관계형 모델

관계형 모델의 대표 주자 프로그래밍을 조금만 공부하면 바로 접할 수 있는 SQL(Structured Query Language) 가 바로 관계형 모델이다.
관계형 모델에서 특정 데이터를 얻을 경우 데이터 모델의 계층을 고려하고 하위 계층의 관점에서 관계를 어떻게 표현할 것인지가 중요한 사항이다.
관계형 모델과 문서 모델의 차이는 뭐가 있을까?
관계형 모델은 테이블의 형태로 데이터를 저장한다. 테이블은 관계로 구성이 되는데 여기서 관계란 데이터를 표현하는 기본 단위를 의미합니다. 테이블에서는 관계를 Row 라고 하고 관계는 순서가 없는 튜플이며 테이블은 이런 순서가 없는 튜플의 모음입니다.
여기서 튜플은 하나의 완전한 데이터 엔티티 또는 객체를 의미합니다. 예를 들어 설명하면 테이블 내에 학생의 이름 이라는 튜플이 존재한다면 해당 튜플은 학생 들의 이름에 관한 모든 정보를 포함하는 것입니다. 그리고 여기서 또 중요한 튜플의 특징은 더 이상 분해할 수 없는 값이며 유일한 값이어야 한다는 것입니다. 학생의 정보를 나타내는 테이블에서 학생의 이름에 관한 관계, Row가 여러 개인 것은 옳지 않기 때문입니다.
관계형의 목표는 정리된 인터페이스 뒤에 구현에 필요한 세부 사항을 숨기는 것이다.

질의 최적화기(query optimizer)

질의 최적화기는 질의의 어느 부분을 어떤 순서로 실행할지를 결정하고 사용할 색인을 자동으로 결정한다. 여기서 이야기하는 질의 최적화기의 어떤 순서를 결정하는 것은 데이터에 접근할 접근 경로를 선택하고 결정하는 것을 이야기 합니다.
하지만 이 접근 경로에 대한 선택은 개발자가 직접 선택하고 설정하는 것이 아닌 미리 데이터베이스에서 작성되어 있는 질의 최적화기를 이용하여 자동으로 생성된다는 것입니다.
질의 최적화기는 짧은 시간에 작성되어서 나온 것이 아닌 오랜 기간을 걸쳐서 개발이 되어 온것이기 때문에 질의 최적화기를 활용하여 특정 데이터에 대한 질의를 수행하는 것이 데이터를 더 효율적으로 사용할 수 있게끔 할 수 있다.

문서형 모델

문서형 모델은 NoSQL 입니다. NoSQL이라는 단어에 대해서 오해할 수 있는 여지가 있기 때문에 먼저 짚고 넘어가자면 NoSQL은 Not Only SQL 의 약자입니다. 그렇다면 왜 Not Only 라는 수식어가 붙었을까요? NoSQL의 가장 대표적인 모델은 문서형 모델입니다.
문서형 모델이 갖는 장점은 임피던스 불일치에 대한 문제를 해결하지 않고 사용이 가능하다는 장점이 있다. 오늘 날 앱을 개발 할 경우 객체 지향적으로 개발하는 경우가 비일비재 하다. 이러한 경향에 맞춰 관계형 데이터를 불러올 경우 구조에 대한 차이로 인해서 불편함을 느끼게 된다. 이러한 불편함을 임피던스 불일치라고 한다. 그래서 오늘날 관계형이 갖는 임피던스 불일치 문제를 해결하기 위하여 많은 ORM(Object Realation Model) 이 개발되고 사용이 되고 있다.
{
  "user_id": 251,
  "first_name": "Bill",
  "last_name": "Gates",
  "summary": "Co-chair of the Bill & Melinda Gates...Active blogger.",
  "region_id": "us:91",
  "industry_id": 131,
  "positions": [
    { "job_title": "Co-chair", "organization": "Bill Foundation" },
    { "job_title": "Co-founder, Chairman", "organization": "Microsoft" }
  ],
  "education": [
    { "school_name": "Harvard University", "start": 1973 },
    { "school_name": "Lakeside School", "start": null }
  ]
}
앞서 설명했던 임피던스의 문제가 문서형 모델의 경우 발생하지 않는데 이러한 이유는 구조적으로 유사하기 때문입니다. 하지만 이러한 구조가 다른 데이터 모델들 중에서 문서형 모델이 앱의 구조와 매우 유사하고 사용성이 용이하다는 것은 아닙니다. 각각의 데이터 모델들은 서로 다른 장점과 단점을 갖고 있기 때문에 이러한 특징을 알고 적합한 모델들을 섞어서 사용하거나 선택해 사용할 필요가 있습니다.

스키마의 유연성

문서형 모델의 데이터베이스를 관리할 때 오해해서는 안되는 것이 문서형 모델에는 스키마가 존재하지 않는다고 생각해서는 안됩니다. 문서형 모델은 유연한 스키마, 동적 스키마를 가진다는 표현이 더 적합한 표현입니다.
그렇다면 유연하고 동적이다의 의미가 무엇일까요? 이는 스키마에의해서 강제되지 않는 스키마를 갖고 있다는 표현이 더 적합할 것입니다. 관계형 모델에서의 스키마를 생각해보겠습니다.
CREATE TABLE User (
	id BIGINT NOT NULL PRIMARY KEY,
	name VARCHAR(255) NOT NULL,
	age INT NOT NULL
);
위와 같이 스키마가 설정되었는데 사용자의 나이에 VARCHAR 타입의 데이터를 저장하고자 할 경우 어떻게 될까요? 데이터 타입 불일치 에러가 발생하면서 제대로 질의가 이루어지지 않을 것입니다. 또 다른 경우를 생각해보겠습니다. 갑자기 마음이 바뀌어서 기존의 스키마에서 age 를 int에서 varchar 로 변경하고 사용자의 first_name 을 추가하려고 할 경우 어떻게 해야 할까요?
ALTER TABLE User
MODIFY COLUMN age VARCHAR(255);

ALTER TABLE User ADD COLUMN first_name TEXT;
UPDATE users SET first_name = split_part(name, '', 1);
위와 같은 질의를 통해서 기존의 스키마를 변경해야 할 것입니다. 여기서 데이터베이스에서는 마이그레이션(migration) 을 수행해야 합니다. 이러한 스키마의 변경 자체는 빠른 시간안에 이루어질 수 있기 때문에 큰 문제가 아닐 수 있습니다. 하지만 특정 몇몇 경우 테이블의 데이터를 복사하여 수행해야 할 경우가 생기기 때문에 주의할 필요가 있습니다.
이제 반대로 유연한 스키마, 동적인 스키마가 어떤 스키마인지 알아보기 위해서 JSON 을 예시로 생각을 해보겠습니다. json에서 기존의 데이터를 수정하거나 타입을 변경하기 위해서는 어떻게 해야 할까요? 그냥 변경하면 됩니다. 새로운 필드를 추가하기 위해서는 어떻게 해야 할까요? 그냥 추가하면 됩니다.
이러한 특징을 보았을 경우 그냥 스키마가 없다 스키마리스(schema-less) 가 더 적합한 표현처럼 보이지만 굳이 왜 유연한 스키마를 갖고 있다는 표현을 하는 것일까요?
스키마가 없다는 표현은 데이터 모델에 구조가 없다 라는 표현과 동일 시 될 수 있습니다. 하지만 사실은 그렇지 않습니다. 실제로 문서형 모델에 특정한 구조를 갖게 끔 작성할 수 있고 그렇지 않을 수도 있습니다.
그리고 스키마가 없다는 표현이 갖는 또 다른 의미는 데이터 모델링의 중요성 을 간과 할 수 있습니다. 문서형 모델이 유연한 스키마를 갖고 있다고 하더라도 문서형 모델 내의 모든 데이터들이 일관성을 갖지 않고 다른 개발자들이 어떤 속성을 갖고 있을 지 예측할 수 없게끔 작성하는 것은 옳지 않기 때문입니다.
이를 조금 더 자세하게 나누어서 설명하자면 관계형 데이터 모델은 쓰기 스키마(schema-on-write) 에 해당하여 쓰여진 모든 데이터가 스키마를 따르고 있음을 보장하고 문서형은 읽기 스키마(schema-on-read) 데이터 구조는 암묵적이고 데이터를 읽을 때만 해석된다는 표현이 더 정확한 표현이다.

데이터를 위한 질의 언어

데이터를 위한 질의 언어는 선언형명령형으로 구분이 된다. 그럼 이 두 가지가 각각 어떠한 특징을 갖고 있고 어떠한 언어에서 사용이 되는 지 알아보자

선언형

SQL은 선언형 질의 언어를 사용하여 데이터모델 내부의 데이터에 대해서 접근한다. 이에 대한 예시를 통해서 선언형이란 어떤 의미인지에 대해서 알아보자
SELECT * FROM animals WHERE family = 'Sharks';
위의 간단한 SQL 구문을 살펴보자 이 SQL 구문의 의미는 무엇일까? animals 테이블 내에 family가 Sharks 인 모든 데이터를 선택한다. 라는 의미를 갖는다. 앞서 풀어서 설명한 구문에 대해서 생각을 해보면 이 구문은 원하는 데이터를 얻기 위한 방법에 대해서 설명하기 보다는 원하는 데이터를 얻기 위한 데이터의 패턴, 즉 결과가 충족해야 하는 조건과 데이터를 어떻게 변환할 지를 지정하고 있다는 것을 알 수 있습니다.
이러한 선언형 질의 방식의 장점은 상세 구현이 숨겨져 있어서 질의를 변경하지 않고도 시스템의 성능을 향상 시킬 수 있다는 것이다. 말이 참 어렵다. 앞서 설명한 내용이 어떤 의미를 하고 있는 지 알아볼 필요가 있다.
명령형의 경우 개발자가 명령한 그대로 모든 작업을 수행해야 한다. 예를 들어 이 명령형 코드를 봐보자
function getSharks() {
  let sharks = [];
  for (let i = 0; i < animals.length; i++) {
    if (animals[i].family === "Sharks") {
      sharks.push(animals[i]);
    }
  }
  return shaks;
}
위의 명령형 코드는 Animals 테이블 내에 데이터들을 순차적으로 나열할 것을 강제한다. 이런 상황에서 데이터베이스 내부적으로 사용이 되지 않는 공간을 회수하고 싶다면 해당 레코드를 옮겨서 저장해야 하고 비어 있는 공간은 순서를 보장해야 하기 때문에 다시 채우는 등의 번거로운 작업을 거쳐야 한다.
하지만 이러한 과정에서 순서를 보장하지 않고 순서가 바뀌어도 상관이 없을 경우는 앞서 겪었던 어려움을 겪지 않아도 되고 데이터베이스 내부에서 최적화할 수 있는 더 많은 여지를 줄 수 있다. 이러한 부분을 제외하고도 명령형은 부수 효과로 인해 예기치 못한 오류가 발생할 수 있고 의존성을 갖는등의 단점을 선언형을 사용할 경우 해소할 수 있다.
이에 대한 이해를 조금 더 돕기 위해서 웹에서 사용되는 선연형 질의 언어인 CSS 를 추가로 설명을 해보겠다. CSS 를 작성해본 경험이 있을 경우 아래의 구문의 결과를 예측할 수 있을 것이다.
li.selectd > p {
  background-color: blue;
}
위와 같이 작성된 css 는 단순히 li 태그 내부의 selected 된 p 태그만을 대상으로 스타일이 적용될 것이다. 이는 단순히 스타일을 적용시키고자 하는 태그의 패턴을 정의한 것이다. 이러한 패턴을 정의하는 것의 장점은 무엇일까? 만약 li 가 사라지거나 selected 된 요소가 없을 경우 추가로 코드를 작성할 필요가 없다. css 문을 이용하여 설정한 패턴과 일치하는 지의 여부를 판단하기 때문에 부수효과가 존재하지 않고 결과를 결정하기 위한 알고리즘을 지정하는 것이 아니라 패턴만 지정하기 때문에 병렬 실행으로 성능이 더 빨라질 가능성이 크다.

다대일 관계 vs 다대다 관계

다대일 관계과 다대다 관계는 내가 어플리케이션을 만들기 위하여 어떠한 데이터 모델을 사용할 것인지에 대한 기준이 되어줄 수 있는 중요한 특징입니다. 이러한 이유는 각각의 데이터 모델을 특정 관계를 갖는 데이터 모델에 적합하고 어떤 모델은 다른 모델에 비해 단점이 있는 데이터 모델들이 존재하기 때문입니다. 여기서 주의할 점은 특정 데이터 모델들이 다른 데이터 모델을 모방하지 못한다거나 다른 관계의 데이터 모델을 다루지 못하는 것은 아니라는 것입니다. 다른 모델들이 특정 관계의 데이터베이스를 관리했을 경우의 장점이 다른 데이터 모델들에 비해 장점이 뚜렷하기 때문에 구분하여 사용하는게 중요하다는 것을 주의하여야 합니다.

다대일 관계

우선 다대일 관계에 대해서 이야기 해보겠습니다. 다대일 관계는 어떤 관계를 갖는 데이터일까요? 예를 들어서 설명해보겠습니다. 학교의 상황을 예시로 들었을 경우 학급은 하나이지만 한 학급에는 여러 학생들이 포함될 수 있습니다. 이러한 관계가 다 대 일 관계인데 많은 사람들은 한 특정 지역이나 앞서 설명했던 학급과 같이 특정 업계나 분야에 속하는 관계를 다 대일 관계라고 정의합니다.
그렇다면 다 대일 관계가 적합하고 사용되어야 하는 경우는 어떤 경우가 있을까요? 주로 중복된 데이터를 정규화하기 위하여 사용이 됩니다. 한 개의 테이블내의 여러 데이터들이 중복되는 특징을 갖고 있을 경우 해당 테이블을 정규화 하기 위하여 별도의 테이블로 분리하여 관리하는 방법들을 사용하게 됩니다.
이러한 다 대일 관계에 더 잘 어울리는 데이터 모델은 어떤 것이 있을까요? 이는 관계형 모델이 문서형 모델에 비해서 더 적합한 데이터 모델이라고 할 수 있습니다. 이러한 이유는 무엇일까요? 문서형 모델에서 기존의 데이터 모델을 수정한다고 가정 해보겠습니다.
{
  "users": [
    {
      "id": "254",
      "school": "Bill"
    },
    {
      "id": "255",
      "school": "Bill"
    },
    {
      "id": "256",
      "school": "Bill"
    }
  ]
}
위와 같이 json 을 이용하여 저장되어 있는 데이터를 정규화를 진행한다고 가정을 해서 school에 대한 데이터를 추가로 작성을 해보겠습니다.
{
  "school_id": 24,
  "name": "Bill",
  "location": "NoWhere"
}
이와 같은 정규화가 이루어졌고 이 데이터 모델을 이용하여 특정 학생이 속한 학교에 대한 정보를 질의한다고 해보겠습니다. 이 경우 학교에 대한 지역 정보를 얻기 위해서는 어떻게 해야 할까요?
const schoolName = users.find((data) => data.id === id).school;
const schoolLocation = school.find((info) => info.name === schoolName).location;
위와 같은 과정을 거쳐서 학교에 대한 지역 정보를 성공적으로 불러왔습니다. 하지만 위의 데이터는 계속 유의미할까요? 위의 문서에서 학교에 대한 정보가 수정되었을 경우 기존의 데이터를 질의하기 위해서 사용했던 명령어들이 적합한, 질의하고자 하는 데이터를 불러온다고 확신할 수 있을까요?
그렇지 않을 확률이 높습니다. 왜냐하면 문서형 데이터를 질의 할 경우 명령형 질의 언어를 이용하여 데이터를 질의하게 되고 이러한 질의는 문서의 데이터가 변경되었을 경우 적합하지 않기 때문입니다.

ID의 유용성

문서형 모델이나 관계형 모델에서 데이터에 대한 정보를 문자로 저장하는 것이 아니라 ID 로 저장하는 것이 갖는 이점이 무엇이 있을까요? 바로 ID는 의미도 포함하고 있지 않다는 것입니다.
어떠한 정보도 저장하지 않음으로써 갖는 장점은 무엇이 있을까요? 이는 어떠한 부수 효과도 주지 않는 다는 것을 의미합니다. 예를 들어서 생각해보겠습니다. 어떤 태그가 있는데 해당 태그는 ID로 연결이 되어 있습니다. 태그와 연결되어 있던 데이터베이스가 변경이 되었다고 가정할 경우 태그에는 어떠한 영향이 있을까요?
변경된 데이터베이스에 해당하는 ID 가 삭제되지 않는 이상 연결된 데이터베이스에는 어떠한 영향도 주지 않습니다. 그러면서도 유연한 데이터 업데이트가 가능하다는 장점을 갖고 있습니다. 연결되어 있는 태그에는 어떠한 추가 작업을 수행하지 않더라도 변경된 데이터를 적용할 수 있다는 장점을 갖고 있습니다.