목업은 늘 친절했다 - 반도체 제조 시스템 6~7월 회고
목차 보기
시리즈 목차 보기1 / 1
회사
1 / 1
- 목업은 늘 친절했다 - 반도체 제조 시스템 6~7월 회고
6월부터 7월 20일까지 내가 남긴 커밋을 세어보니 127개였다. 프론트엔드 110개, 애플리케이션 서버 10개, 웹 API 7개. 숫자만 보면 열심히 산 것 같은데 커밋 제목을 차례로 읽으면 조금 다른 그림이 나온다.
feat 사이에 fix가 끼어 있고, 그 fix 뒤에는 더 구체적인 fix가 붙어 있었다. 화면을 만들고, 실제 데이터를 연결하고, 연결하고 나서야 보이는 문제를 고쳤다. 두 달 동안 한 일은 새 기능 127개가 아니라 가정을 하나씩 현실에 맞춰 고치는 일이었다.
6월, 화면 하나가 데이터 모델을 데리고 왔다
6월 초에는 다국어와 엑셀부터 손댔다. 언어를 바꾸면 그리드 헤더도 함께 바뀌어야 했고, 내려받는 엑셀에도 같은 언어가 적용돼야 했다. 큰 기능은 아니지만 화면, API, 엑셀 파일이 서로 다른 말을 하면 사용자는 셋 중 하나를 믿지 못한다. 공통 import와 download helper를 만들고 서버에서는 대용량 엑셀을 스트리밍하도록 바꿨다.
곧 기준정보 화면 작업이 이어졌다. 서버가 내려주는 폼 설정으로 상세 패널을 만들고, 제품·자재·설비 화면에 공통 패턴을 붙였다. 처음에는 폼 하나 추가하는 일로 보였다. 실제로는 값의 타입 변환, 숫자 입력, 다국어 섹션 제목, 기존 행의 PK 잠금까지 따라왔다. 화면은 네모난데 요구사항은 자꾸 옆으로 자랐다.
설비 이미지는 더했다. 이미지를 보여주는 버튼 하나를 넣으려다 프론트의 미리보기, API 엔드포인트, CLOB 매핑, 저장 트랜잭션을 모두 만졌다. 버튼 클릭이 한 번 안 되면 프론트 문제처럼 보이지만, 저장이 안 되면 Oracle과 Java까지 내려가야 했다. 그 과정에서 USER라는 컬럼이 Oracle 예약어와 부딪혀 ORA-01747을 냈다. 사용자를 위한 시스템에서 USER를 지웠더니 저장이 됐다. 데이터베이스식 유머는 대체로 웃을 때가 아니라 해결하고 나서 웃긴다.
BOM은 표가 아니라 상태였다
6월 말에는 라인 BOM 설정을 맡았다. 조회하고 엑셀을 올려 정합성을 비교한 뒤 활성화하거나 비활성화하는 흐름이었다. 화면만 보면 탭이 여러 개 달린 큰 표다. 서버에서는 정의와 이력, 활성 상태와 작업 중 버전을 함께 다뤄야 했다.
여기서 KEEP_VERSION='Y'가 오래 남았다. 사용자가 비활성 버전을 초안으로 고칠 때 작업 중인 버전을 유지해야 했다. 저장 버튼은 하나인데 "저장"의 뜻이 상태마다 달랐다. 새 버전을 만들 것인지, 초안을 덮을 것인지, 활성 버전을 보호할 것인지가 한 트랜잭션 안에서 갈렸다. CRUD라는 말이 갑자기 지나치게 낙관적으로 들렸다.
프론트도 얌전하지 않았다. v-show가 빠져 탭 일곱 개가 한꺼번에 보였고, 숨겨진 탭의 그리드는 자기 폭을 아주 작게 계산했다. 하나를 숨기면 다른 하나가 쪼그라들었다. 나중에는 상하 패널을 드래그해 크기를 바꾸게 만들었는데, 공용 리사이즈 컴포넌트를 고치자 다른 화면까지 따라 움직였다. 결국 특정 화면의 동작 범위를 따로 격리했다. 공용 컴포넌트는 재사용의 도구이면서 영향 범위를 넓히는 장치라는 사실을 몸으로 배웠다.
천 단위 쉼표가 합계를 망친 날
그리드 PoC도 만들었다. 소계와 총계, 드래그 영역 합계, 행·셀·컬럼 복사를 한 화면에서 시험했다. 기능을 붙일 때는 순조로웠다. 사용자가 1,000을 붙여넣기 전까지는.
사람에게 1,000은 천이지만 JavaScript에 먼저 들어온 값은 문자열이었다. 합계는 조용히 NaN이 됐다. 숫자를 정규화하는 로직을 고치고 편집, 붙여넣기, 합계 경로를 다시 확인했다. 화려한 그리드 기능보다 쉼표 하나를 제대로 읽는 일이 더 오래 남았다. 업무 시스템에서는 드래그 합계가 멋져도 최종 합계가 틀리면 그냥 틀린 시스템이다.
7월, 목업을 지우자 일이 시작됐다
6월 말부터 생산실적, Lot 이력, 작업지시 추적, 재고 현황 화면을 목업으로 만들었다. 목업은 친절하다. 필드가 빠지지 않고 null도 거의 없으며, 내가 예상한 순서로 데이터가 온다. 검색 조건을 넣으면 기다렸다는 듯 정답을 돌려준다.
7월에는 이 목업을 하나씩 지우고 실 DB 조회로 바꿨다. 이때부터 화면이 공장 용어를 제대로 묻기 시작했다. Area 조건은 몇 단계로 이어지는지, Lot에서 박스와 팔레트 이력을 어디까지 따라갈지, 재고를 어떤 상태와 단위로 나눌지 정해야 했다. 목업 파일 수백 줄을 삭제했는데 코드는 줄어도 확인할 것은 늘었다. 삭제 줄이 많은 커밋이 꼭 쉬운 커밋은 아니었다.
수리 요청과 완료, 수리 대기 현황도 이 시기에 붙였다. 검색 조건 하나를 필수로 바꾸고, Lot 스캔 필터를 실제로 먹게 만들고, 투입 자재와 수리 이력을 탭으로 나눴다. 하단 그리드 높이를 두 번 고친 커밋도 있다. 첫 번째는 더 넓게, 두 번째는 남은 공간만큼. CSS는 가끔 비즈니스 로직보다 더 정직해서, 틀리면 즉시 화면 전체로 항의한다.
SELECT만 허용하는 콘솔
중간에는 브라우저에서 조회 쿼리를 실행하는 콘솔도 만들었다. 프론트에는 바인드 값 입력, 결과 그리드, 집계와 복사를 넣었다. 서버에는 SELECT 검증기와 실행 API, 로그, 페이지네이션을 붙였다. 결과가 많을 때는 서버 페이지네이션과 무한 스크롤로 이어지게 했다.
쿼리 콘솔은 편하지만 편한 만큼 위험하다. "실행된다"보다 "무엇을 실행하지 못하게 할 것인가"를 먼저 정해야 했다. UI 한 장을 추가하는 일인데 파싱과 검증, 로그, 응답 크기까지 함께 봐야 했다. 이 작업 뒤로 관리자 도구를 볼 때 버튼보다 경계부터 보게 됐다.
두 달 뒤에 남은 것
두 달 동안 가장 많이 바뀐 건 코드를 쓰는 속도가 아니었다. 화면 이름과 테이블 이름을 외우는 데서 시작해, 어느 상태를 누가 바꾸고 다음 공정이 무엇을 믿는지 묻게 됐다. 반도체 제조 시스템은 화면들의 모음이 아니었다. 작업지시, Lot, BOM, 설비, 품질, 수리, 재고가 서로의 상태를 이어받는 긴 약속에 가까웠다.
힘든 순간은 대개 작은 불일치에서 시작했다. 예약어 하나, 쉼표 하나, 빠진 페이지 파일 하나, 공용 리사이즈 옵션 하나. 반대로 재미도 거기에 있었다. 원인을 찾고 나면 서로 무관해 보이던 프론트와 API, 트랜잭션, DB 스키마가 한 줄로 이어졌다.
127이라는 숫자는 곧 잊힐 것 같다. 대신 목업은 늘 친절하고 실데이터는 늘 할 말이 많다는 사실, 저장 버튼 하나에도 여러 상태의 이해관계가 들어 있다는 사실은 오래 남을 것이다. 다음에는 커밋 수를 세기 전에 이 약속들을 먼저 더 잘 그려보고 싶다. 가능하면 합계가 NaN이 되기 전에.