도서/기술

[책] 데이터 지향 프로그래밍 - 15장 디버깅

egg528 2025. 2. 9. 16:40

 로직을 작성했다면 내가 원하는대로 동작하는지 확인해보는 과정은 필수적이다. 이는 OOP이든 DOP이든 그 어떤 프로그래밍 패러다임에서도 마찬가지일 것이다. 하지만 DOP는 이 과정에서 누릴 수 있는 이점이 있다. DOP의 데이터는 불변이기 때문에 메서드의 인자가 결과값의 유일한 원인이라는 점이다. 즉, DOP에서는 메서드 인자와 그 결과값에 대한 확인으로 동작을 확인할 수 있게 된다.

 

 

 

컨텍스트 포착


 메서드 인자는 로깅을 통해서 확인이 가능하다. 메서드 도입부에 console.log()를 활용해 인자들을 출력하면 그만이다. 하지만 console에 출력되는 과정에서 데이터를 그대로 복붙해서 사용하기 어려운 형태로 바뀌는 경우가 있다. 예를 들면 문자열의 경우 상용을 위해서는 "string" 형태가 필요하지만 console에는 string이라고만 표현된다.

 

function hasWordStartingWith(sentence, prefix) {
    console.log(JSON.stringify(sentence));
    console.log(JSON.stringify(prefix));
    
    var words = sentence.split(" ");
    
    return _.find(words, function(word) {
        return word.startsWith(prefix);
    }) != null;
}

 이때 직렬화와 역직렬화를 사용하면 된다. 만약 위 메서드 인자로 sentence="안녕", prefix="안"이 들어왔다면 console에는 "안녕", "안"이 출력되어 복사하여 사용하기 용이해진다. 이런 방식은 DOP가 활용하는 범용 자료 구조와도 잘 맞는다. DOP는 복잡한 데이터가 모두 범용 자료 구조로 구현되어 JSON으로 직렬화하고 복사/붙여넣기로 역직렬화해 사용하기 용이하다.

 

 

 

REPL을 활용한 디버깅


 console에 찍힌 데이터를 복/붙해서 사용한다 하는데 어디서 사용하란 거지? 의문일 수 있다. 이는 REPL에서 사용하는 것을 뜻하는데 REPL은 코드를 입력하고 실행하고 결과를 확인하는 프로그래밍 환경을 뜻한다. javascript의 경우 브라우저 콘솔을 REPL로 이해하면 된다.

 

 사실 생각해보면 어느 곳에서도 이 과정을 설명하고 강조하지는 않지만 개발을 하면서 가장 많이 활용하는 도구 중 하나인 것 같다.

 

 

 

단위 테스트와 외부 데이터 테스트


 REPL을 활용해 디버깅하고 그냥 끝내기는 아쉽다. 나중에 동일한 디버깅을 반족하고 싶지 않다면 인자를 확인하고 - 로직을 수행해 - 결과값을 확인하는 디버깅 작업을 단위 테스트로 바꿔두는 편이 좋다.

 

 단위 테스트를 작성하기 위해서는 메서드 인자가 필요한데 이때 인자를 구하는 방식은 다양할 것이다. 유추할 수도, LLM을 이용할 수도 있을 것 같다. 하지만 책에서는 컨텍스트 포착에서 했던 로깅 작업을 활용하라 말한다.  

 

function dumpData(data, context) {
    var path = dataFilePath(context);
    var content = JSON.stringify(data);
    
    fs.writeFile(path, content, function () {
        console.log("Data for " + context + " stored in: " + path);
    });
}

Catalog.searchBooksByTitle = function(catalogData, query) {
    dumpData([catalogData, query], 'searchBooksByTitle');
    
    var allBooks = _.get(catalogData, "booksByIsbn");
    var queryLowerCased = query.toLowerCase();
    
    var matchingBooks = _.filter(allBooks, function(book) {
        return _.get(book, "title")
            .toLowerCase()
            .startsWith(queryLowerCased);
    });

    var bookInfos = _.map(matchingBooks, function(book) {
        return Catalog.bookInfo(catalogData, book);
    });

    return bookInfos;
};

 예를 들어 이전에 console에 인자를 찍어보는 로직을 파일 저장으로 바꾸고 단위 테스트에서 이 파일을 활용하는 것이다. 이 방식 또한 DOP 데이터들이 범용 자료 구조이기 때문에 직/역직렬화가 간단해서 쉽게 적용해볼 수 있는 내용인 것 같다. 

 

 

 마지막으로 외부 데이터 테스트는 어떻게 해야할까? 테스트에서도 외부 데이터를 직접 이용해야 할까? 아니면 외부에서 가져온 데이터를 대체할 목 데이터를 둬야 할까? 책에서도 분명한 해결책을 제시하지는 않는다. 다만 Datomic이란 데이터 베이스에 대한 언급이 있는데 이는 데이터에 시간을 추가 변수로 둬 동일한 시점의 특정 데이터는 항상 동일하게 주어지는 방식을 사용한다. 즉. 이 DB를 이용하면 고정된 데이터를 얻을 수 있다는 의미이다.

 

 하지만 어짜피 동일한 데이터를 얻을 목적이라면 목데이터를 사용해 외부 데이터의 반환값을 대체하는 것과 크게 다르지 않아 보인다.

 

 

 

내 생각


 사실 개발을 시작했을 때부터 지금까지 REPL을 사용하고 있었지만 정확한 용어는 처음 알게 된 것 같다. 항상 하고 있었지만 어디서도 설명해주지 않았던 REPL 디버깅을 언급해줘서 좋았고 잘 활용하는 팁과 DOP의 데이터 구조가 REPL 활용에 왜 좋은지 이해하게 됐다. 또 메서드 인자를 파일로 빼서 단위 테스트에 활용하는 방식은 복잡한 인자를 가진 메서드를 테스트할 때 겪었던 어려움을 해결해 줄 방법인 것 같다.