Skip to content

일반적인 실패 사례

TQS 인증 심사에서 빈번하게 발생하는 불합격 사유와 그 해결 방법을 정리합니다. 본 장은 빈출 불합격 사유, 사례별 원인 분석, 자주 묻는 질문(FAQ)을 포함합니다. 프로젝트 팀은 심사 요청 전에 본 장의 내용을 참고하여 동일한 실수를 반복하지 않도록 사전에 대비해야 합니다.


33.3.1. 빈출 불합격 사유 Top 10

다음은 TQS 인증 심사에서 가장 빈번하게 발견되는 불합격 사유를 빈도순으로 정리한 것입니다.

순위불합격 사유빈도영향 영역
1테스트 커버리지 미달 (라인 80% 또는 브랜치 70% 미만)매우 높음테스트
2System.out.println 사용높음코드 컨벤션
3TypeScript any 타입 사용높음프론트엔드
4CI/CD 파이프라인 미구성 또는 불완전높음운영
5시크릿 하드코딩 (API 키, 비밀번호, 토큰)높음보안
6JPA/Hibernate 사용 (jOOQ 미사용)중간데이터
7Vue Options API 사용중간프론트엔드
8Flyway 마이그레이션 미적용중간데이터
9.gitignore 누락 또는 불완전중간형상관리
10글로벌 예외 처리 미구현중간백엔드

위 항목은 모두 TQS 필수 항목에 해당합니다. 하나라도 미충족 시 인증을 획득할 수 없습니다.


33.3.2. 사례별 원인 분석

각 불합격 사유에 대해 원인, 해결 방법, 예방 방법을 상세히 설명합니다.

33.3.2.1. 테스트 커버리지 미달

원인: 테스트 코드 작성 문화가 정착되지 않았거나, 테스트 작성 시간을 확보하지 못한 경우에 발생합니다. 복잡한 비즈니스 로직에 대한 테스트 작성이 어려워 후순위로 밀리는 경우가 많습니다.

해결 방법:

  • 핵심 비즈니스 로직(서비스 레이어)부터 우선적으로 테스트를 작성합니다.
  • 테스트가 불필요한 코드(설정 클래스, DTO, jOOQ 자동 생성 코드)는 커버리지 측정에서 제외합니다.
  • JaCoCo의 <exclude> 설정으로 제외 대상을 명시합니다.

예방 방법:

  • 새로운 기능 개발 시 테스트 코드를 함께 작성하는 관행을 수립합니다.
  • CI 파이프라인에 커버리지 임계값 검증을 추가하여 커버리지가 하락하면 빌드가 실패하도록 설정합니다.

33.3.2.2. System.out.println 사용

원인: 디버깅 목적으로 삽입한 System.out.println이 제거되지 않고 남아 있는 경우입니다. 로깅 프레임워크에 대한 인식이 부족한 경우에도 발생합니다.

해결 방법:

  • 모든 System.out.println을 SLF4J + Logback 기반 로깅으로 교체합니다.
  • 디버깅용 출력은 log.debug()를 사용하고, 운영 환경에서는 DEBUG 레벨을 비활성화합니다.

예방 방법:

  • ESLint 또는 정적 분석 도구에서 System.out.println 사용을 에러로 감지하도록 규칙을 설정합니다.
  • 코드 리뷰 시 콘솔 출력 사용 여부를 필수 점검 항목으로 포함합니다.

33.3.2.3. TypeScript any 타입 사용

원인: 타입 정의가 복잡하거나 외부 라이브러리의 타입이 불분명한 경우, 편의를 위해 any를 사용하는 경우입니다.

해결 방법:

  • 외부 라이브러리의 타입이 제공되지 않는 경우 declare module로 타입을 선언합니다.
  • 제네릭을 활용하여 유연하면서도 타입 안전한 코드를 작성합니다.
  • 불가피한 경우 unknown을 사용하고 타입 가드로 타입을 좁힙니다.

예방 방법:

  • ESLint에서 @typescript-eslint/no-explicit-any 규칙을 error로 설정합니다.
  • 타입 정의 파일(.d.ts)을 프로젝트에 포함하여 관리합니다.

33.3.2.4. CI/CD 파이프라인 미구성

원인: CI/CD의 필요성을 인지하지 못하거나, 설정의 복잡함으로 인해 미루는 경우입니다. 로컬 환경에서만 빌드와 테스트를 수행하는 관행이 고착된 프로젝트에서 빈번합니다.

해결 방법:

  • CircleCI 기반 파이프라인을 구성합니다. .circleci/config.yml 파일을 생성하고 린트 → 테스트 → 빌드 → 보안 스캔 순서로 단계를 정의합니다.
  • TQS가 요구하는 모든 검증 도구(Spotless, ESLint, Prettier, JaCoCo, Vitest, OWASP)를 파이프라인에 통합합니다.

예방 방법:

  • 프로젝트 초기 단계에서 CI/CD 파이프라인을 우선적으로 구성합니다.
  • 파이프라인 설정 파일을 버전 관리에 포함합니다.

33.3.2.5. 시크릿 하드코딩

원인: 개발 편의를 위해 API 키, 데이터베이스 비밀번호, 외부 서비스 토큰을 소스코드에 직접 작성하는 경우입니다. 로컬 환경용으로 작성한 시크릿이 커밋에 포함되는 사고가 빈번합니다.

해결 방법:

  • 모든 시크릿을 환경 변수로 분리합니다. Spring Boot의 경우 application.yml에서 ${ENV_VAR} 형식으로 참조합니다.
  • .env 파일을 .gitignore에 추가하여 버전 관리에서 제외합니다.
  • Git 이력에 이미 커밋된 시크릿이 있는 경우, 시크릿을 즉시 변경(로테이션)합니다.

예방 방법:

  • Pre-commit 훅에 시크릿 감지 도구를 추가합니다.
  • 코드 리뷰 시 시크릿 포함 여부를 필수 점검 항목으로 포함합니다.

33.3.2.6. JPA/Hibernate 사용

원인: TQS 규격에서 데이터 접근 계층의 표준 기술로 jOOQ를 지정하고 있으나, 기존에 JPA/Hibernate를 사용하던 프로젝트가 전환하지 않은 경우입니다.

해결 방법:

  • 신규 프로젝트는 처음부터 jOOQ를 사용하여 개발합니다.
  • 기존 프로젝트는 새로운 기능부터 jOOQ를 적용하고, 기존 JPA 코드는 단계적으로 전환합니다.
  • jOOQ 코드 생성기를 설정하여 데이터베이스 스키마 기반의 타입 안전한 쿼리를 작성합니다.

예방 방법:

  • 프로젝트 초기 설정 시 jOOQ 의존성과 코드 생성기를 구성합니다.
  • TQS 규격의 데이터 접근 계층 표준을 팀에 공유합니다.

33.3.2.7. Vue Options API 사용

원인: Vue 2 시절부터 개발된 프로젝트에서 Options API를 그대로 사용하는 경우입니다. Composition API에 대한 학습 비용을 이유로 전환을 미루는 경우도 있습니다.

해결 방법:

  • 모든 Vue 컴포넌트를 <script setup> 기반 Composition API로 전환합니다.
  • 공통 로직은 Composable 함수로 추출합니다.
  • Pinia 스토어는 Setup Store 방식으로 정의합니다.

예방 방법:

  • 새로운 컴포넌트 생성 시 반드시 Composition API를 사용하도록 팀 내 규칙을 수립합니다.
  • ESLint에서 Options API 사용을 감지하는 규칙을 활성화합니다.

33.3.2.8. Flyway 마이그레이션 미적용

원인: 데이터베이스 스키마 변경을 수동으로 관리하거나, 마이그레이션 도구의 필요성을 인식하지 못한 경우입니다.

해결 방법:

  • Flyway를 프로젝트에 통합하고, 모든 스키마 변경을 마이그레이션 스크립트로 관리합니다.
  • 마이그레이션 파일은 V{버전}__{설명}.sql 명명 규칙을 따릅니다.
  • 기존 스키마를 기준으로 초기 마이그레이션 파일(Baseline)을 생성합니다.

예방 방법:

  • 프로젝트 초기에 Flyway를 설정하고, 첫 번째 마이그레이션 파일을 생성합니다.
  • 수동 DDL 실행을 금지하고, 모든 스키마 변경을 마이그레이션 파일로만 수행하도록 합니다.

33.3.2.9. .gitignore 누락

원인: .gitignore 파일을 생성하지 않거나, IDE 설정 파일, 빌드 산출물, 환경 변수 파일 등이 적절히 제외되지 않은 경우입니다.

해결 방법:

  • 프로젝트 루트에 .gitignore 파일을 생성합니다.
  • 다음 항목이 반드시 포함되어야 합니다: IDE 설정(.idea/, .vscode/의 개인 설정), 빌드 산출물(target/, dist/, node_modules/), 환경 변수 파일(.env, .env.local), OS 파일(.DS_Store, Thumbs.db).
  • 이미 커밋된 파일은 git rm --cached 명령으로 추적을 해제합니다.

예방 방법:

  • 프로젝트 생성 직후 .gitignore를 설정합니다.
  • 팀 공용 .gitignore 템플릿을 유지합니다.

33.3.2.10. 글로벌 예외 처리 미구현

원인: 예외 처리를 각 컨트롤러에서 개별적으로 수행하거나, 예외 발생 시 스택 트레이스가 클라이언트에 그대로 노출되는 경우입니다.

해결 방법:

  • Spring Boot의 @RestControllerAdvice를 사용하여 글로벌 예외 처리를 구현합니다.
  • 표준 에러 응답 형식을 정의하고 모든 예외에 일관되게 적용합니다.
  • 예외 유형별로 적절한 HTTP 상태 코드를 반환하도록 설정합니다.

예방 방법:

  • 프로젝트 초기에 글로벌 예외 처리 클래스를 생성합니다.
  • 표준 에러 응답 형식을 팀 내에 공유하고 준수합니다.

33.3.3. FAQ

TQS 인증 준비 과정에서 자주 묻는 질문과 답변을 정리합니다.

Q1. 기존 JPA 프로젝트를 jOOQ로 마이그레이션해야 하나요?

신규 프로젝트는 처음부터 jOOQ를 사용해야 합니다. 기존 JPA 프로젝트의 경우, 즉시 전면 전환이 아닌 단계적 전환을 권장합니다. 새로운 기능 개발 시 jOOQ를 적용하고, 기존 JPA 코드는 유지보수 과정에서 순차적으로 전환합니다. 다만, 최초 심사 시 신규 프로젝트에서 JPA를 사용하는 경우 불합격 처리됩니다.

Q2. 테스트 커버리지 80%를 달성하기 어렵습니다.

커버리지 달성이 어려운 경우, 다음 전략을 적용합니다. 첫째, 핵심 비즈니스 로직(서비스 레이어)을 우선적으로 테스트합니다. 둘째, 테스트가 불필요한 코드(설정 클래스, DTO, 자동 생성 코드)를 커버리지 측정에서 제외합니다. 셋째, 단순히 수치를 올리기 위한 의미 없는 테스트는 지양합니다. TQS 기술 심사에서는 커버리지 수치뿐만 아니라 테스트의 품질도 함께 검증합니다.

Q3. Options API로 작성된 대규모 프로젝트를 전환하는 데 시간이 부족합니다.

전체 컴포넌트를 한 번에 전환할 필요는 없습니다. 다만, TQS 인증 시점에 모든 컴포넌트가 Composition API를 사용해야 합니다. 대규모 프로젝트의 경우, 인증 일정을 충분히 확보하고 단계적으로 전환하는 것을 권장합니다. 전환 작업은 단순 컴포넌트부터 시작하여 복잡한 컴포넌트로 확장하는 방식이 효과적입니다.

Q4. CI/CD 파이프라인에 모든 검증 도구를 포함해야 하나요?

TQS에서 요구하는 필수 검증 도구(Spotless, ESLint, Prettier, JaCoCo, Vitest, OWASP Dependency-Check)는 반드시 CI 파이프라인에 포함해야 합니다. Lighthouse는 배포 후 별도로 실행할 수 있지만, CI에 통합하는 것을 권장합니다. 파이프라인에 포함되지 않은 도구의 검증 결과는 심사 시 인정되지 않을 수 있습니다.

Q5. OWASP 스캔에서 오탐(False Positive)이 발생하면 어떻게 해야 하나요?

오탐으로 확인된 취약점은 억제(Suppression) 파일에 등록하여 이후 스캔에서 제외할 수 있습니다. 다만, 억제 등록 시 해당 취약점이 오탐임을 증명하는 근거를 함께 기록해야 합니다. 심사 시 억제 파일의 타당성도 검증 대상에 포함됩니다.

Q6. 인증 준비 기간 동안 기능 개발을 병행할 수 있나요?

병행은 가능하지만, 인증 준비 작업의 우선순위를 높이는 것을 권장합니다. 새로운 기능 개발 시 TQS 규격을 준수하며 개발하면 인증 준비와 기능 개발을 동시에 진행할 수 있습니다. 다만, 인증 준비 일정이 지연되지 않도록 프로젝트 리드가 일정을 관리해야 합니다.

Q7. 기본 인증과 우수 인증의 실질적 차이는 무엇인가요?

기본 인증은 필수 항목 100% 충족만으로 획득할 수 있습니다. 우수 인증은 필수 항목 100%에 더하여 권장 항목의 80% 이상을 충족해야 합니다. 우수 인증을 획득하면 TQS 마크에 "우수" 등급을 표기할 수 있으며, 사내 기술 우수 사례로 등록될 수 있습니다. 처음 인증을 준비하는 프로젝트는 기본 인증 획득을 우선 목표로 설정하는 것을 권장합니다.

Q8. 심사에서 조건부 통과를 받으면 어떻게 되나요?

조건부 통과는 경미한 보완이 필요한 경우에 부여됩니다. 보완 기간은 최대 2주이며, 보완 완료 후 재확인 심사를 거쳐 최종 판정을 받습니다. 재확인 심사는 미충족 항목에 대해서만 수행하므로 전체 재심사보다 부담이 적습니다.

Q9. Flyway 마이그레이션을 적용하면 기존 데이터에 영향이 있나요?

Flyway의 Baseline 기능을 사용하면 기존 데이터베이스 스키마를 유지하면서 마이그레이션 관리를 시작할 수 있습니다. Baseline 이후의 스키마 변경만 마이그레이션 파일로 관리하면 되므로, 기존 데이터에 영향을 주지 않습니다.

Q10. HikariCP 커넥션 풀 설정도 심사 대상인가요?

HikariCP는 TQS에서 필수로 지정한 커넥션 풀 라이브러리입니다. 커넥션 풀 설정(최대 풀 크기, 타임아웃 등)의 적정성도 심사 항목에 포함됩니다. Spring Boot 3.x에서는 HikariCP가 기본 커넥션 풀이므로 별도의 라이브러리 교체는 필요하지 않지만, 설정 값이 운영 환경에 적합한지 확인해야 합니다.

Q11. 프론트엔드만 있는 프로젝트도 TQS 인증을 받을 수 있나요?

프론트엔드만 포함하는 프로젝트도 TQS-S/W 인증을 받을 수 있습니다. 이 경우 프론트엔드 관련 체크리스트 항목만 적용됩니다. 백엔드 관련 항목(Spotless, JaCoCo, jOOQ, Flyway 등)은 심사에서 제외됩니다.

Q12. 인증 심사 중에 코드를 수정할 수 있나요?

정식 기술 심사가 진행되는 동안에는 심사 대상 브랜치의 코드를 수정해서는 안 됩니다. 심사 요청 시 제출한 커밋 해시 기준으로 검증이 수행되므로, 심사 중 코드 변경은 심사 결과의 일관성을 해칠 수 있습니다. 코드 수정은 심사 결과 통보 후에 진행해야 합니다.

Q13. 보안 사고가 발생한 이력이 있으면 인증에 불리한가요?

보안 사고 이력 자체가 불합격 사유는 아닙니다. 다만, 사고 발생 후 적절한 대응 조치(원인 분석, 재발 방지 대책, 보안 설정 보강)가 이루어졌는지를 심사합니다. 대응 조치가 TQS 규격을 충족하면 인증을 획득할 수 있습니다.

TIENIPIA QUALIFIED STANDARD