‘할 수 있을까’에서 공개 가능한 크기로

운영자 블로그의 「1인 개발 할 수 있을까?」(2023년 12월 6일)에는 작은 시도를 지속하고 과정과 결과를 쌓아보려는 생각이 담겨 있습니다. 지금 쭈니박스는 여러 작은 프로젝트를 소개하고, 서비스의 실행 화면과 이곳의 제작 기록을 나눠 관리합니다.

이 글은 과거 글에 없던 성공담이나 수익을 덧붙이지 않습니다. ‘무엇부터 공개할 것인가’를 결정할 수 있도록, 가상의 도구 하나에 범위 결정 방법을 적용해 봅니다. 독자에게 필요한 결과와 운영할 수 있는 크기를 함께 적는 것이 핵심입니다.

1. 기능 이름보다 완료할 행동을 씁니다

예시로 여러 줄의 목록을 입력하면 중복 항목을 정리해 주는 작은 웹 도구를 기획한다고 가정합니다. ‘목록 관리 플랫폼 만들기’라고 적으면 회원, 폴더, 공유, 검색, 통계가 모두 필요해 보입니다. 대신 사용자가 끝내야 할 일을 이렇게 정할 수 있습니다.

사용자는 줄바꿈으로 구분된 목록을 넣고, 중복을 제거한 결과를 확인한 뒤 가져갈 수 있다.

이 문장에는 입력, 처리, 확인, 결과 가져가기라는 종료 지점이 있습니다. 화면을 여러 개 만들 필요는 없지만, 결과가 어떻게 달라졌는지 설명할 자리는 필요합니다. 예를 들어 앞뒤 공백을 없애는지, 대소문자를 같은 값으로 보는지, 원래 순서를 유지하는지를 먼저 결정합니다.

‘AI로 정리’처럼 구현 수단부터 정하면 간단한 문자열 처리에도 외부 API와 비용이 붙을 수 있습니다. 규칙만으로 해결되는 문제는 규칙을 먼저 정하고, 외부 서비스가 꼭 필요한지 나중에 판단합니다.

2. 기능을 뺄 때는 남는 책임도 적습니다

가상의 목록 정리 도구: 첫 버전의 선택
항목첫 버전이유와 다시 검토할 조건
입력·결과 비교포함무엇이 바뀌었는지 알아야 결과를 믿고 가져감
회원 가입제외계정 없이 행동을 완료할 수 있음. 기기 간 기록이 필요해지면 재검토
서버 저장제외저장이 핵심 요구가 아님. 협업·복구 요구가 생기면 재검토
처리 규칙 안내포함공백·대소문자·순서 기준이 없으면 결과를 해석하기 어려움
키보드 사용·작은 화면포함기본 동작에 접근하기 위한 조건
팀 공유와 통계보류첫 행동과 직접 관계없는 운영 부담

브라우저 처리만 한다면 그 사실을 코드와 네트워크 요청으로 확인한 뒤 안내합니다. ‘서버가 없으니 개인정보를 전혀 처리하지 않는다’고 단정하지 않습니다. 호스팅 요청, 외부 스크립트, 문의 방식은 별도로 확인해야 합니다. 이 표는 제안이지 실제 쭈니박스 서비스의 개인정보처리방침이 아닙니다.

범위를 줄인다는 것은 권한, 오류 안내, 접근성을 나중으로 미룬다는 뜻이 아닙니다. 없어도 사용자가 목적을 달성할 수 있는 부가 기능을 미루는 것입니다. 정적 사이트 접근성 점검은 작은 첫 버전에도 적용할 수 있습니다.

3. 정상 화면 하나 대신 상태 몇 개를 완성합니다

가상의 목록 도구는 다음 상태를 구분해야 합니다. ‘결과 없음’이라는 문장 하나로 모든 상황을 덮으면 사용자는 기다려야 할지 입력을 바꿔야 할지 알 수 없습니다.

  • 처음 들어옴: 입력 형식과 처리 규칙을 보여줍니다. 예시는 사용자의 실제 자료와 구분합니다.
  • 빈 입력: 무엇을 입력해야 하는지 설명합니다. 완료한 것처럼 결과 숫자를 만들지 않습니다.
  • 정상 결과: 처리 전후 항목과 달라진 내용을 확인할 수 있게 합니다.
  • 너무 큰 입력: 검증한 처리 범위를 넘으면 이유와 줄이는 방법을 알려줍니다. 한계 값은 실제 성능 검사로 정합니다.
  • 가져오기 실패: 복사 같은 보조 동작이 실패하더라도 결과를 선택하거나 다른 방식으로 가져갈 수 있게 합니다.

첫 시험은 개인 자료가 없는 가짜 목록으로 합니다. 중복, 공백 줄, 한글, 같은 글자의 대소문자, 줄 끝 차이를 넣고 예상 결과를 먼저 적습니다. 몇 명이 좋아했다는 반응보다 ‘내가 기대한 결과와 달랐던 입력’을 남기는 편이 다음 수정의 근거가 됩니다.

실습: ‘중복 제거’라는 한 문장을 여섯 입력으로 고정하기

앞의 가상 도구에서 가장 위험한 모호함은 화면 개수가 아니라 ‘같은 항목’의 정의입니다. Apple과 apple을 합쳐도 되는 상품 목록과, 구별해야 하는 코드 목록은 다릅니다. 그래서 이번 예제는 양끝 공백 제거 → 빈 줄 제외 → 정확히 같은 문자열만 제거 → 처음 나온 순서 유지로 결정합니다. 대소문자, 내부 공백, 유니코드 정규화는 자동으로 바꾸지 않습니다.

실제 사용자 자료가 아닌 독립 입력 — ↵는 줄바꿈
입력기대 결과고정한 결정
사과 ↵ 바나나 ↵ 사과사과, 바나나첫 등장 순서 유지
공백만 있는 줄과 빈 줄빈 목록빈 항목을 하나 남기지 않음
Apple ↵ apple두 항목 유지대소문자는 구별
A B ↵ A B두 항목 유지항목 안의 공백은 보존
같은 목록의 LF / CRLF / CR 줄 끝같은 결과줄 끝 차이만 정규화
가 ↵ 분해된 가두 항목 유지겉모양만 보고 자동 병합하지 않음

아래는 화면이나 저장 기능이 없는 처리 함수와 자체 검사입니다. Node.js가 설치된 환경에서 VS Code → File → New Text File에 붙여넣고 list-rules.mjs로 저장한 뒤 Terminal → New Terminal에서 해당 폴더의 node list-rules.mjs를 실행합니다. 기존 프로젝트 파일을 덮어쓰지 않습니다.

import assert from 'node:assert/strict';

function cleanList(text) {
  const lines = text.split(/\r\n|\r|\n/)
    .map(line => line.trim()).filter(Boolean);
  return [...new Set(lines)];
}

const cases = [
  [' 사과 \n바나나\n사과', ['사과', '바나나']],
  [' \n\t\n', []],
  ['Apple\napple', ['Apple', 'apple']],
  ['A B\nA  B', ['A B', 'A  B']],
  ['사과\r\n바나나\r사과\n바나나', ['사과', '바나나']],
  ['가\n\u1100\u1161', ['가', '\u1100\u1161']],
];
for (const [input, expected] of cases) {
  assert.deepEqual(cleanList(input), expected);
}
console.log('6 list-rule cases passed');

이 글의 예제 검증 결과는 6 list-rule cases passed입니다. 특히 마지막 검사는 ‘한글 지원’이라는 넓은 표현으로 놓치기 쉬운 경계입니다. 사람이 읽는 목록이라면 NFC 정규화를 넣는 편이 나을 수 있지만, 식별자를 다룬다면 원문 보존이 더 중요할 수 있습니다. 정규화를 넣기로 바꾸는 순간 마지막 예상 결과도 함께 고쳐야 합니다. 이는 오류 수정이 아니라 제품 규칙 변경입니다.

여섯 검사가 통과해도 아직 ‘앱 완성’은 아닙니다

함수는 결과를 만들 뿐 복사 버튼, 키보드 안내, 입력 한도, 저장 정책을 구현하지 않습니다. 큰 입력의 성능도 측정하지 않았으므로 ‘무제한 처리’라고 소개할 근거가 없습니다. 첫 공개 카드는 이제 추상적인 ‘중복 제거’ 대신 이 여섯 결과를 가리킬 수 있고, 화면 작업자는 무엇을 유지해야 하는지 알 수 있습니다. 기능을 줄이면서도 판단 기준은 더 구체적으로 만드는 방법입니다.

4. 다음 작업자에게 넘길 한 장을 작성합니다

대상: 목록의 중복을 정리하려는 사람
완료 행동: 입력 → 차이 확인 → 결과 가져가기
처리 규칙: 공백·대소문자·순서를 각각 명시
이번에 제외: 회원, 서버 저장, 팀 공유, 통계
필수 상태: 처음, 빈 입력, 정상, 한계 초과, 가져오기 실패
검증: 가짜 입력별 예상 결과 + 키보드 + 작은 화면
공개 조건: 내부 링크 정상, 규칙 안내와 실제 동작 일치
되돌리기: 이전 배포 버전과 이번 변경 범위 기록

이 카드에서 모르는 항목은 개발자가 임의로 정한 사실이 아니라 결정할 질문으로 남깁니다. 작업을 부탁할 때도 ‘이 앱을 완성해줘’보다 포함·제외·검증 범위를 같이 전달하면 변경 이유를 확인하기 쉽습니다.

첫 공개 뒤에는 사용자가 실제로 막힌 지점을 하나씩 기록합니다. 기기 간 저장이 반복해서 필요하다는 근거가 생겼다면 계정과 데이터 보관을 함께 설계하고, 단순히 만들 수 있다는 이유만으로 기능을 늘리지 않습니다. 서비스가 커질 때 저장소와 배포를 나눌 기준은 서비스 경계를 나눈 이유에서 다룹니다.