Skip to content
isdnetworks
Go back

읽을 때 맞출지 쓸 때 갈릴지 정했다

(수정됨)

외부에서 받은 자료의 option_values 가 때로는 문자열이고 때로는 배열로 오고 있었다. 값이 하나면 문자열로 오고 여럿이면 배열로 오는 형태였다.

Table of contents

Open Table of contents

문제 — 쓸 때마다 가른 결과

배열로 가정하고 foreach 로 순회하면 문자열일 때 한 글자씩 도는데 오류는 안 나고 이상한 결과만 나왔다. 그래서 그 값을 쓰는 자리마다 is_array() 확인 줄을 하나씩 넣었다.

세어 보니 십여 곳이 됐고 그중 하나를 빠뜨려서 문제가 났다. 같은 조건을 여러 자리에 복제하면 빠뜨릴 자리도 그만큼 늘어난다.

해결 — 읽는 자리로 옮긴 정규화

두 가지 방법이 있었는데 쓰는 자리의 is_array() 를 빠짐없이 채우는 것과 응답을 받은 직후 ChannelResponse 에서 한 번 맞추는 것이다. 뒤쪽을 골랐다. 이유는 같은 조건을 여러 자리에 복제하면 빠뜨릴 자리도 그만큼 늘어서다. 대신 응답 원형을 쓰던 코드가 있으면 그것까지 바뀌는 것을 감수했다. 값을 배열로 바꾸는 toArray() 를 만들고 대상 필드들을 그 함수에 통과시킨다. PHP 매뉴얼대로 스칼라를 (array) 로 캐스팅하면 그 값 하나를 담은 배열이 되므로 문자열 하나는 그것으로 충분했다.

그 뒤로는 항상 배열이므로 쓰는 자리 십여 곳에서 확인 조건이 전부 사라졌다. 형태를 맞추는 자리를 앞으로 옮기니 그 뒤의 코드가 단순해졌다.

검증 — 어떤 형태가 오는지 세기

맞추려면 어떤 형태가 오는지를 알아야 해서 응답 표본의 gettype() 을 종류별로 세어 봤다. string 과 array 말고 NULL 도 상당수 섞여 있었다.

NULL 과 빈 문자열은 빈 배열로 맞췄다. NULL 은 PHP 매뉴얼대로 (array) 캐스팅만으로 빈 배열이 되지만 빈 문자열은 원소 하나짜리 배열이 되므로 따로 걸렀다. 그리고 예상에 없는 형태가 오면 Log::warning() 으로 남기게 했는데 며칠 뒤 integer 가 오는 경우가 나왔고 옵션 번호만 오는 케이스였다. 모르는 형태를 알리게 해 두었기 때문에 새 형태를 찾을 수 있었다.

주의 — 원본 보존과 정규화의 병행

어디서 맞출지를 정할 때 원본 형태를 잃는지가 쟁점으로 남았다. 받는 자리에서 맞추면 쓰는 쪽은 단순해지지만 원래 어떤 형태로 왔는지가 사라진다.

원본은 따로 로그에 남기고 맞춘 것을 쓰는 형태로 두 가지를 다 챙겼다. 원본이 필요하면 그것을 따로 남기고 쓰는 값은 맞춰서 쓰면 된다.

보내는 쪽과 저장분까지

받는 쪽만 문제가 아니었다. 우리가 보낼 때도 하나면 문자열로 보내고 있어서 받는 쪽이 같은 고생을 하고 있었을 것이므로 항상 배열로 보내게 바꾸고 상대에게 알렸다.

우리 데이터베이스에도 형태가 섞여 있었다. JSON 컬럼에 문자열과 배열과 NULL 이 섞여 저장돼 있어서 문자열은 배열로 감싸고 널은 빈 배열로 맞춘 뒤 넣는 자리에서 항상 배열로 넣게 했다. CHECK (JSON_TYPE(option_values) = 'ARRAY') 제약을 걸 수 있어서 걸어 두니 코드가 실수해도 안 들어갔다.

정리


Share this post on:

Previous Post
조사와 만드는 것을 단계로 나눴다
Next Post
인코딩된 식별자의 복원