2016년 10월 2일 일요일

JSON 에 대한 간략한 생각

제목이 좀 애매한데...그냥 개인적으로JSON 데이터 구조를 설계하는데 조심해야 할 한가지(어떻게 보면 프로그래밍에서의 설계 방식에 대한 기본 중 하나가 아닐까 하지만)에 대한 잡설입니다.


지금은 아주 약간 시간이 지났지만, JSON 에서 데이터를 만드는 부분에 있어 어떤 사람과 논쟁이 발생한 적이 있었습니다. 저는 중간에 그냥 대화가 힘들 것을 직감하고 대화를 끊었지만, 그 이후에도 다른 사람과 계속 논쟁을 이어 가더군요. 좋은 의미의 논쟁이었으면 좋았겠지만 좀 어거지 수준의 대화도 일부 있어서...그냥 눈팅하면서도 좀 짜증이 나더군요.

논쟁이 일어난 계기는 질문자가 아래와 같은 늬앙스의 질문을 했기 때문입니다.

JSON 으로 웹의 그리드에 표시할 데이터 목록을 보내려고 하는데, 생성할 때의 키 순서와 달리 실제 String 으로 변환되어 나온 JSON 에서는 생성한 순서처럼 내용이 생성되어 있지 않다. 방법이 없을까?

그리고 질문자가 올린 것을 보니, JSON Object 에 key 로 "A", "B", "C" 와 같이 순서를 위해 특정값을 넣고, 뒤에 해당 줄에 표시할 내용을 value 로 넣었더군요.

처음에 질문을 봤을 때 그냥 String 으로 직접 만들면 순서가 흐트러지지 않는다고 하려다가...이건 좀 아니다 싶어서 좀 더 원론적인 답변을 했습니다.

JSON Array 는 순서가 유지됩니다. 말씀하신 내용의 정보를 보낼 때에는 그냥 JSON Array 로 데이터를 보내시는게 맞습니다. 그렇게 내용을 변경해보세요. 받는 쪽에서도 순서가 뒤바뀌지 않기 때문에 이렇게 구조를 바꾸시는게 좋습니다.

그런데, 뒤에 어떤 사람이 Google 의 Gson 을 이용해서 입력된 순서...가 아닌, key 의 정렬을 유지한 채(key 정렬 순이 원 질문자의 의도가 맞긴 합니다)로 String 을 만들어내는 이야기 했습니다. 물론 받는 쪽은 Javascript 였으니 Gson 은 없겠지만 말입니다.

제가 이 사람의 댓글에 문제를 제기하면서 사태가 커졌습니다.

말씀하신 방법대로 정렬을 해서 보내는 방법도 좋지만, 그런 식으로 String 을 생성해도 받는 쪽에서 순서를 유지하는 방법을 쓰지 않으면 다시 순서가 흐트러지기 때문에 그런 방법은 좋지 않습니다.

이런 늬앙스였습니다.

그 사람은 질문 내용 그 자체에 대한 답변에만 충실하면 되지 않느냐, 이렇게 하면 정렬된 문자열이 나오는데 무슨 문제냐...등...반발을 심하게 했죠.

그래서, 여기에 대해서 이야기를 하려고 합니다.



먼저 JSON 의 특성 중 일부를 짚고 넘어가야 겠네요.

JSON 은 Obejct 라고 불리는 구조로 이루어져야 합니다. Object 는 key 와 value 로 이루어져 있는 단순한 집합이고, 각 key/value 쌍은 콤마로 구분되어 여러 개가 저장될 수 있습니다. 그리고 "key 는 순서가 유지되지 않습니다".
이 Object 는 String 으로 된 key 와 여러 형태의 value 을 가질 수 있는데, 숫자형(double), 문자형(String), 참/거짓(Boolean) 뿐만 아니라 null 이나 JSON Object, JSON Array 같은 구조도 가질 수 있습니다. 여기서 JSON Array 는 흔히 말하는 배열과 같은 형태 같지만, 사실 각 값들은 여러 자료형이 섞여서 들어갈 수 있기 때문에 Java 의 Object[] 나 List 에 가깝다고 이해하는게 맞습니다. List<Object> 라고 할까요.
어쨌든 표준 JSON 문장은 이런 특징 때문에 Java 라이브러리에서는 통상적으로 JSON Object 는 HashMap 으로, JSON Array 는 ArrayList 로 대응되어 구현되고 JSON String 을 Java Bean 개체와 마샬링/언마샬링 할 때에 자동으로 HashMap 과 ArrayList 로 변환되어 저장되는 경우가 대부분입니다(대부분이 이유가 JSON 을 다루는 라이브러리는 하나가 아니니까요).

그리고, JSON 은 Javascript 에서 이용되기 위해 처음 고안된 방법이다 보니 Javascript 에서 아무런 추가 라이브러리 없이 바로 처리가 가능합니다. 그리고 Javascript 에서는 key 순서를 애초에 보장하지 않기 때문에 String 으로 정렬된 형태로 받는다고 해도 결국 순서대로 Object 의 key 들을 가져오지 못합니다. 정렬의 개념도 내부적으로 없구요. 그렇기 때문에 JSON Object 의 키는 언제든 순서에 상관없이 빠르게 처리할 수 있는 형태대로 내부에서 저장하고 있다고 이해한 상태에서 개발해야지, 이를 순서대로 뽑아낼 것이라고 생각하고 프로그래밍 하는 것은 의미가 없습니다.

문제는, 질문자의 경우 "A", "B", "C" 와 같이 순서대로 key 을 정렬하여 String 을 저장한 뒤 받는 쪽에서 역시나 순서대로 하나씩 꺼낼 생각을 하고 있겠지만...이건 양 쪽 모두 한 사람이 프로그래밍을 하거나 문서를 잘 만들어서 이후에도 받는 쪽에서 변함없이 이렇게 처리하도록 프로그램을 유지해야 가능한 방법입니다. 예전 제 글(http://zepinos.blogspot.kr/2016/09/mybatisibatis-oralce-sequence.html)에서도 말한 적이 있지만 프로그램을 영원히 혼자서 만드는 경우가 아니라면 가급적 표준을 지키고, 문제가 발생할 가능성이 최대한 적은 쪽으로 프로그래밍을 하는 습관을 가지는게 중요합니다. 그런데 굳이 표준을 지키면서 개발할 수 있는걸 이렇게 엉뚱하게 프로그래밍을 하려고 하는 것도 그렇고(초보니까 이럴 수도 있죠), 그걸 알면서도 질문에 대한 답만 해야한다고 주장하는 것도...좀 질 나빠 보이는건 어쩔 수 없더군요.

그리고, 보통 이런 리스트를 DB 에서 가져올 때 List 개체에 담아서 가져오기 때문에 이걸 그냥 Map.put("키", List) 와 같이 담고 JSON String 으로만 변환하면 자동으로 "키" 에 JSON Array 형태로 JSON Object 들이 순서대로 담겨져 들어가있을 것입니다. 너무나 쉽고 for 을 써가면서 "A", "B", "C" 와 같이 키를 만들 필요도 없고(당연히 사용자가 매우 많아지면 서버 측의 속도 저하가 필연적으로 따라옵니다), List 의 개수가 가변적일 경우 대응하기도 쉽습니다(사실상 코드를 고칠 필요가 없습니다). 받는 쪽에서도 어떤 라이브러리를 이용하든 Array 형태의 데이터는 순서가 바뀌지도 않구요.

실제로 많은 Javascript grid 라이브러리들은 데이터를 JSON 으로 동적으로 가져올 때 JSON Array 형태로 값을 요구합니다. 그렇기 때문에, 이러한 방법은 매우 보편적인 방법이라고 할 수 있습니다. 만약, 어떤 라이브러리에서 리스트 형태의 데이터를 binding 할 때 Array 형태가 아닌 key 의 정렬 순서대로 값을 Object 에서 가져오도록 되어 있을 때...과연 이 라이브러리가 잘 짜여진 프로그램이라고 생각할 수 있을까요? 저라면...이런 라이브러리는 안쓸 것 같은데요...



특히 JSON 은 주석을 달 수 없기 때문에 데이터만 가지고 그 정보의 내용을 유추해야 하는 경우도 많고, 문서가 없을 경우 자신만의 독특한 구조로 데이터를 구성한다면 협업하는 입장에서 피해야할 개발자로 낙인 찍히기 쉽습니다. 이 점 유념했으면 좋겠습니다.
그런 의미에서, YAML 을 주목하고 있습니다. Spring Boot 의 기본 설정 파일 형식 중 하나로 이용되고 있는데, parsing 속도가 아직은 매우 느리다고 합니다만, 주석도 담을 수 있고, 계층 구조와 List 등도 모두 지원하기 때문에 JSON 을 대체하는 좋은 방법이 될 수 있을꺼란 기대가 있습니다.




마지막으로, 이 때의 일을 소회하자면...끝까지 이 내용 가지고 질질 끌면서 어거지 쓰면서 새 글까지 써대면서 질문자의 글에 대한 내용만 답변해야 하는거 아니냐고 동조자를 모으는 모습을 보이던데...중간에 빨리 발 빼길 잘했다는 생각이 들었습니다. 저와는 맞지 않는 사람이란 걸 느꼈습니다. 저와의 이 일이 있기 전에 더 큰 일이 있고, 상대방과 코드까지 공개하면서 논쟁을 벌였는데...상대방이 반말을 막 하는 모습 때문에 상대방을 안좋게 보았는데...그 때도 말꼬리 잡는 것 때문에 상대방이 좀 짜증은 났겠다는 생각이 들었습니다. 말꼬리라고 하는 것도...숲은 안보고 나무만 집요하게 들이밀면서 상대의 말실수를 가지고 끝까지 공격하는 모습은 좋지 않게 보였는데...저도 당하고 보니 다시는 상대하고 싶지 않은 사람이더군요. 그래서 내린 결론이..."절대 대응하지 않는다", "없는 사람으로 대응한다" 입니다. 이 글도 여기 쓰는 목적이고...

혹시 그 당사자가 이 글 봤다면 개인 블로그에 혼자 떠드시길 바랍니다. 해당 커뮤니티에선 제 이미지 관리(?) 차원 뿐만 아니라 공공성이 있는 곳에서 분탕치기 싫어서 조용히 있었던 거지, 당신의 내용에 동의하거나 납득하기에 그만하는게 아니라는거...알길 바랍니다. 벼로써 키는 충분히 자라기는 했는데 아직 고개를 숙이는 단계까지 가질 않은 것 같아서 이해는 하긴 합니다만, 나중에 이불킥 할 일 늘리지 마세요.