MUBLO · SYSTEM NOTE

ABOUT

SYSTEM NOTE

스킨 — 화면을 만드는 일이 개발이 되어서는 안 됩니다

wwiz 2026-08-06 12:59 9분 읽기 조회 88 수정됨

목록 화면 하나를 다르게 보이게 만들어야 한다고 해봅시다.
제목 아래에 요약을 넣고, 썸네일을 왼쪽으로 옮기고, 날짜를 상대 시간으로 바꾸는 정도입니다.

데이터와 조회 조건은 그대로입니다. 바뀌는 것은 값을 어떤 태그에 담아 어디에 놓느냐뿐입니다.

그런데 화면 파일 위쪽에 요청 파라미터와 조회 조건, 비밀글과 회원 등급의 권한 판단, 첨부 조회가 함께 들어 있다면 태그 하나를 옮기는 일도 표현의 변경으로 끝나지 않습니다.
어디까지가 화면이고 어디부터가 기능인지 먼저 알아내야 합니다.

고칠 수 있다는 것만으로는 부족합니다

네 번째 글에서 운영자가 기능을 직접 배치할 수 있어야 한다고 적었고, 여섯 번째 글에서는 되돌릴 수 있어야 시도할 수 있다고 적었습니다. 화면을 만드는 사람에게는 조건이 하나 더 필요합니다.
고쳐도 되는 자리와 건드리면 안 되는 자리가 파일 단위로 나뉘어 있을 것.

머블로에서 기능 계층은 화면에 필요한 데이터를 확정하고, 스킨은 그 값을 어떤 구조로 보여줄지만 결정합니다. 스킨은 데이터베이스를 직접 조회하거나 값을 계산하고 권한을 판단하지 않습니다.

경계를 문서가 아니라 폴더로 그었다는 것이 이 글의 중심입니다.

어디까지가 스킨입니까

사이트의 헤더·푸터·레이아웃부터 로그인·마이페이지·검색 같은 기능 화면까지 스킨으로 나뉩니다. 게시판과 쇼핑몰 같은 패키지, FAQ·매뉴얼·팝업·설문 같은 플러그인의 화면도 각자의 스킨 폴더를 가집니다.

블록 하나하나도 스킨입니다.
이미지·메뉴·동영상·로그인 위젯은 같은 데이터를 서로 다른 구조로 보여줄 수 있고, 운영자는 블록을 놓을 때 그중 하나를 고릅니다.

사이트 한 벌을 통째로 바꾸는 일과 블록 하나의 표현을 더하는 일이 같은 구조 위에 있습니다. 운영자가 블록을 고르는 그 목록에, 페이지 전체를 만들지 않고 표현 하나만 만들어 더할 수 있습니다.

만드는 데 필요한 것

새 스킨은 기존 폴더를 복사하고 이름을 바꾸는 데서 시작합니다.
별도 등록 절차는 없습니다. 이미 정해진 스킨 위치에 폴더를 만들면 관리자의 선택 목록에 나타납니다.

블록 스킨은 출력 파일 하나로도 동작합니다. 보통 스타일 파일을 함께 두고, 목록에 보일 이름과 권장 열 수가 필요하면 작은 설정 파일을 더합니다.

게시판 스킨은 목록·본문·글쓰기·비밀번호 확인 네 화면과 스타일 파일로 한 벌을 이룹니다. 기본형 외에 갤러리형, 카드형, 홈 화면용 스킨도 같은 규약으로 들어 있습니다.

파일이 빠졌다고 사이트가 멈추지는 않습니다. 선택한 스킨에 파일이 없으면 기본 스킨의 같은 파일을 실행합니다. 로그인 화면 하나만 바꾸고 나머지를 기본값에 맡길 수도 있고, 프레임은 Head · Header · LayoutOpen · LayoutClose · Footer · Foot 가운데 필요한 파트만 바꿀 수 있습니다. 다만 게시판처럼 화면이 이어지는 스킨은 톤이 섞이지 않도록 한 벌을 완성하는 편이 좋습니다.

이 폴백이 지키는 것은 처음 만드는 수고보다 나중에 따라가야 할 목록입니다.
코어나 패키지에 새 화면이 생겨도 기존 커스텀 스킨은 기본 파일을 사용합니다. 바꾸지 않을 파일까지 복사해 소유할 이유가 없습니다.

무엇이 오는지는 계약으로 정해 둡니다

모든 프론트 스킨에는 $mublo 라는 예약 변수가 들어갑니다.
사이트 설정, 보는 사람, 요청 정보, 메뉴 트리, 테마, CSRF 토큰, 실행 환경이 같은 키 구조로 담깁니다. 캐시되는 블록과 미리보기에는 회원·요청·토큰 상태를 비운 형태가 전달됩니다.

이것은 편의를 위한 전역 변수가 아니라 버전이 붙은 계약입니다. 필수 섹션이 빠지면 예외가 나고, 컨트롤러나 확장이 mublo 키를 덮어쓰려 하면 그 자리에서 막힙니다.

외부 제작 대상으로 먼저 정리한 게시판 스킨에는 화면별 데이터와 URL, 폼 전송 규칙을 적은 계약 문서가 있습니다. 같은 배포물에 AI 작업 지침과 검사기도 둡니다. 지침은 계약을 추측하지 않고 먼저 문서를 읽게 하며, 검사기는 빠진 파일과 잘못된 주소, 남은 CSS 규칙처럼 기계가 판정할 수 있는 문제를 찾습니다.

왜 기본 출력은 서버 완성 HTML입니까?

서버는 데이터만 내려주고 화면은 React나 Vue 같은 컴포넌트가 조립하게 만들 수도 있습니다. 상태가 많은 관리자 편집기에는 그 구조가 잘 맞고, 머블로도 그런 화면은 자바스크립트로 만듭니다.

현재 구조에는 반대급부가 있습니다.
머블로는 콘텐츠를 먼저 버퍼에 렌더하고, 스킨이 남긴 헤더·레이아웃 힌트를 읽은 뒤 바깥 프레임을 조립합니다. 콘텐츠를 두 번 실행하지는 않지만, 부모의 모양을 정하려고 자식을 먼저 실행하는 우회가 필요합니다.

여러 번 그쪽으로 방향을 틀 뻔했습니다.
몰라서 피한 것도, 해보지 않아서 고른 것도 아닙니다. 그럼에도 사이트의 기본 출력을 서버에 남긴 이유는 세 가지입니다.

첫째, 사람과 AI가 이미 아는 웹의 언어를 그대로 쓸 수 있습니다.
구조는 HTML, 모양은 CSS, 동작은 JavaScript로 만들고 값 출력과 반복에만 얇은 PHP 문법을 씁니다. 전용 템플릿 문법을 새로 익히거나 설명할 필요가 없습니다. 앞서 말한 작업 지침과 검사기도 이 전제 위에 있습니다 — 우리에게만 통하는 문법이었다면 사람에게든 AI에게든 설명부터 해야 했을 것입니다.

둘째, 제작과 배포에 빌드 단계가 없습니다.
파일을 올리면 화면이 바뀝니다. 저장소의 npm 의존성은 브라우저 테스트 도구 하나뿐이고, 스킨을 만들거나 배포하는 데는 별도 도구를 설치하지 않습니다. 파일 단위 폴백도 실행 중에 그대로 성립합니다.

셋째, 데이터와 실패의 경계를 서버가 기본으로 제공합니다.
$mublo 는 원본 세션이나 엔티티가 아니라 화면용 스냅샷입니다. 콘텐츠와 프레임 스킨은 자기 출력 버퍼 안에서 실행되고, 블록은 칸 단위로 격리됩니다. 한 조각이 실패해도 나머지 페이지는 계속 출력됩니다.

이것은 금지가 아닙니다. 스킨은 CSS와 JavaScript를 등록할 수 있고, 문서 전체를 직접 쓰거나 특정 화면에 React나 Vue를 올릴 수도 있습니다.
고정한 것은 아무것도 준비하지 않은 사람이 처음 만나는 화면은 서버가 완성한 HTML이라는 기본값입니다.

스킨이 할 수 없는 것

스킨은 새로운 기능을 만드는 도구가 아닙니다.
전달되지 않은 데이터나 새로운 권한·검색 규칙이 필요하다면 기능 쪽 계약부터 넓혀야 합니다. 정렬 파라미터가 없는데 버튼만 그리면 눌러도 동작하지 않는 화면이 생길 뿐입니다.

스킨에서 데이터베이스를 직접 조회하면 당장은 빠르지만, 그 순간 테이블 구조와 권한 정책까지 스킨의 책임이 됩니다. 스키마나 캐시 정책이 바뀔 때 함께 깨지는 파일은 더 이상 갈아 끼울 수 있는 표현 부품이 아닙니다.

스킨 이름은 최종적으로 파일 경로가 되므로 사용할 수 있는 글자를 제한하고, 저장할 때 실제 디렉터리를 확인합니다. 이상한 값이 남아 있으면 렌더 직전에 기본 스킨으로 닫습니다.

새 스킨을 만드는 데는 HTML과 CSS, 그리고 화면이 받는 값에 대한 이해가 필요합니다. 코드를 몰라도 무엇이든 만드는 도구가 아니라, 업무 로직 전체를 몰라도 표현에 참여할 수 있게 하는 경계입니다.

마음 놓고 고칠 수 있는 자리

사람이 적은 곳에서는 한 사람이 상품도 올리고 화면도 고치며 필요하면 개발까지 맡습니다. 역할을 나눈다는 말이 사람을 세 명 둔다는 뜻일 수는 없습니다.

화면에 무엇을 올릴지 고르는 일은 블록의 선택이고, 같은 데이터를 다른 구조로 그리는 일은 스킨의 변경이며, 없던 값과 규칙을 만드는 일은 기능의 개발입니다. 구조가 나뉘어 있으면 같은 사람도 필요한 깊이에서 멈출 수 있습니다.

썸네일을 옮기려고 조회 코드를 읽지 않아도 되는 것.
사이트 한 벌을 만들지 않아도 블록 하나의 모양을 배포할 수 있는 것.
새 화면이 추가돼도 바꾸지 않은 부분은 기본값으로 살아 있는 것.

표현과 로직을 나눈다는 말은 설계 원칙처럼 들립니다.
하지만 그 경계가 실제로 지키는 것은 처음 이 코드를 열어본 사람의 자신감입니다.

마음 놓고 고치려면, 먼저 마음 놓고 건드릴 수 있는 자리가 있어야 합니다.

글쓰기

댓글 0

등록된 댓글이 없습니다.