탐구

모든 서버가 앱이다

작성: makemind · 2026년 4월 2일
이 글에는 실증본이 있습니다. 같은 주제를 돌아가는 코드와 실제로 그려진 화면으로 다시 만들었습니다 — 내놓지 않은 것이 앱을 지킨다 — 모든 서버가 앱이다, 그 다음 이야기. 이 글은 쓰인 그대로 둡니다.

당신의 책상 어딘가, 혹은 공장 한구석, 혹은 클라우드의 익명의 랙 안에 — 묵묵히 돌아가는 무언가가 있다. 주문을 받아 적고, 재고를 세고, 온도를 읽고, 회비를 기록한다. 그것은 아이콘도 없고, 스토어에도 없고, 누가 "써 봤다"고 자랑하지도 않는다. 우리는 그것을 서버라 부르며, 앱과는 전혀 다른 종(種)으로 취급해 왔다. 그런데 이 글은 한 문장을 정면으로 들이민다 — 그 묵묵한 것이, 사실은 앱이었다. 처음부터.

지난 Vol들에서 우리는 서버가 화면을 정의하는 걸 거듭 봤다. 패널에서, 칩에서, 계측기에서. 각각은 "이 장치 위에서도 된다"는 사례였다. 이번 Vol는 그 모든 사례가 가리키는 한 문장을 정면으로 본다. 너무 단순해서 그냥 지나치기 쉬운 문장이다. 모든 서버가 앱이다.

이 문장이 농담처럼 들린다면, 그건 우리가 "앱"과 "서버"를 너무 다른 것으로 여겨 왔기 때문이다. 하나는 손에 잡히는 아이콘, 다른 하나는 보이지 않는 기계. 이 글은 그 둘이 실은 같은 것의 두 면이었음을, 한 겹씩 벗겨 보인다. 그리고 마지막에는, 둘이 같아진 다음에 무엇이 위험해지는지 — 그래서 무엇을 내놓지 말아야 하는지를 본다. 등호 하나로 끝나는 글이 아니다.

데이터센터의 서버 랙 — 묵묵히 돌아가는 이것들이, 사실은 처음부터 앱이었다
데이터센터의 서버 랙 — 묵묵히 돌아가는 이것들이, 사실은 처음부터 앱이었다

앱이란 무엇인가 — 껍데기를 걷어내고

먼저 물어야 한다. 앱이란 무엇인가. 우리는 앱을 아이콘으로, 스토어에서 받는 것으로, 기기에 설치되는 것으로 떠올린다. 그런데 그건 앱의 전달 방식이지 앱의 본질이 아니다. 종이에 인쇄된 글자가 책의 본질이 아니듯, 설치되고 아이콘이 생기는 절차는 앱이 우리 손에 도착하는 방식일 뿐이다.

기술적 껍데기를 걷어내면, 앱은 세 가지를 하는 무언가다. 무엇을 보여줄지(화면), 무엇을 할 수 있는지(도구·기능), 무엇을 기억하는지(데이터). 화면이 뜨고, 버튼을 누르면 무언가가 일어나고, 그 결과가 어딘가에 남는다. 카메라 앱이든, 은행 앱이든, 메모 앱이든 — 본질은 이 셋의 조합이다. 화면, 도구, 데이터.

이 셋을 손에 쥐고 다시 세상을 둘러보면, 갑자기 많은 것이 앱처럼 보이기 시작한다. 식당의 키오스크: 메뉴를 보여주고(화면), 주문을 넣고(도구), 무엇을 시켰는지 기억한다(데이터). 자동차의 계기판: 속도를 보여주고, 모드를 바꾸고, 주행 기록을 남긴다. 우리가 "앱"이라 부르지 않았을 뿐, 화면·도구·데이터의 조합은 도처에 있었다. 그렇다면 질문은 자연스럽게 뒤집힌다. 왜 어떤 조합만 앱이라 불리고, 어떤 조합은 아닌가?

서버는 이미 둘을 갖고 있었다

이제 서버를 보자. 잘 만들어진 서버는 무엇을 하나. 자기가 할 수 있는 일을 기능으로 노출한다 — "주문을 생성해", "재고를 조회해", "이 사용자를 인증해". 그리고 데이터를 보관한다 — 주문 목록, 재고 수량, 회원 명부. 요청이 오면 답한다. 수십 년간 우리가 "백엔드"라 부르며 화면 뒤에 숨겨 둔 그것.

여기서 멈춰 서 보자. 앱의 세 가지 중 을, 서버는 이미 하고 있었다. 도구가 있고(기능), 데이터가 있다(저장). 빠진 것은 단 하나, 화면이었다. 서버는 앱의 2/3였다. 우리가 그것을 앱이라 부르지 않은 유일한 이유는, 그것이 사람에게 보일 얼굴이 없었기 때문이다.

그래서 우리는 늘 서버 위에 별도의 앱을 얹었다. 서버는 뒤에서 기능과 데이터를 제공하고, 앱은 앞에서 화면을 그렸다. 둘은 다른 프로젝트였고, 다른 저장소에 살았고, 다른 팀이 만들기도 했으며, 둘을 잇는 코드 — API 호출, 응답 파싱, 화면 갱신, 에러 처리, 로딩 상태 — 를 또 한 겹 짜야 했다. 같은 "주문"이라는 개념이, 서버 코드에 한 번, 앱 코드에 또 한 번, 그 사이 연결 코드에 또 한 번 — 세 번 표현됐다. 필드 하나를 추가하면 세 곳을 고쳐야 했다. 이름 하나를 바꾸면 세 곳이 어긋날 위험을 졌다. 이 삼중의 중복이 모든 앱 개발의 밑바닥에 묵직하게 깔려 있었다. 우리는 그걸 "일"이라 부르며 당연하게 여겼다.

빠진 하나가 채워지면

서버 정의 방식이 채운 게 바로 그 빠진 하나다. 서버가 도구와 데이터뿐 아니라 화면까지 정의해 내보낼 수 있다면 — "이 화면엔 주문 목록을 보여라, 각 항목에 취소 버튼을 달아라, 누르면 주문 취소 도구를 호출하라" — 그 순간 서버는 앱의 세 가지를 모두 갖춘다. 얼굴이 생긴 것이다.

더는 "서버 위에 앱을 얹는" 게 아니다. 서버가 곧 앱이다. 화면과 도구와 데이터가 한자리에서 정의되니, 셋을 잇는 중복 코드도 사라진다. "주문"이라는 개념이 한 번만 표현된다. 한 곳을 고치면 화면도, 동작도, 저장도 함께 따라온다. 세 번 적던 것을 한 번 적게 되는 것 — 이것이 등호의 첫 번째 선물이다.

서버는 앱의 3분의 2였다. 화면 한 겹이 더해지는 순간, 나머지 3분의 1이 채워지고 등호가 닫힌다. 서버 = 앱.

이 작은 등호가 큰 함의를 연다. 세상의 거의 모든 것에는 이미 서버가 있다. 쇼핑몰의 주문 서버, 공장의 설비 관제 서버, 병원의 진료 기록 시스템, 작은 동호회의 회비 관리 스크립트, 누군가 주말에 만든 사이드 프로젝트, 책상 위에서 깜빡이는 평가보드 한 장. 그 서버들이 약속된 방식으로 화면을 정의할 수 있게 되는 순간 — 그 모든 서버가 직접 앱이 된다. 따로 앱을 빌드할 것도, 스토어에 올릴 것도, 앞단을 새로 짤 것도 없이. 이미 있던 시스템이, 화면 한 겹을 정의하는 것으로 앱이 된다.

그동안 이 서버들 대부분이 앱을 갖지 못한 이유를 떠올려 보면 등호의 무게가 더 분명해진다. 앱이 없었던 건 능력이 없어서가 아니었다. 동호회 회비 스크립트는 회비를 정확히 계산할 줄 안다. 공장의 관제 서버는 설비의 모든 수치를 안다. 다만 거기에 얼굴을 붙이는 비용 — 별도의 앱 프로젝트, 디자이너, 스토어 등록, 양쪽을 잇는 코드 — 이 그 작은 시스템들이 감당하기엔 너무 컸을 뿐이다. 그래서 능력 있는 수많은 서버가 "관리자만 콘솔로 만지는 것"으로 평생을 살았다. 등호는 그 비용을 화면 정의 한 겹으로 줄인다. 얼굴을 가질 자격이 있었으나 비용 때문에 못 가졌던 것들이, 비로소 얼굴을 갖는다.

한 장면 — 무엇을 내놓고, 무엇을 잠가 둘 것인가

추상적으로 들릴 테니 한 장면을 그리자. 작은 카페의 주방 한쪽에, 매출과 재고와 레시피를 관리하는 서버가 돌아간다고 하자. 사장이 직접 만든 것이다 — 화려하진 않지만 자기 가게를 정확히 안다. 이 서버는 여러 가지를 할 수 있다. 주문을 받고, 재고를 깎고, 일일 매출을 집계하고, 레시피의 원가를 계산하고, 직원의 출퇴근을 기록하고, 그리고 — 데이터베이스 전체를 삭제할 수도 있다.

이 서버가 앱이 되는 순간, 사장은 한 가지 결정을 내려야 한다. 무엇을 도구로 내놓을 것인가. 카운터의 태블릿에 띄울 화면을 위해, 그는 "주문 받기"와 "재고 조회"를 도구로 연다. 점원들이 누를 버튼이다. 하지만 "일일 매출 집계"는 사장 본인의 화면에만 연다 — 점원이 볼 것이 아니다. 그리고 "데이터베이스 삭제"는 어떤 화면에도, 어떤 도구로도 내놓지 않는다. 그 능력은 서버 안에 있되, 표면 위로는 존재하지 않는다. 버튼이 없으니 누를 수 없고, 도구가 없으니 호출할 수 없다.

여기에 이 글의 두 번째 매듭이 있다. 서버가 앱이 된다는 건, 서버의 모든 능력이 화면에 노출된다는 뜻이 아니다. 정반대다. 앱이 된다는 건, 그 수많은 능력 중 무엇을 표면에 올리고 무엇을 잠가 둘지를 결정하는 일이다. 키오스크에 "환불" 버튼은 두되 "전 매장 가격 일괄 변경"은 두지 않는 것. 그 선택이 곧 앱의 모양이고, 동시에 앱의 안전이다.

그리고 이 결정은 한 번으로 끝나지 않는다. 같은 서버가 누구의 화면을 위해 앱이 되느냐에 따라, 열고 잠그는 선이 달라진다. 점원의 태블릿을 위한 화면, 사장의 휴대폰을 위한 화면, 회계사에게 잠깐 열어 주는 화면 — 같은 서버, 같은 능력 더미에서 서로 다른 도구 집합을 골라내면, 한 서버가 여러 앱이 된다. "전 직원 급여 조회"는 사장의 화면에만, "내 출퇴근 기록"은 점원의 화면에만. 하나의 묵묵한 기계 위에서, 보는 사람마다 다른 얼굴이 떠오른다. 무엇을 도구로 고르느냐가 그 얼굴을 결정한다.

무엇을 도구로 내놓지 않을지가, 무엇을 내놓을지만큼 그 앱을 정의한다.

약속된 언어가 핵심이다

여기서 "약속된 방식"이 전부다. 서버와 기기가 같은 언어로 말해야 한다. 무엇을 화면이라 부르고, 위젯의 종류는 어떻게 정하고, 도구를 어떻게 호출하고, 데이터를 어떤 모양으로 주고받을지에 대한 공통 규약. 이 규약이 없으면, 각 서버는 또 자기만의 방식으로 화면을 정의할 테고, 그러면 SDUI가 그랬듯 "그 회사 그 앱에서만 되는" 폐쇄 시스템으로 돌아간다. 카페의 서버가 정의한 화면을 카페가 만든 기기만 그릴 수 있다면, 그건 그냥 옛날 방식에 이름만 바꿔 단 것이다.

규약이 한 회사 안에 갇히지 않고 열려 있을 때, 비로소 "아무 서버나, 아무 기기에, 화면을 정의해 보낸다"가 성립한다. 카페 사장이 만든 서버가 정의한 화면을, 그가 마트에서 산 평범한 태블릿의 범용 런타임이 그려 낸다. 둘은 서로를 모른다. 태블릿은 카페 서버를 위해 만들어지지 않았고, 서버는 그 태블릿의 기종을 모른다. 그래도 같은 언어를 쓰기에 통한다. 이것이 브라우저가 어느 회사 서버의 HTML이든 그려 내는 원리와 정확히 같다. 이 매거진이 한 열린 공통 언어를 거듭 이야기하는 이유가 이것이다 — 그것이 서버와 기기 사이의 공용어이기 때문이다. makemind의 런타임은 그 공용어를 그리는 쪽에 서 있을 뿐이다.

여기서 한 가지를 분명히 해 두자. 이 "약속된 언어"는 거창한 새 프로그래밍 언어가 아니다. "여기 제목 하나, 그 아래 버튼 하나, 버튼을 누르면 이 도구를 부른다"를 적는 구조화된 서술에 가깝다. HTML이 프로그래밍 언어가 아니라 문서의 구조를 적는 약속이었듯이. 그래서 서버를 만들 줄 아는 사람이라면, 이미 그 언어의 8할을 아는 셈이다 — 자기 서버가 무엇을 할 수 있는지를 이미 알고 있으니까.

열린 표면에는 경계가 필요하다

그런데 서버가 앱이 된다는 건, 좋기만 한 일이 아니다. 무게가 따라온다. 표면을 연다는 것은, 그 표면을 향한 위협도 함께 연다는 뜻이기 때문이다.

화면을 내보낸다는 건 책임도 같이 진다는 뜻이다. 무엇을 보여줘도 되고 무엇은 안 되는지. 누가 그 화면을 받을 자격이 있는지. 서버가 악의적이거나 뚫렸을 때, 받는 쪽 기기를 어디까지 위험에 빠뜨릴 수 있는지. 표면이 열린 만큼, 그 표면을 지키는 경계도 같은 크기로 열려 있어야 한다. 여기에는 두 종류의 경계가 있고, 둘을 구분하는 것이 중요하다.

첫째, 받는 쪽의 경계 — 런타임이 정의를 검증한다. 기기의 런타임은 받은 정의를 신뢰하지 않는다. 서버가 보낸 화면 정의가 할 수 있는 일은 런타임이 정한 울타리 안에 묶인다 — 임의 코드 실행이 아니라, 미리 정해진 위젯과 도구의 조합만 가능하다. 서버가 "이 코드를 기기에서 실행해"라고 말할 길은 없다. "이 위젯들을 이렇게 배치하고, 누르면 네가 가진 도구 중 이것을 불러"라고 말할 수 있을 뿐이다. 브라우저가 임의 사이트의 자바스크립트를 샌드박스 안에서만 실행하는 것과 같은 발상이다. 악의적 서버가 보낼 수 있는 최악도, 결국 런타임이 허용한 위젯과 도구의 범위를 넘지 못한다.

둘째, 내보내는 쪽의 경계 — 무엇을 도구로 만들지 않는가. 이게 더 미묘하고, 더 근본적이다. 앞의 카페 장면에서 봤듯, 어떤 능력을 애초에 도구로 만들지 않음으로써 불가침으로 남기는 것. "데이터베이스 삭제"가 도구 목록에 없으면, 아무리 화면을 조작해도, 아무리 정의를 변조해도 그 일은 일어날 수 없다. 존재하지 않는 버튼은 뚫을 수 없기 때문이다. 이건 코드로 막는 방어의 문제가 아니라, 무엇을 표면에 올릴지를 정하는 설계의 문제다. 가장 강한 보안은 막는 것이 아니라, 애초에 길을 내지 않는 것이다.

이 두 번째 경계가 이 Vol의 진짜 주제다. 서버가 앱이 될 때, 우리는 자연히 "무엇을 보여줄까, 무엇을 누르게 할까"를 생각한다. 그런데 그만큼 중요한 질문이 그 옆에 있다 — 무엇을 끝내 도구로 만들지 않을 것인가. 그 질문에 답하는 것이, 서버를 앱으로 만드는 일의 절반이다.

정직하게 — 모든 서버가 좋은 앱이 되지는 않는다

여기까지가 비전이다. 그런데 비전은 한계를 정직하게 말할 때만 신뢰를 얻는다. 몇 가지를 분명히 해 두자.

*"서버 = 앱"은 자동이 아니다. 서버가 도구와 데이터를 가졌다고 해서, 좋은 화면이 저절로 생기지는 않는다. 누군가는 여전히 "이 화면엔 무엇을 보여줄지, 어떤 흐름으로 이어질지"를 설계해야 한다. 등호가 없애 주는 것은 연결 코드의 중복이지, 디자인이라는 일 자체가 아니다. 잘 짜인 서버라도 화면 설계가 엉성하면 엉성한 앱이 된다. 이 전환은 노동을 없애는 게 아니라, 노동의 종류*를 바꾼다 — 배관을 잇던 시간을 화면을 고민하는 데 쓰게.

모든 것이 화면을 가질 만한 건 아니다. 어떤 서버는 다른 서버하고만 말하는 게 본분이다. 사람이 볼 화면이 애초에 필요 없는 것에 억지로 얼굴을 달 이유는 없다. "될 수 있다"가 "되어야 한다"는 아니다. 화면은 사람과 만나야 하는 자리에만 필요하다.

기존 시스템이 곧장 변신하지는 않는다. 수십 년 된 서버가 약속된 언어를 하루아침에 말하게 되는 건 아니다. 그 서버가 가진 능력을 도구의 모양으로 정리하고, 어느 것을 열고 어느 것을 잠글지 결정하는 — 그 얇지만 분명한 한 겹의 작업이 필요하다. 다만 그 한 겹은, 별도의 앱을 통째로 새로 짜는 것에 비하면 비교할 수 없이 얇다. 우리가 줄인다고 말하는 것은 그 차이다.

다음

그래서 이 Vol에서 우리는 불가침의 경계를 지키면서 서버가 앱이 되는 자리를 본다. 영상은 한 프레임도 건드리지 않으면서, 그 주변의 로그와 설정만 화면으로 여는 블랙박스 — 영상 수정 도구를 아예 만들지 않음으로써 무결성을 지키는 사례. 그리고 진단은 사람에게 남기면서, 진료의 흐름만 화면으로 정리하는 의사의 도구 — 판단의 권한을 도구 밖에 두는 사례. 두 사례 모두, 강조점은 같은 곳에 있다. 무엇을 도구로 만들었는가가 아니라, 무엇을 끝내 만들지 않았는가.

서버가 앱이 되어도, 건드리면 안 되는 것은 그대로 둔다. 능력을 모두 표면에 올리는 것이 아니라, 올릴 것과 잠가 둘 것을 가르는 손 — 그것이 묵묵한 기계를 비로소 앱으로 만든다. 무엇을 도구로 만들지 않을지가, 무엇을 만들지만큼 중요한 설계가 되는 자리. 책상 위에서 깜빡이던 그 익명의 기계가, 얼굴을 갖되 함부로 열리지 않는 — 그런 앱이 되는 자리를 다음 글들에서 본다.


makemind.dev 「탐구」 — 「모든 서버가 앱이다」 Vol의 여는 글입니다. 서버가 앱이 되는 자리를, 넘어서는 안 될 경계와 함께 봅니다.

Twitter