빌드
개발자를 위한 실전 튜토리얼과 실용 가이드.

센서를 갈아 끼워도 제어는 그대로 — 온실 하나를 두 번 짓지 않는 법
온실 제어기가 비싼 진짜 이유는 센서와 제어가 코드 안에서 1:1로 맞물려 있기 때문이다. 노드가 자기를 선언하게 하고 규칙을 품종이 아니라 종류로 쓰면, 온도 센서를 다른 모델로 바꿔도 고칠 코드가 없다. 같은 서버·같은 규칙으로 서로 다른 두 온실을 실제로 돌린 기록.
매장에 이미 있는 결제기 옆에 서버 하나를 세우고, 태블릿·PC·주방 화면을 붙였다. 세 기기 어디에도 앱을 만들지 않았는데 각각 키오스크·POS·주방 디스플레이가 됐다. 카드 승인 경로는 한 줄도 건드리지 않았다. 코드 전체와 실행 로그, 실제로 렌더된 세 화면을 그대로 싣는다.
STM32H723은 USB 시리얼로, ESP32는 mDNS로 발견해 Wi-Fi TCP로 붙었다. 두 보드가 각자 화면 정의를 건네고, 버튼을 누르면 실제 LED가 켜진다. 클라이언트 코드는 두 경우에 한 글자도 다르지 않다. 시뮬레이터 없음 — 이 편만은 하드웨어가 없으면 검증이 실패한다.
이 시리즈의 모든 화면은 물어서 알았다. 손에 든 화면은 그래도 되지만 벽에 박힌 주방 화면은 안 된다 — 계속 묻거나 늦거나 둘 중 하나가 된다. 구독하고 나서 세 건이 도착하는 동안 화면이 호출한 도구는 0개다.
재시도에 관한 글은 대개 거는 쪽에서 쓰여 있다. 이 편은 받는 쪽에서 센다. 700밀리초 장애를 네 명이 두 가지 방법으로 넘겼고, 둘 다 결국 통과했다. 다른 건 게이트웨이가 그동안 맞은 횟수다 — 64번과 25번.
같은 시간을 두 사람이 동시에 잡는다. 두 처리기는 말로 설명하면 똑같은 일을 한다 — 비었는지 보고, 비었으면 잡는다. 한쪽은 두 사람에게 다 확정을 보내고, 다른 쪽은 안 보낸다. 차이는 중간에 있는 await 하나다.
화면 하나를 두 사람이 연다. 취소 버튼은 둘 다에게 보인다. 알바가 누르면 서버가 거절하고, 거절이 장부에 남는다. 화면 파일은 같은 파일이고, 그 해시를 로그에 찍어 뒀다.
이 시리즈의 모든 샘플은 화면 파일을 앱 옆에 두고 있었다. 이번 클라이언트에는 화면이 한 장도 없다. 서버에 무엇을 그릴지 물어서 그리고, 서버가 바뀌었다고 하면 다시 묻는다. 재설치도 재시작도 빌드도 없다.
Claude Desktop에 "노트에 저장해줘"라고 적으면 내 노트북에서 도는 몇십 줄짜리 서버가 실행된다. 스토어도 배포도 없이 설정 한 줄이다. 그 왕복을 처음부터 끝까지 만들고, dart test로 스스로 검사하게 했다.
화면 강좌 마지막 편. conditional 로 화면이 갈라지고, list 가 개수를 모르는 채로 줄을 만든다. 그리고 세 트랙 열여섯 편이 하나로 붙는다.
2월에 칩, 3월에 계측기, 4월에 블랙박스, 5월에 온실을 만들었다. 각각 자기 앱을 갖고 있고 서로를 모른다. 그런데 화면을 그리는 코드는 스물일곱 벌 전부 바이트가 같았다. 같은 버전이 아니라 같은 파일이다.
화면 강좌 4편. onTap 에는 코드가 없고 도구 이름만 있다. 그 이름이 실제로 호스트까지 갔는지는 그림으로 확인할 수 없어서, 하니스가 눌러 보고 받아 적는다.
화면 강좌 3편. `{{now}}` 하나로 화면과 값이 갈라진다. 그리고 그게 진짜 갈라졌는지는 한 파일을 서로 다른 상태로 두 번 렌더해서 확인한다.
화면 강좌 2편. 여러 개를 놓으려면 좌표가 필요할 것 같지만, linear 는 방향과 간격만 받는다. 좌표를 안 쓰는 게 취향이 아니라 조건인 이유.
온실에 붙은 센서는 제각각이다. 섭씨로 재는 것, 화씨로 재는 것, ppm으로 재는 것. 노드가 자기를 선언하고 규칙이 모델명 대신 종류로 말하게 했더니, 센서를 교체하고 두 개를 증설해도 서버 코드와 규칙이 한 글자도 안 바뀌었다.
화면 강좌 1편. 클라이언트 강좌 4편에서 서버가 보내온 그 덩어리가 정확히 무엇인지. 네 줄짜리 JSON 하나와, 그 안을 절대 들여다보지 않는 호스트 하나로 시작한다.
MCP 클라이언트 강좌 마지막 편. 구독하고, 알림을 받고, 그때 읽는다. 폴링이 자원을 쓰는 건 부차적이다 — 진짜 문제는 두 번 묻는 사이에 값이 두 번 바뀌면 가운데를 영영 못 본다는 것.
MCP 클라이언트 강좌 4편. 서버에서 화면 정의를 읽어 런타임에 넘긴다. 이 파일에는 데스크가 어떻게 생겼는지에 대한 코드가 한 줄도 없다 — 그게 검사된다.
차량 관리자는 블랙박스에서 영상 말고도 볼 게 많다. 운행 기록, 카드 잔량, 충격 감도. 그래서 보통은 전부 주는 API를 만들고 영상 앞에만 권한 검사를 붙인다. 그 검사를 지우면 끝난다. 이 앱은 영상 도구를 잠그지 않고 아예 만들지 않았다.
MCP 클라이언트 강좌 3편. 도구를 부르고 답을 읽는다. 결과가 값이 아니라 콘텐츠 목록이라는 것, 그리고 서버가 거절했을 때 그게 throw 로 오지 않는다는 것 — 그래서 잡는 게 아니라 읽어야 한다.
MCP 클라이언트 강좌 2편. 도구와 리소스 목록을 묻는다. 두 줄이면 끝나는데, 이 두 줄이 있느냐 없느냐가 "이 서버 전용 클라이언트" 와 "아무 서버에나 서는 클라이언트" 를 가른다.
MCP 클라이언트 강좌 첫 편. 서버에 붙는다. 여기서 볼 것은 접속 코드가 아니라 전송의 정체다 — 열 소켓이 아니라 띄울 명령이고, 그래서 나중에 전송을 바꾸는 일이 명령 한 줄 바꾸는 일이 된다.
MCP 서버 강좌 마지막 편. 화면이 1초마다 묻는 걸 없앤다. 서버가 알리는데, 알림에는 uri 만 담고 값은 안 담는다. 그리고 구독하지 않은 클라이언트에는 아무것도 안 간다.
계측기는 이미 말할 줄 안다. 문제는 세 회사가 세 가지로 답한다는 것이다 — 지수 표기, 캐리지 리턴, 단위가 붙은 값. 그 셋을 한 모양으로 만들고 한 화면에 세웠다. 그리고 화면은 손잡이가 아니라 계기가 말한 숫자를 보여준다.
MCP 서버 강좌 5편. 대기 인원이 변수에 있으면 프로세스와 함께 사라진다. 파일에 적는데, 매번 전체를 다시 쓴다. 부분 갱신보다 느리지만 반쯤 쓰이다 만 기록이 생기지 않는다.
MCP 서버 강좌 4편. 화면을 서버가 파일로 들고 있다가 내준다. 파일을 고치면 재빌드도 재설치도 없이 다음 접속에서 바뀐다 — 다만 매 요청 읽어야 그 말이 참이 된다.
MCP 서버 강좌 3편. 입력 스키마를 붙이고, 그 스키마를 믿지 않는 핸들러를 쓴다. 0명을 들여보내라는 요청과 99명을 들여보내라는 요청이 각각 다른 이유로 거절되는 것까지.
평가보드에 화면을 붙이려면 보통 그래픽 스택을 얹고 펌웨어를 다시 굽는다. 그 대신 보드가 자기 능력을 도구로, 자기 화면을 리소스로 내주게 했다. 책상 위 STM32H723에 붙어 LED를 켜고, 보드가 건넨 656바이트짜리 화면을 그대로 렌더했다.
MCP 서버 강좌 2편. 도구를 하나 등록한다. 이름·설명·입력 스키마·핸들러 네 조각인데, 그중 셋은 우리가 아니라 부르는 쪽이 읽는다. 그래서 설명문을 잘 쓰는 게 핸들러를 잘 쓰는 것보다 값이 크다.
2주 전 번호판에 버튼을 붙였다. 누르면 숫자가 움직인다. 그런데 그 숫자를 누가 들고 있느냐가 문제다. 화면이 들고 있으면 두 번째 패널이 다른 숫자를 띄운다. 카운터가 들고 있으면 패널을 뽑았다 꽂아도 같은 숫자다.
패널의 능력을 도구로, 화면을 정의로, 런타임이 렌더로. 그 전체 사슬이 실제로 도는 샘플을 처음부터 끝까지 펼쳐, 패키지들이 어떻게 맞물리는지 보인다. 화면은 그린 게 아니라 실제로 렌더해 캡처했다.
대기실 번호판을 만든다. 화면 정의는 아홉 줄이고, 그 아홉 줄은 클라이언트 안에 없다. 서버가 파일로 들고 있다가 접속한 쪽에 건네준다. 빌드도 설치도 없다는 말은 그 뜻이다.
MCP 서버 강좌 첫 편. 도구도 리소스도 없이 서버만 세운다. 여기서 확인할 건 하나다 — 클라이언트가 붙어서 initialize 에 답을 받는가. 그리고 이 단계에서 박아 둬야 끝까지 안 터지는 규칙 하나.