본문 바로가기

Technology

개발자들의 영원한 숙제, 'NULL' 이야기

웹뿐만 아니라 애플리케이션, 데이터베이스 등 대부분의 개발에서 중요하게 맞닥뜨리게 되는 것이 바로 'NULL'이라는 개념입니다. 'NULL'이란 아무것도 없음을 의미하는 단어이며, 0이나 " "와 같은 공백과는 다른 개념입니다. 

프로그래밍을 접하지 않으신 분들이라면 쉽게 와 닿지 않을 텐데요. 그런 분들을 위해 개발에 있어서 'NULL'이 어떤 의미를 가지는지 알아보려고 합니다. 





NULL이란?


NULL이 '영원한 숙제'인 것은 아마도 많은 개발자들이 NULL을 마주하는 경우가 주로 프로그래밍 중에 에러 메시지로 고생할 때이기 때문이라고 생각합니다. 이 개념을 만들어낸 당사자도 '몇십 억짜리 실수'라고 이야기할 정도로, 프로그래밍을 하면서 많은 예외 상황을 만들어 냅니다.


프로그래밍 언어인 C언어에서는 생성된 메모리의 주소를 '포인터'라는 것이 가리키게 되어 포인터를 통해 데이터를 가져올 수 있게 됩니다. 이때 포인터가 아무것도 가리키고 있지 않다는 것을 나타내기 위해 NULL이라는 개념을 사용하게 되는 것입니다. 따라서 메모리에 0이나 " "와 같은 공백이 존재하여 포인터를 통해 값을 가져와 연산 등에 활용될 수 있는 반면에, NULL은 포인터가 가져올 값이 없는 상태를 말하므로 그 활용에 제약이 큽니다.  





데이터베이스의 경우에서도 마찬가지로 값이 존재하지 않음을 나타내는 데 사용되며 그 값을 'NULL값'이라고 합니다. Oracle, Mysql과 같이 데이터베이스를 처리하는 벤더마다 NULL값을 처리하는 방식이 구체적으로 다르지만, 기본적으로 '아직 입력되지 않은 값' 또는 '알 수 없는 값'을 의미합니다. 결국 '존재하지 않는 값'이므로 SQL(구조적 질의 언어)을 이용한 다양한 연산에서도 제약을 받게 됩니다. 

대중적으로 쓰이고 있는 Oracle 데이터베이스의 경우로 제약에 관한 예를 들어보겠습니다. 사칙 연산( +, -, *, / )의 경우입니다. 흔히 'NULL값에 3을 더하면 아무것도 없는 것에서 3을 더하니까 3이겠지'라고 생각하실 수 있지만, 결과는 NULL입니다. 이것은 숫자의 형태가 아닌 어떤 것과 연산을 시도하려는 논리적 오류에서 발생하는 것입니다. 





이해를 돕기 위해 간단하게 예를 들어보자면 통장의 잔액이 0원인 상태가 0의 개념이라면, 통장 자체를 개설하지 않아 계좌번호가 없는 (또는 계좌번호를 모르는) 것이 NULL값의 개념인 것입니다. 계좌번호가 없는 상태에서 돈을 입금하는 것은 말이 안 되겠죠?

사칙연산과 관련하여 좀 더 깊게 들어가면, Sum(선택한 모든 값을 더해주는 함수)과 같은 집계 함수에서는 경우가 다릅니다. NULL값이 포함되어 있어도 이를 제외하고 계산이 가능한데, 이는 데이터베이스 관리 시스템을 만든 곳에서 사용자를 배려한 처사가 아닐까 합니다. 

데이터베이스를 사용하는 사용자는 입력된 데이터를 가지고 효과적으로 원하는 정보를 출력해내는 것을 원할 것입니다. 수많은 레코드 중에서 극히 일부 레코드 값이 NULL값이라고 해서 집계 처리 결과를 무조건 NULL로 리턴한다면, 이로 인해 다양한 경우에서 제약을 받을 것입니다.



영원한 숙제


위에서 말한 이러한 규칙들이 다른 데이터베이스에서도 동일하게 적용되는 것은 아닙니다. 다양한 상황에 따라서 NULL규칙이 일관적이지 않은 부분도 개발자를 힘들게 하지만, 각각의 데이터베이스 종류별로 NULL에 대해 상이한 규칙을 갖는 것도 개발자를 힘들게 합니다. 

C언어에서는 NULL로 인해 'Null Pointer Dereference'가 발생합니다. 





일반적으로 Null Pointer Dereference가 발생하면 실행 중인 프로그램이 종료됩니다. 또한 보안적으로 취약해질 수 있습니다. 공격자가 의도적으로 이러한 Null Pointer Dereference를 실행하는 경우, 그 결과 발생하는 예외 사항을 추후 공격을 계획하는 데 악용할 수 있기 때문입니다.

이를 막기 위해서는 특별한 방법은 없습니다. 코드를 작성할 때 미리 이러한 경우를 계산하여 작성하거나, Null 포인터 체크를 통하여 프로그램이 실행 중에 중단되는 경우가 없도록 하는 것입니다. 하지만 실제 업무에서는 몇백 또는 몇천 줄 그 이상의 코드를 일일이 체크하기란 쉬운 일이 아닙니다. 이렇게 개발자의 야근은 늘어나는 것일까요? 



현명한 개발자의 해결책


야근을 피하고 효율적으로 개발하는 현명한 개발자가 되기 위하여 어떤 방법을 사용해야 할까요? 


1. 정적분석도구의 사용  

우선 정적 분석 도구(Static Code Analysis Tool)를 사용하는 것입니다. 정적 분석은 컴퓨터 소프트웨어를 분석하는 방법 가운데 하나로, 그 소프트웨어로부터 만들어진 프로그램을 실제로 실행해보지 않고 분석하는 방법입니다. 분석된 정보를 이용하는 것뿐만 아니라 있음 직한 코딩 에러를 표시해주는 것, 프로그램이 어떤 속성을 만족하는지 수학적으로 증명하는 것까지 다양합니다.    



 사진출처: Wisedog's Lifelog



2. 안드로이드 대안 언어 '코틀린'

코틀린이라는 안드로이드 개발 언어는 제트브레인이 2011년 만든 언어입니다. 문법적으로 C언어와 비슷한 자바와 호환이 되는 장점이 있으며, 이와 더불어 자바보다 문법 자체가 간결하여 유지보수를 조금 더 편하게 할 수 있고 다양하게 표현을 확장할 수 있습니다. 





C와 마찬가지로 자바에서도 NULL과 관련한 예외 상황이 NullPointerException이라는 이름으로 발생합니다. 하지만 코틀리는 NULL값을 코드에서 없애는 것을 지향하여, 결과적으로 프로그램이 실행 중에 예외 상황을 만나 중단되는 위험을 줄여주며 안정성을 높여줍니다.


다양한 프로그램 분석 방법과 NULL을 지양하는 대체 언어를 선택하는 것들은 모두 좋은 대안이 될 수 있지만, 최선의 방법은 개발자들이 NULL에 대해 완벽하게 이해하고 사용하는 것이라는 사실에는 변함이 없습니다. 

개인적으로는 반드시 NULL을 쓸 필요가 없고 NULL을 허용할 필요가 없다고 생각합니다. 무식하지만 우직하게 개발을 해 나가는 방법이 있습니다. 데이터베이스에는 데이터를 입력할 때 'NOT NULL'이라는 조건을 두어 무조건 NULL값을 허용하지 않을 수 있으며, 따라서 NULL을 허용했을 때 생기는 문제점을 미리 방지할 수 있습니다. C나 Java같은 언어를 사용함에도, 0과 공백을 활용하여 값이 없음을 개발자 스스로 인식하지만, 포인터가 데이터가 있음을 인지하게 하는 방법도 있습니다.   

이러한 방법들은 개발의 배경이 되는 상황, 개발 관련 요구사항, 개발자의 의도에 따라서 개발자 스스로가 선택해서 사용해야 합니다. 그리고 개발자가 NULL에 휩쓸려 급급하게 에러를 수정하며 따라가는 것이 아니라, 주도적으로 NULL을 이용해 나간다면 좀 더 효율적인 프로그래밍을 할 수 있을 것입니다. 

지피지기면 백전백승!


by 수달 발자국

출처: 위키백과, 아이티데일리디비가이드넷, 블로터, Javarevisited