Skip to content
isdnetworks
Go back

두 곳에서 같은 모양이 나왔다

두 프로젝트에서 비슷한 문제가 났다. 한쪽은 주문 목록이 느리고 다른 쪽은 상품 목록이 느렸는데 코드는 서로 달랐다.

Table of contents

Open Table of contents

같은 모양의 두 사례

원인을 확인하니 형태가 같았는데 목록을 돌면서 행마다 관련 자료를 하나씩 조회하고 있었다.

foreach ($orders as $o) { $o->member = $this->memberRepo->find($o->member_no); }
foreach ($products as $p) { $p->category = $this->categoryRepo->find($p->category_no); }

둘 다 목록에서 관련 자료를 붙이는 코드이고 처음에는 자료가 적어 안 느렸다가 자료가 늘면서 느려졌다. 개별 실수가 아니라 그 상황에서 누구나 하게 되는 형태였다.

안 생긴 곳의 구조

같은 형태가 다른 프로젝트에도 있는지 전부 찾아봤더니 네 프로젝트 중 셋에 있었고 하나에는 없었다.

없는 프로젝트를 열어 보니 목록을 만드는 공통 코드를 쓰고 있었다. 관계를 미리 선언하고 한 번에 가져오는 구조라 행마다 조회하는 코드를 쓸 자리가 없었다. 안 생긴 것이 사람이 조심해서가 아니라 구조가 막고 있어서였다.

공통 코드와 정적 분석

그 공통 코드를 나머지 세 프로젝트에도 넣고 각각의 목록 코드를 그것을 쓰도록 바꿨다. 그리고 새로 생기는 것을 막으려고 정적 분석에 규칙을 넣었다.

'forbidden_patterns' => [
    '/foreach[^}]*->(find|first)\(/s' => '반복문 안 조회. ListBuilder 를 쓰십시오',
],

고치는 것과 다시 안 생기게 하는 것은 다른 작업이라 둘 다 했다. 고치기만 하고 끝내면 몇 달 뒤에 같은 것이 다시 나온다.

다른 공통 모양

이 참에 프로젝트 사이에 걸쳐 있는 다른 공통 형태도 함께 찾아봤다.

반복문 안 조회        4개 프로젝트 중 3
시간 제한 미설정      4개 중 4
로그에 개인정보       4개 중 2
설정 하드코딩         4개 중 3

외부 호출에 시간 제한을 안 거는 것은 네 프로젝트 전부에 있었다. 아무도 안 넣고 있었으므로 개인의 문제가 아니라 기본값의 문제였다. 시간 제한이 들어간 공통 클라이언트를 만들어 그것을 쓰게 했다.

정기 비교와 장치 부착 확인

한 번 비교하고 끝내지 않고 분기에 한 번씩 같은 검사를 전 프로젝트에 돌리게 했다. 그러다 한 프로젝트에서 시간 제한 없는 호출이 셋 늘어 있는 것을 발견했다.

정적 분석으로 막고 있다고 생각했는데 그 프로젝트에만 규칙이 안 붙어 있었다. 막는 장치를 만든 것과 그 장치가 전부에 붙어 있는 것은 별개라서 장치의 부착 여부 자체를 점검 대상에 넣어야 했다.

착수 시점의 목록

점검 목록이 생기고 나니 새 프로젝트를 시작할 때도 그 목록을 그대로 썼다. 정적 분석 규칙을 넣고 공통 클라이언트를 쓰게 하고 로그 마스킹을 설정하고 설정을 외부화하는 넷을 착수할 때 넣는다.

나중에 넣으면 이미 그 형태로 쓴 코드가 쌓여 있어서 고칠 것이 많아진다. 한 프로젝트에서 착수 때 안 넣고 두 달 뒤에 넣었더니 고칠 자리가 스물이 넘었다. 처음에 넣으면 그렇게 쓸 일 자체가 안 생긴다.

정리


Share this post on:

Previous Post
전수 검색으로 확정했다
Next Post
전부를 멈추는 한 건