Skip to content
isdnetworks
Go back

세 조건을 항상 같이 걸었다

(수정됨)

자료를 조회할 때 company_id와 deleted_at과 is_active 세 조건을 항상 같이 걸어야 했다. 한 곳에서 하나가 빠진 것을 발견하고 전체를 확인하기로 했다.

Table of contents

Open Table of contents

검증 — 흩어진 조회의 실태

해당 테이블을 조회하는 자리를 grep으로 세니 수십 곳이었고 하나씩 확인했다. 셋 다 있는 곳이 대부분이고 둘만 있는 곳이 넷이며 하나만 있는 곳이 하나였다.

company_id 조건이 빠진 곳이 가장 위험했는데 다른 회사 자료가 그대로 보이기 때문이다. 같이 걸려야 하는 조건이 흩어져 있으면 시간이 지나면서 하나씩 빠진다.

조치 — 자동으로 붙이는 구조

두 가지 방법이 있었는데 빠진 자리마다 조건을 손으로 넣는 것과 모델의 addGlobalScope로 전역으로 붙게 하는 것이다. 뒤쪽을 골랐다. 이유는 손으로 넣으면 다음에 새로 생기는 조회에서 또 빠져서다. 대신 조건이 붙는 것이 코드에 안 보여 원시 쿼리를 따로 챙겨야 하는 것을 감수했다. 그러면 조회하는 쪽은 나머지 조건만 추가하면 된다.

빼야 하는 경우는 Laravel 공식 문서대로 withoutGlobalScope에 스코프 이름을 명시해 빼게 해서 의도적으로 뺀 것이 코드에 드러나게 했다. 전역 범위는 모델을 거칠 때만 붙으므로 DB::select 원시 쿼리를 쓰는 몇 곳도 찾았고 그중 셋에 조건이 빠져 있었다. 남기는 원시 쿼리에는 왜 모델을 안 쓰는지를 주석으로 적고 조건을 직접 넣었다.

검증 — 빠지면 걸리는 시험

주요 경로를 돌면서 DB::listen으로 잡은 쿼리에 company_id 조건이 있는지 확인하는 시험을 만들었다. 새 화면이 생기면 그 목록에 넣게 했다.

다른 회사 자료가 보이는지도 상세와 목록 양쪽으로 시험했다. 처음 돌렸을 때 상세에서 실패했는데 조건이 빠진 자리였다. 목록만 시험했으면 상세의 누락은 안 걸렸을 것이다.

주의 — 지난 것을 확인하는 조건

조건이 빠져 있던 동안 실제로 다른 회사 자료가 나갔는지도 보려 했다. 접근 로그에 company_id가 없어서 확인할 수 없었다.

로그에 그 값을 넣게 고쳤고 그 뒤로는 같은 확인이 가능해졌다. 지난 것을 확인하려면 그때 로그에 그 값이 있었어야 하므로 사고 뒤에 넣는 것은 다음 사고를 위한 준비다.

결과 — 조건이 늘 때 드러난 값

나중에 조건이 하나 더 필요해졌다. 한 자리에 모아 뒀으므로 거기만 고쳤고 수십 곳은 손대지 않았다.

흩어져 있었으면 수십 곳에 넣어야 했고 그중 몇 곳은 빠뜨렸을 것이다. 모아 두는 값은 처음이 아니라 조건이 늘 때 나왔다.

전역으로 붙게 하면서 빼는 방법도 생겼는데 그것을 아무 데서나 쓸 수 있으면 다시 같은 문제가 된다. withoutGlobalScope를 쓸 수 있는 자리를 AdminRepository 하나로 모으고 거기서 권한을 확인하게 했다. grep해 보면 그 한 곳만 남으므로 다른 데서 쓰면 검토에서 걸린다.

정리


Share this post on:

Previous Post
컬렉션마다 다른 규칙
Next Post
상태 컬럼으로 센 잘못된 분류