dev.log2009. 3. 3. 18:17
회사에는 goto를 좋아하는 사람이 한명 있다. goto를 그냥 남발하는 게 아니다. 진심으로 goto를 좋아해서 쓴다 -_-a 이런 종류의 인간이 제일 난감한데, 이런 식이다. '남들이 다 쓰지 말라고 하는 거지만 난 잘 쓸 자신이 있다'는 식이다. 남들과 달리 잘 쓸 수 있으므로 쓰겠다는 입장. 그래서 모든 로직의 핵심을 goto로 구현해 놓고 자랑스러워한다. '이 로직은 goto로 완벽하게 짜봤지요' ㄷㄷㄷ

bool func()
{
    bool succ = false;
    mutex.lock();
    if ( do_something() == false )
       goto exit;

    if ( do_another() == false )
       goto exit;

    if ( do_blabla() == false )
       goto exit;

    succ = true;
exit:
    mutex.unlock();
    return succ;
}


사실 난 되도록이면 코드는 자기가 짜고 싶은 대로 짜면 된다;는 입장이라, 이 인간이 goto를 쓰건 말건 걍 놔 뒀었다. 그리고 위와 같은 코드는 일반적으로 용인되는 goto의 쓰임과 크게 어긋나지도 않기 때문에. 문제는 이런 부분.

void* get()
{
retry:
    mutex.lock();  

    if ( !available )
    {
        if ( try_alloc() == false )
            goto must_alloc
    }

    void* result = do_postprocess();
    mutex.unlock();
    goto done;   

must_alloc:
    mutex.unlock();

    if ( alloc()  )
        goto retry;
    return 0;

done:
    return result;
}

대충 이런식. 이 코드를 내가 디버깅해야 할 비상사태가 오면서 문제가 불거지기 전까지는 문제의 심각성을 몰랐다. -_- 뒤로갔다 앞으로 갔다 하는 goto의 흐름을 쫓다가 디버깅시간의 2/3가 흘러간 걸 보고서 고쳐놔야 겠다는 생각이 들었다.

사실 앞의 코드는 너무 쉽다. 그냥 true/false를 바로 리턴하도록 바꾸고 뮤텍스는 로컬 객체로 래핑해서 생성자/소멸자에서 lock/unlock을 부르게 하면 되니까. 뒤에 꺼는 좀 까다롭다. 분명히 루프이긴 한데, 루프의 종료조건이 뭔지 알기가 매우 힘들다 -_- 종료조건이라 하더라도 거기에서도 분기가 두갈래다. 깔끔한 코드를 만들기가 어렵다. 나름 도전의식이 생기는 코드랄까.

Posted by uhm