시스템에서 데이터는 다양한 경로를 통해서 내외부로 흘러들어가며, 이는 해당 데이터를 처리하는 코드의 견고성과 건전성을 해치는 원인되기도 합니다. 특히, AS-IS 시스템을 TO-BE 시스템으로 전환하는데 있어서 데이터 마이그레이션과 같은 작업은 적게는 수백개에서 많게는 수천개에 달하는 테이블의 매핑으로 인해서 수많은 오류 데이터를 낳게 됩니다. 이는 AS-IS와 TO-BE의 매핑이 그리 간단하고 쉬운일이 아니기 때문에 발생할 수 있는 오류들 중에 가장 큰 비중을 차지하고 합니다.
일반적으로 어느 특정 경로를 통해서 입력과 출력의 대상이 되는 데이터를 처리하는 코드는 정해진 비즈니스 규칙에 의해서만 동작하도록 만들어져 있기 때문에 이와 같이 다른 경로를 통해서 입력/출력되는 데이터에 대한 오류에 대해서는 대부분이 에러나 오작동을 하게 만드는 원인이 되기도 합니다. 즉, 데이터의 경로를 통제하고 해당 데이터 값을 무결화시키는 작업이 이러한 에러나 오작동을 최소화시키는 일이지만, 요새와 같이 다양한 접점을 통해서 들어오는 데이터 흐름 경로들은 코드의 견고성과 건전성에 심각한 위험이 되는게 사실입니다.
이를 위해서는 코드가 나름대로 자기 자신을 지키기 위한 수단으로 방어적인 코드를 가지고 있을 필요가 있으며, 그 방어적인 수단은 다양한 형태로 코드에서 표현될 수 있습니다.
1. 정합성 강화
데이터는 조회와 입력은 연산을 처리하기 전에 데이터의 올바름을 검증하기 위한 정합성 로직을 필요로 합니다. 통상 입출력 경로가 어느 특정 코드에서만 처리될 수 있도록 정해진 경우에는 이러한 정합성에 대한 강도가 그리 크지 않아도 크게 문제가 되지는 않습니다. 예를 들어, 웹 화면에서 넘어오는 데이터들은 어느 정도 UI에서 데이터의 정합성 수준을 맞추어주기 때문에 서버에서는 이에 대한 정합성이 크게 필요하지 않을 수도 있습니다. 또한, 이러한 경로를 통해서 들어와서 테이블 상에 저장되는 데이터들 역시 이를 다시 조회했을 때에 그 값들에 대한 의미에 대해 크게 의심할 부분이 없을 것입니다.
하지만, 테이블 상에 놓여있는 데이터가 이와 같은 특정 코드를 통해서 만들어진 것이 아니라, 다른 접점의 코드나 데이터 마이그레이션과 같은 처리로 테이블에 놓여있다고 가정한다면, 해당 데이터를 조회하는 시점부터 그 값들의 정확성을 검증해야 할 것입니다.
예를 들어, 남녀의 구분을 '1'과 '2'로 표현하는 데이터가 있다고 한다면, 정해진 경로를 통해서 들어오는 데이터에 대해서는 해당 값이 있는지만을 점검하기만 하면 될 수도 있을 겁니다. 하지만, 다른 경로를 통해서 들어온 이 값에 대해서는 실제 '1'혹은 '2' 값이 있는지, 그리고, 남자일때('1') 필요한 값들이 모두 충족하는지와 같은 별도의 정합성을 강화시키는 코드를 필요로 할 것입니다. 이는 비즈니스 로직의 재사용하고도 관련이 있는데, 동일 데이터를 처리하는 비즈니스 로직이 분산되면 될수록 이러한 데이터에 대한 정합성 강화와 같은 방어적인 프로그래밍은 추후 발생될 수 있는 오류를 사전에 방지해줄 수 있습니다.
2. 오퍼레이션의 시그너처의 세분화
오퍼레이션은 그 기능에 따라서 범용성의 정도를 표현해볼 수 있습니다. 동일 패턴으로 인한 코드 중복을 피하기 위해서 다소 범용적인 형태로 프로그래밍을 하는 경우도 있습니다. 즉, 입출력 파라미터들이 Collection 유형이거나, Object와 같은 유형으로 시그너처를 만드는 경우에, 그 내부에서는 다양한 경로의 비즈니스 로직들을 단순화시켜(혹은 추상화시켜) 처리하는 경우들이 있습니다. 이러한 경우에는 오류가 있는 데이터에 대한 일반적인 처리를 불가능하게 하거나 기존 코드를 더 복잡하게 만들 우려가 있기 때문에 오류가 발생할 수 있는 경우에 따라서 오퍼레이션을 더 세분화시켜 명확한 오류 지점이나 값을 빨리 찾을 수 있게 해야 합니다. 하지만, 너무 세분화시키거나 분리된 오퍼레이션들은 결국 유지보수를 어렵게 만들거나 동일 비즈니스 로직의 분산의 결과를 초래하기 때문에 유의할 필요는 있습니다. 다만 너무 보편화/일반화시킨 오퍼레이션은 이러한 오류 데이터의 대응을 더 힘들게 만들 수도 있습니다.
3. 구간별/유형별 테스트 방법 강화
데이터 흐름의 경로의 다양화는 테스트 유형의 다양화로 나타날 수 있습니다. 즉, 데이터 흐름을 통제할 수 있는 수준으로 최소화시키는 것이 테스트 유형을 최소화시키는 방법일 것입니다. 코드를 최대한 건전하고 견고성있게 유지하기 위해서는 결국 테스트로 검증을 할 수 밖에 없으며, 이는 비즈니스 로직을 개발하는 개발자에게 상당한 부담이 될 수 밖에는 없을 것입니다. 다양한 유형의 테스트를 통해서 발생할 수 있는 오류를 사전에 점검해보고, 이를 다시 코드에 반영하는 노력은 단순한 경우에는 그리 부담이 되지 않을 수도 있겠지만, 다양한 데이터 흐름의 경로를 가지는 시스템에서는 어느 한 사람의 노력보다 더 많은 사람들의 노력을 필요로 하며, 이는 전체적인 관점에서 검증의 방법을 만들어야 합니다.
예를 들어, 데이터 마이그레이션을 통해서 입력된 데이터들은 온라인에서 실행되는 코드를 통해서 다시 조회해서 비즈니스 로직을 처리하도록 테스트를 만들어야 하며, 그에 대한 결과를 다시 데이터 마이그레이션 코드에 적용해야 합니다. 일반적으로 이 두개의 로직을 처리하는 팀이 구분되어 있고, 서로 다른 영역에서 작업을 하기 때문에 이러한 부분은 특정 한팀이나 개인이 처리하기에는 어렵습니다.
방어적 프로그래밍은 결국 해당 비즈니스 로직을 담는 코드를 최대한 단일화시킨다고 해서 해결될 수 있는 문제는 아닙니다. 그러한 경우, 해당 코드는 상당히 복잡한 구조와 (원래를 요구사항에서 정의되어 있지는 않지만, 내부적인 요구에 의해서 새로 발생되는) 비즈니스 로직을 만들게 됩니다. 또한, 불필요한 코드를 만들어낼 수 있기 때문에 방어의 수준과 비즈니스 로직의 중복 분산의 수준을 적절하게 조정해야 합니다.
His Hand by h.koppdelaney |
일반적으로 어느 특정 경로를 통해서 입력과 출력의 대상이 되는 데이터를 처리하는 코드는 정해진 비즈니스 규칙에 의해서만 동작하도록 만들어져 있기 때문에 이와 같이 다른 경로를 통해서 입력/출력되는 데이터에 대한 오류에 대해서는 대부분이 에러나 오작동을 하게 만드는 원인이 되기도 합니다. 즉, 데이터의 경로를 통제하고 해당 데이터 값을 무결화시키는 작업이 이러한 에러나 오작동을 최소화시키는 일이지만, 요새와 같이 다양한 접점을 통해서 들어오는 데이터 흐름 경로들은 코드의 견고성과 건전성에 심각한 위험이 되는게 사실입니다.
이를 위해서는 코드가 나름대로 자기 자신을 지키기 위한 수단으로 방어적인 코드를 가지고 있을 필요가 있으며, 그 방어적인 수단은 다양한 형태로 코드에서 표현될 수 있습니다.
1. 정합성 강화
데이터는 조회와 입력은 연산을 처리하기 전에 데이터의 올바름을 검증하기 위한 정합성 로직을 필요로 합니다. 통상 입출력 경로가 어느 특정 코드에서만 처리될 수 있도록 정해진 경우에는 이러한 정합성에 대한 강도가 그리 크지 않아도 크게 문제가 되지는 않습니다. 예를 들어, 웹 화면에서 넘어오는 데이터들은 어느 정도 UI에서 데이터의 정합성 수준을 맞추어주기 때문에 서버에서는 이에 대한 정합성이 크게 필요하지 않을 수도 있습니다. 또한, 이러한 경로를 통해서 들어와서 테이블 상에 저장되는 데이터들 역시 이를 다시 조회했을 때에 그 값들에 대한 의미에 대해 크게 의심할 부분이 없을 것입니다.
하지만, 테이블 상에 놓여있는 데이터가 이와 같은 특정 코드를 통해서 만들어진 것이 아니라, 다른 접점의 코드나 데이터 마이그레이션과 같은 처리로 테이블에 놓여있다고 가정한다면, 해당 데이터를 조회하는 시점부터 그 값들의 정확성을 검증해야 할 것입니다.
예를 들어, 남녀의 구분을 '1'과 '2'로 표현하는 데이터가 있다고 한다면, 정해진 경로를 통해서 들어오는 데이터에 대해서는 해당 값이 있는지만을 점검하기만 하면 될 수도 있을 겁니다. 하지만, 다른 경로를 통해서 들어온 이 값에 대해서는 실제 '1'혹은 '2' 값이 있는지, 그리고, 남자일때('1') 필요한 값들이 모두 충족하는지와 같은 별도의 정합성을 강화시키는 코드를 필요로 할 것입니다. 이는 비즈니스 로직의 재사용하고도 관련이 있는데, 동일 데이터를 처리하는 비즈니스 로직이 분산되면 될수록 이러한 데이터에 대한 정합성 강화와 같은 방어적인 프로그래밍은 추후 발생될 수 있는 오류를 사전에 방지해줄 수 있습니다.
2. 오퍼레이션의 시그너처의 세분화
오퍼레이션은 그 기능에 따라서 범용성의 정도를 표현해볼 수 있습니다. 동일 패턴으로 인한 코드 중복을 피하기 위해서 다소 범용적인 형태로 프로그래밍을 하는 경우도 있습니다. 즉, 입출력 파라미터들이 Collection 유형이거나, Object와 같은 유형으로 시그너처를 만드는 경우에, 그 내부에서는 다양한 경로의 비즈니스 로직들을 단순화시켜(혹은 추상화시켜) 처리하는 경우들이 있습니다. 이러한 경우에는 오류가 있는 데이터에 대한 일반적인 처리를 불가능하게 하거나 기존 코드를 더 복잡하게 만들 우려가 있기 때문에 오류가 발생할 수 있는 경우에 따라서 오퍼레이션을 더 세분화시켜 명확한 오류 지점이나 값을 빨리 찾을 수 있게 해야 합니다. 하지만, 너무 세분화시키거나 분리된 오퍼레이션들은 결국 유지보수를 어렵게 만들거나 동일 비즈니스 로직의 분산의 결과를 초래하기 때문에 유의할 필요는 있습니다. 다만 너무 보편화/일반화시킨 오퍼레이션은 이러한 오류 데이터의 대응을 더 힘들게 만들 수도 있습니다.
3. 구간별/유형별 테스트 방법 강화
데이터 흐름의 경로의 다양화는 테스트 유형의 다양화로 나타날 수 있습니다. 즉, 데이터 흐름을 통제할 수 있는 수준으로 최소화시키는 것이 테스트 유형을 최소화시키는 방법일 것입니다. 코드를 최대한 건전하고 견고성있게 유지하기 위해서는 결국 테스트로 검증을 할 수 밖에 없으며, 이는 비즈니스 로직을 개발하는 개발자에게 상당한 부담이 될 수 밖에는 없을 것입니다. 다양한 유형의 테스트를 통해서 발생할 수 있는 오류를 사전에 점검해보고, 이를 다시 코드에 반영하는 노력은 단순한 경우에는 그리 부담이 되지 않을 수도 있겠지만, 다양한 데이터 흐름의 경로를 가지는 시스템에서는 어느 한 사람의 노력보다 더 많은 사람들의 노력을 필요로 하며, 이는 전체적인 관점에서 검증의 방법을 만들어야 합니다.
예를 들어, 데이터 마이그레이션을 통해서 입력된 데이터들은 온라인에서 실행되는 코드를 통해서 다시 조회해서 비즈니스 로직을 처리하도록 테스트를 만들어야 하며, 그에 대한 결과를 다시 데이터 마이그레이션 코드에 적용해야 합니다. 일반적으로 이 두개의 로직을 처리하는 팀이 구분되어 있고, 서로 다른 영역에서 작업을 하기 때문에 이러한 부분은 특정 한팀이나 개인이 처리하기에는 어렵습니다.
방어적 프로그래밍은 결국 해당 비즈니스 로직을 담는 코드를 최대한 단일화시킨다고 해서 해결될 수 있는 문제는 아닙니다. 그러한 경우, 해당 코드는 상당히 복잡한 구조와 (원래를 요구사항에서 정의되어 있지는 않지만, 내부적인 요구에 의해서 새로 발생되는) 비즈니스 로직을 만들게 됩니다. 또한, 불필요한 코드를 만들어낼 수 있기 때문에 방어의 수준과 비즈니스 로직의 중복 분산의 수준을 적절하게 조정해야 합니다.
반응형
'Homo Coding' 카테고리의 다른 글
데이터 양과 비즈니스 로직의 복잡도 (0) | 2012.01.19 |
---|---|
기준의 법칙 (0) | 2011.10.28 |
프로그래밍 초보자가 알아야 하는 9 + 1 가지 (1) | 2011.07.20 |
런타임 계열 예외와 checked 예외 (0) | 2011.05.07 |
예외에 대한 비용 (0) | 2011.04.28 |