
SQLite를 선택한 이유
요약
데이터의 단순 조회를 넘어 이력 축적을 위해 SQLite를 선택한 과정을 다룹니다. API의 비영속성과 스프레드시트의 자동화 한계를 극복하고, 운영 환경과의 분리를 위해 SQLite를 채택한 비엔지니어의 의사결정 기록입니다.
핵심 포인트
- 데이터의 스냅샷 조회를 넘어 트렌드 분석을 위한 이력 축적의 중요성
- API 기반 비영속성 방식이 AI의 근거 제시와 이력 비교에 미치는 한계
- 스프레드시트의 자동화 재현성 및 데이터 정합성 문제
- 운영 DB(MySQL)와의 혼동을 방지하기 위한 심리적·기술적 경계 설정
- 단일 미디어 규모에 적합한 가볍고 설명 가능한 SQLite의 채택
연결이 늘어나고 숫자가 보이기 시작하면, 다음 불만이 생겨난다. "지금 상황"은 알 수 있다. 하지만 "어제와 비교해서 어떤가"는 알 수 없다.
GA4 화면을 열면 오늘의 숫자는 보인다. Search Console도 마찬가지다. WordPress MCP로 기사는 가져올 수 있다. 하지만 그것들은 그 순간의 스냅샷이다. 아침에 비교하고 싶은 것은 트렌드와 예외, 그리고 근거 있는 한마디다. 라이브 참조(Live reference)만으로는 이력이 남지 않는다. 이력이 남지 않으면 AI도 인간도 같은 근거로 이야기할 수 없다.
이번 글에서는 데이터를 "보는 것"에서 "쌓는 것"으로 나아간 판단——왜 SQLite를 선택했는가——에 대해 쓰고자 한다. DB 입문 강의가 아니다. 비엔지니어(Non-engineer)가 무엇을 거부하고 무엇을 채택했는지에 대한 기록이다.
Vol.02에서 MCP와 API의 연결을 늘리고, Vol.03에서 폭주를 막고, Vol.04에서 사양의 오너(Owner)를 인간으로 돌려놓았다. 거기까지 오니 데이터의 저장 공간이 공백 상태였다. Connector는 움직이기 시작했다. GA4와 GSC는 API로 일간 데이터를 취득하는 방침도 확정되었다. WordPress 기사는 MCP로부터 읽을 수 있다. 하지만 읽은 결과를 어디에 남길지가 결정되지 않았다.
운영진의 질문은 단순했다. 어제의 PV와 오늘의 PV를 동일한 조건으로 나열하고 싶다. 지난주의 검색 쿼리와 이번 주를 비교하고 싶다. 기사 업데이트가 유입에 어떻게 영향을 미쳤는지, 감각이 아닌 이력으로 추적하고 싶다. 이것은 대시보드의 외관 문제보다 앞선, 축적의 문제였다.
테마는 이력을 위해 SQLite First를 선택한 이유와 거부한 선택지들이다.
MySQL, PostgreSQL, API만 사용, 스프레드시트——모두 검토 대상이었다. AI는 비교표를 만드는 데 능숙하다. 표는 아름답다. 하지만 채택은 인간의 몫이었다. Kagoshimaniax라는 단일 미디어의 아침에 무엇이 가장 가볍고 설명 가능한가. 거기서부터 역산했다.
논의의 출발점은 "API의 응답을 그때마다 확인하면 충분하지 않을까"라는 안이었다. 구현은 가볍다. 화면도 만들기 쉽다. 하지만 운용해 보니 한계가 빨리 왔다. 어제의 숫자가 오늘의 화면에 남지 않는다. 취득에 실패한 날을 나중에 추적할 수 없다. AI에게 "지난주와 비교해서"라고 물어도 근거 데이터가 없다. 비영속성(Non-persistence)은 이력 비교와 AI의 근거 제시 모두를 약화시켰다.
스프레드시트 안도 나왔다. 나는 평소에 표 계산에 익숙하다. 겉보기에는 안심이 된다. 하지만 Connector의 일간 실행, 타입(Type)의 정합성, 자동화의 재현성을 고려하면 운영 OS의 핵심에는 적합하지 않았다. 수동으로 고칠 수 있는 것은 편리하지만, 수동으로 고치는 순간 자동화의 신뢰도가 떨어진다. 신뢰도가 떨어지면 아침 확인 작업이 다시 개인의 역량에 의존하는 속인화(Individualization) 현상이 발생한다.
MySQL / MariaDB도 선택지에 있었다. WordPress 운영 환경이 DB를 사용하고 있는 만큼 친숙하다. 하지만 여기서 큰 불안 요소가 있었다. 운영 중인 WordPress의 DB와 혼동할 리스크다. 로컬에서 운영 OS를 키워나갈 때, 운영 환경과 같은 종류의 DB를 만지면 심리적 경계가 모호해진다. 비엔지니어인 나에게 그 모호함은 치명적이었다. 만져서는 안 되는 것과 만져도 되는 것을 종류 단계에서부터 나누고 싶었다.
PostgreSQL은 "제대로 된 선택"처럼 보였다. 향후 클라우드 이전도 고려할 수 있다. 하지만 당시의 규모——단일 미디어, 로컬 완결, 우선 내가 사용함——에는 과하게 느껴졌다. 과도한 선택은 셋업과 운용의 설명 비용을 늘린다. 설명 비용이 늘어나면 Dogfooding(자사 제품 사용)이 늦어진다.
채택한 것은 SQLite First였다. 단일 파일 db/kagoshimaniax.db에 기사 동기화, Connector의 일간 출력, 실행 로그를 집약한다. 스키마(Schema)는 database/schema.sql로 관리한다. 나중에 ADR-0001로 남겼지만, 당시의 표현은 더 소박했다. "파일 하나에 이력을 쌓는다. 복사하면 백업이 된다. WordPress 운영 DB와는 별개라는 것을 한눈에 알 수 있다".
실제로 진행한 축적의 단위는 대략 다음 세 가지였다.
| 데이터 종류 | 저장 방식 | 아침에 도움이 된 점 |
|---|---|---|
| WordPress 기사 | 동기화하여 articles에 저장 | 업데이트와 유입을 동일한 맥락에서 확인 |
| GA4 / GSC 일간 데이터 | API Connector로 취득 및 저장 | 어제와의 비교가 가능해짐 |
| Connector 실행 로그 | system_connector_runs 등 | 결측일 및 실패일을 추적 가능 |
실패도 있었다. 처음에는 "DB에 들어가기만 하면 자동으로 가치가 생긴다"라고 생각할 뻔했다. 넣기만 해서는, 화면이 없다면 아침을 볼 수 없다. 축적과 가시화(Visualization)는 한 세트라는 것을 깨달았다. 또 다른 실패는 스키마(Schema)를 갑자기 크게 만들려고 했던 것이다. AI는 친절하게도 많은 테이블을 제안한다. 나는 그것을 멈추고, 우선 일간 데이터, 기사, 그리고 실행 로그(Execution Log)로 범위를 좁혔다. 범위를 좁혔기에 리뷰할 수 있었다.
WordPress 운영 DB와는 별개의 계통으로 운영한다는 판단도 중요했다. 기사는 동기화(Synchronization)가 필요하다고 명시했다. 동기화를 잊으면 DB의 기사와 운영 환경이 어긋난다. 이 어긋남은 장애가 아니라 설계상의 전제다. 전제를 문서에 기록함으로써 나중에 스스로 길을 잃지 않을 수 있었다.
Local First의 감각도 이 결정과 함께 굳어졌다. 데이터의 주권을 로컬(Local)에 둔다. 클라우드(Cloud)는 나중에 검토할 수 있다 (ADR-0006의 방향). 우선 내 Mac에서 아침의 10분이 돌아가는 것. 그것이 우선이었다.
백업 이야기도 이 결정으로 인해 처음으로 현실이 되었다. SQLite는 파일 복사만으로 끝난다. 비엔지니어인 나에게는 mysqldump보다 설명하기 쉬웠다. "일주일에 한 번, db 폴더를 복사한다"——그것만으로 이력에 대한 안심이 한 단계 올라갔다. 안심은 화려한 기능보다 먼저 효과를 발휘할 때가 있다.
기각한 선택지들을 다시 나열해 보면 당시의 판단을 쉽게 추적할 수 있다.
| 기각한 안 | 언뜻 보이는 매력 | 기각 이유 (운영 관점) |
|---|---|---|
| API 전용 | 가볍다, 바로 보인다 | 이력·결손 추적·AI 근거가 약함 |
| ... |
SQLite는 비엔지니어에게 설명하기 쉬운 DB였다. 서버라는 개념을 늘리지 않는다. 파일이 늘어날 뿐이다. 파일은 무섭지 않다. 서버는 아직 조금 무섭다. 설명하기 쉽다는 점은 채택의 이유가 될 수 있다. 특히 혼자서 운영과 개발 판단을 겸할 때 말이다.
이력을 남기는 것은 AI와의 관계도 바꾸었다. 근거 있는 제안은 생데이터(Raw Data)의 스냅샷만으로는 약하다. 어제와의 차분(Difference)이 있으면, "늘었나/줄었나/예외인가"를 같은 언어로 이야기할 수 있다. 이야기할 수 있게 되면 채택의 질이 올라간다. DB는 AI를 위한 것이라기보다, 인간의 판단을 위한 것이었다.
트레이드오프(Trade-off)도 받아들였다. 동시 쓰기나 대규모 멀티 테넌트(Multi-tenant)에는 적합하지 않다. 나중에 클라우드로 옮길 때는 재검토할지도 모른다. 하지만 Version 1.0 시점에서는 과도한 앞서 읽기(Pre-reading)보다, 오늘 아침의 비교를 할 수 있다는 점의 가치가 더 컸다. 앞서 읽기는 사양(Specification)에 적어두면 되지만, 구현을 먼저 비대하게 만들지는 않는다.
마지막으로, SQLite를 "영원한 정답"으로 만들지 않기로 했다. SQLite First는 현 단계의 정답이다. First라는 단어는 고정이 아니라 순서를 나타낸다. 순서를 오해하면 기술이 교리가 된다. Vol.02의 MCP에서 범했던 실수를 반복하고 싶지 않았다.
"쌓는 것"으로 나아감으로써 Connector의 의미도 변했다. 단순히 가져오기만 하는 스크립트에서, 운영 OS의 혈액과 같은 존재로. 혈액이 없으면 화면은 새하얗게 보인다. 화면은 나중에 추가할 수 있다. 혈액을 먼저 통하게 하는 판단은 수수하지만 효과적이었다. 수수한 판단을 지탱한 것은 결국 아침의 비교라는 매우 실무적인 욕구였다. 욕구가 사양이 되고, 사양이 SQLite가 되고, SQLite가 다음 이야기——모든 것이 연결된 날——로 가는 다리가 되었다.
- "지금 어떤가"만으로는 운영 판단이 얕아진다. 이력이 필요했다.
- API 전용·스프레드시트·MySQL은 각각의 이유가 있어 기각했다.
- WordPress 운영 DB와의 혼동 리스크는 비엔지니어에게 실리적인 기각 이유였다.
- SQLite First는 가벼움과 Local First, 그리고 설명 가능성의 균형이 좋았다.
- 축적만으로는 불충분하다. 화면과 세트로 구성되어야 비로소 아침의 가치가 된다.
- First는 교리가 아니라, 현 단계의 순서를 나타내는 단어로 사용한다.
다음에는 뿔뿔이 흩어져 늘어났던 연결과 축적이 하나의 OS로 보이기 시작한 날——모든 것이 연결된 날——을 쓰겠다.
| 항목 | 내용 |
|---|---|
| Season | 1 |
| ... | |
| Vol.06 「모든 것이 연결된 날」 |
Connector와 SQLite, 그리고 화면이 하나의 운영 OS로 보이기 시작한 이야기입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기