임시 해결책(영어: workaround, kludge, hotfix)은 코드의 문제에 대한 임시적 또는 차선의 해결책으로, 작동은 하지만 클린 아키텍처, 가독성 또는 성능 원칙을 위반합니다. 임시 해결책은 실제 개발에서 불가피합니다. 마감일, 버전 비호환성, 레거시 코드, 문서화되지 않은 프레임워크 동작이 개발자로 하여금 타협하게 만들기 때문입니다. Martin Fowler(2025)에 따르면, 정당화된 임시 해결책과 기술 부채의 주요 차이점은 이를 제거할 계획과 코드 내 명시적 표시의 유무입니다.
핵심 포인트
임시 해결책은 기능적으로는 올바르지만 기술적으로는 차선인 소프트웨어 솔루션을 가리키는 속어입니다. 이러한 코드는 작동하고 테스트를 통과하며 프로덕션에까지 도달하지만, 읽으면 모든 것을 처음부터 다시 쓰고 싶어집니다. 영어권에서는 workaround, kludge(kluge), hack 또는 quick-and-dirty fix라는 용어가 사용됩니다.
이 용어는 가정의 은유에서 유래했습니다. 의자 다리가 부러지면 테이프로 묶을 수 있습니다. 의자는 다시 작동하지만 해결책은 임시적이고 보기 흉합니다. 프로그래밍에서도 마찬가지입니다. 버그는 하드코드, 타임아웃 임시 해결책 또는 문서화되지 않은 API를 통한 우회로 수정됩니다. 코드는 컴파일되고 애플리케이션은 충돌하지 않지만, 해결책을 품질 높은 것이라고 할 수 없습니다.
중요한 차이점: 버그는 코드가 예상대로 작동하지 않는 것입니다. 임시 해결책은 코드가 작동하지만 설계가 나쁜 것입니다. 임시 해결책은 항상 개발자의 의식적인 선택입니다. “이것이 추하다는 것을 알지만 지금은 문제를 해결합니다.”
Stripe(2024)에 따르면, 개발자는 평균적으로 주당 17시간을 기술 부채와 임시 해결책 처리에 소비합니다. 이는 근무 시간의 거의 절반입니다. 이는 팀 생산성의 직접적인 손실입니다.
첫 번째이자 주요 원인은 마감일입니다. 출시까지 하루가 남았고 중요한 버그가 아직 수정되지 않은 경우, 팀은 올바른 해결책 대신 빠른 해결책을 선택합니다. 값 하드코딩, 검사 비활성화, sleep() 추가는 마감일 임시 해결책의 전형적인 예입니다. 숙련된 개발자는 항상 이러한 위치를 TODO 또는 FIXME로 표시합니다.
두 번째 원인은 API 비호환성입니다. 타사 라이브러리나 프레임워크가 문서화된 것과 다르게 동작합니다. 프레임워크가 필요한 클래스를 내보내지 않거나, 메서드가 더 이상 사용되지 않는 것으로 표시되었지만 대안이 없습니다. 개발자는 리플렉션, 내부 API 또는 우회 방법을 사용해야 합니다. Java에서는 setAccessible(true)를 통한 접근, Swift에서는 @objc와 performSelector가 이에 해당합니다.
세 번째 원인은 레거시 코드입니다. 개발자가 5~10년 전에 오래된 프레임워크 버전으로 작성된 프로젝트를 인계받습니다. 전체 모듈을 다시 작성할 시간이나 예산이 없어 새 기능이 임시 해결책을 통해 기존 코드에 “붙여집니다.” 점차 레이어가 너무 많이 쌓여 모듈이 “큰 진흙 덩어리”(big ball of mud)로 변합니다.
네 번째 원인은 테스트 부족입니다. 테스트 없는 리팩토링은 위험합니다. 아키텍처 변경이 작동 중인 기능을 손상시킬 수 있습니다. 테스트가 없을 때 개발자는 안정성을 위험에 빠뜨리기보다 작동 중인 코드 위에 임시 해결책을 추가하는 것을 선호합니다. Google Testing Blog(2024)에 따르면, 테스트가 없는 팀은 워크어라운드 솔루션을 3배 더 많이 사용합니다.
임시 해결책의 분류는 팀이 어떤 유형의 기술 부채를 다루고 있는지 이해하고 올바른 제거 전략을 선택하는 데 도움이 됩니다. 주요 유형을 살펴보겠습니다.
하드코드 — 가장 일반적인 유형. 구성, 리소스 또는 매개변수 대신 코드에 고정 값이 사용됩니다. 예: 하드코딩된 서버 URL, 5초 타임아웃, 16pt 글꼴 크기. 하드코드는 코드를 확장 불가능하게 만들고 변경 시마다 재컴파일이 필요합니다.
복사-붙여넣기 — 공통 로직을 추출하는 대신 약간의 수정을 가해 코드를 복제하는 것. 전형적인 증상: 프로젝트에 한 줄만 다른 3개의 유사한 메서드가 있습니다. 복사-붙여넣기는 작업 시 코드 작성을 빠르게 하지만 향후 유지보수를 10배 느리게 만듭니다. 수정을 한 곳이 아닌 세 곳에 적용해야 하기 때문입니다.
빈 try-catch — 아무것도 하지 않거나 오류를 처리하지 않고 로깅만 하는 catch 블록. 이러한 임시 해결책은 예외를 “무음화”하지만 원인을 해결하지 않습니다. 애플리케이션은 계속 작동하지만 데이터가 손상되거나 사용자가 피드백을 받지 못할 수 있습니다.
코드 내 Sleep — 이벤트나 콜백이 있어야 할 자리에 Thread.sleep(500) 또는 DispatchQueue.main.asyncAfter를 사용하는 것. 이 코드는 신뢰할 수 없습니다. 느린 기기에서는 500ms로 충분하지 않을 수 있고, 빠른 기기에서는 일시 중지가 불필요합니다. CountDownLatch, Semaphore 또는 적절한 타이밍의 async/await를 사용하세요.
호환성 플래그 — OS 버전, 기기 모델 또는 기능 가용성을 확인하는 if-else 계단식 구조. 플래그가 3~4개를 넘으면 코드가 스파게티가 됩니다. 해결책은 Strategy 패턴이나 구성을 통한 Feature Flags입니다.
많은 개발자가 임시 해결책과 기술 부채를 혼동합니다. 차이점은 규모와 인식에 있습니다. 임시 해결책은 국소적이고 구체적인 해결책(하나의 메서드, 하나의 클래스)입니다. 기술 부채는 모듈이나 전체 애플리케이션의 아키텍처에 영향을 미치는 시스템적 문제입니다.
Ward Cunningham(기술 부채 용어의 창시자)의 은유: 기술 부채는 은행 대출을 받는 것과 같습니다. 지금 돈을 빌려 집을 더 빨리 짓지만, 나중에 이자를 지불합니다. 임시 해결책은 못 박는 기계 대신 망치로 못을 박는 것과 같습니다. 작업은 완료되지만 덜 효율적입니다.
하나의 임시 해결책이 기술 부채를 만들지는 않습니다. 그러나 하나의 모듈에 50개의 임시 해결책이 있으면 아키텍처 부채입니다. 따라서 팀 규칙: 각 임시 해결책은 코드 리뷰나 작업 추적기에 기록되며, 팀은 정기적으로(스프린트당 한 번) 축적된 워크어라운드 솔루션을 검토합니다.
Spotify Engineering(2023)에 따르면, 코드에서 임시 해결책을 추적하는 팀(특수 TODO 레이블 또는 사용자 정의 어노테이션 사용)은 리팩토링 시간을 30% 줄입니다. 문제 지점을 찾는 데 시간을 낭비하지 않기 때문입니다.
첫 번째 단계는 목록 작성입니다. 코드베이스에서 키워드를 검색하세요: TODO, FIXME, HACK, WORKAROUND, KLUDGE. 최신 IDE는 이를 별도 색상으로 강조 표시합니다. GitHub도 Pull Request 인터페이스에서 TODO를 표시합니다. 우선순위와 함께 모든 임시 해결책 목록을 만드세요.
두 번째 단계는 우선순위 설정입니다. 모든 임시 해결책을 즉시 수정할 필요는 없습니다. 우선순위 = 파일 변경 빈도 × 중요도. 파일이 연간 2번 변경되면 임시 해결책은 기다릴 수 있습니다. 모듈이 모든 스프린트에서 수정된다면 임시 해결책을 먼저 수정해야 합니다.
세 번째 단계는 테스트와 함께하는 리팩토링입니다. 테스트 없이 임시 해결책을 리팩토링하지 마세요. 먼저 현재 동작(임시 해결책 포함)을 검증하는 테스트를 작성하고, 리팩토링한 다음, 테스트가 통과하는지 확인하세요. 이 과정 없이 임시 해결책을 리팩토링하면 해당 코드가 작성된 목적의 기능이 손상될 수 있습니다.
// Before: 하드코딩된 URL 워크어라운드
fun getApiUrl(): String {
return "https://api.example.com/v2"
}
// After: BuildConfig를 통한 구성
fun getApiUrl(): String {
return BuildConfig.API_BASE_URL
}
네 번째 단계는 자동화입니다. 특정 임시 해결책 패턴을 금지하는 린터를 설정하세요. 예를 들어, Kotlin용 Detekt는 프로덕션 코드에서 Thread.sleep()의 부재를 확인할 수 있고, ESLint는 프로젝트에서 console.log를 금지할 수 있습니다. 이는 동일한 유형의 새로운 임시 해결책이 나타나는 것을 방지합니다.
이 용어의 부정적인 의미에도 불구하고, 임시 해결책은 정당화된 해결책이 될 수 있습니다. 주요 조건: 임시 해결책이 일시적이고, 명시적으로 표시되며, 대체 계획이 있어야 합니다. 모든 대규모 프로젝트의 프로덕션 코드에는 수백 개의 정당화된 임시 해결책이 있습니다.
상황 1: 프로덕션 핫픽스. 중요한 버그가 모든 사용자에게 영향을 미칩니다. 팀은 1시간 이내에 수정이 필요합니다. 올바른 접근 방식: 가능한 모든 방법으로 버그를 수정하고 핫픽스를 배포합니다. 그런 다음 다음 날 적절한 해결책을 작성하고 티켓을 종료합니다. 핫픽스가 48시간 이상 지속되지 않으면 정당화된 임시 해결책입니다.
상황 2: 새 라이브러리 버전 대기. 프레임워크에 master에서 수정되었지만 릴리스가 2주 후인 버그가 있습니다. 복잡한 우회 코드를 작성하는 대신 팀은 “REMOVE after library 3.2”라는 메모와 함께 워크어라운드를 추가합니다. 3.2가 릴리스되면 워크어라운드가 제거됩니다.
상황 3: 스타트업 또는 MVP 마감. MVP 단계에서는 아키텍처보다 속도가 중요합니다. 시작 단계의 임시 해결책은 정상입니다. 문제는 스타트업이 제품으로 전환되지 않고 임시 해결책이 남아 있을 때 발생합니다. 권장 사항: 펀딩 라운드 후 중요한 기술 부채를 해결하기 위한 스프린트를 할당하세요.
주요 원칙: “레거시 코드는 테스트 없는 코드다”(Michael Feathers). 임시 해결책이 테스트로 보호되고 명시적으로 문서화되어 있다면 관리 가능합니다. 잊혀진 모듈에서 2년 동안 주석 없이 방치되어 있다면 더 이상 임시 해결책이 아니라 아키텍처 문제입니다.
자주 묻는 질문
버그 — 코드가 예상대로 작동하지 않습니다. 임시 해결책 — 코드가 작동하지만 차선으로 작성되었습니다. 임시 해결책은 항상 개발자의 의식적인 결정이며, 버그는 일반적으로 무의식적인 실수입니다.
// TODO: refactor — ... 또는 이유, 날짜, 책임자, 제거 기한을 필드로 가진 사용자 정의 @Workaround 어노테이션을 사용하세요. 설명 없는 맨 // HACK은 피하세요.
모듈이 변경되지 않고 임시 해결책이 안정적이라면 — 아니요. 이유 없는 리팩토링은 회귀 위험을 증가시킵니다. 새 기능 추가를 방해하는 임시 해결책만 수정하세요.
시간을 비교하세요: “현재 이러한 임시 해결책 때문에 수동 테스트에 4시간을 소비합니다. 리팩토링은 8시간이 걸리며 시간을 30분으로 줄입니다. 투자 수익률은 2스프린트입니다.” 속도와 비용의 언어로 말하고, 클린 아키텍처의 언어로 말하지 마세요.
프로젝트 전체에서 grep으로 TODO, FIXME, HACK, WORKAROUND를 검색하세요. 100줄이 넘는 메서드와 5개 이상의 종속성을 가진 클래스를 분석하세요. 사용자 정의 규칙이 있는 린터를 사용하여 자동 감지하세요.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.