본문 바로가기

카테고리 없음

VSCode 확장 프로그램 만들기 (3) - VSCode 코드 품질 측정 확장 프로그램(VSCode 익스텐션)

Style Rank 프로젝트 소개

코드를 작성하다 보면 "이 코드가 잘 작성된 건가?" 하는 의문이 들 때가 있다. 주로 ESlint와 같은 도구를 활용하여 코드 컨벤션에 대한 검사를 하곤 하지만, 해당 코드가 얼마나 복잡하게 짜여있는지, 구조적으로 문제가 없어도 클린 코드로써 좋은 코드인지에 대한 검사에는 어려움이 있다. 리뷰를 해주는 입장에서 읽기에 가독성 등의 측면에서 문제가 없는지에 대한 의문이 든 경우가 많을 것이다.

 

Style Rank는 이러한 의문에 답하기 위해 만든 VSCode 익스텐션이다. 파일을 저장하는 순간 코드 품질을 자동으로 분석하고, S/A/B/C/D/F 등급을 실시간으로 보여준다.

 

아래는 관련 깃허브 url과 vscode 익스텐션 마켓의 url이다.

 

Github: https://github.com/ChangwooJ/style-rank

 

GitHub - ChangwooJ/style-rank

Contribute to ChangwooJ/style-rank development by creating an account on GitHub.

github.com

 

VSCode Marketplace(Style Rank): https://marketplace.visualstudio.com/items?itemName=style-rank.style-rank

 

Style Rank - Visual Studio Marketplace

Extension for Visual Studio Code - AST 기반 코드 품질 랭크 측정기

marketplace.visualstudio.com

 

 

 

프로젝트 개요

Style Rank는 AST 기반 코드 복잡도 분석 및 랭크 측정 도구다.

항목 내용
목적 TypeScript/JavaScript 코드의 복잡도와 클린코드 위반 자동 검사
핵심 기능 파일 저장 시 자동 분석 + 실시간 랭크 표시
기술 스택 Babel Parser, Babel Traverse, VSCode Extension API
지원 언어 JavaScript, TypeScript, JSX, TSX

 

핵심 기능

 

자동 코드 분석

 

src/extension.ts에서 파일 저장 이벤트를 감지하여 자동으로 분석을 실행한다.

const saveListener = vscode.workspace.onDidSaveTextDocument((document) => {
  const supportedLanguages = ['typescript', 'javascript', 'typescriptreact', 'javascriptreact'];

  if (!supportedLanguages.includes(document.languageId)) {
    console.log('지원하지 않는 언어입니다.');
    return;
  }

  try {
    const code = document.getText();
    const fileName = path.basename(document.fileName);
    const filePath = document.fileName;
    analyzeCode(code, fileName, filePath, true);
  } catch (e) {
    vscode.window.showErrorMessage(
      `코드 분석 중 오류가 발생했습니다: ${e instanceof Error ? e.message : String(e)}`
    );
  }
});

 

파일을 저장할 때마다 document.getText()로 전체 코드를 가져와 분석한다. 에러 발생 시 사용자에게 명확한 메시지를 표시한다.

 

 

다차원 분석 파이프라인


src/extension.ts의 analyzeCode 함수는 여러 분석을 순차적으로 실행한다.

const analyzeCode = (code: string, fileName: string, filePath: string, showOutput: boolean = false) => {
  try {
    // 1. AST 파싱
    const ast = parseCodeToAST(code);

    // 2. 복잡도 계산
    const complexityResult = calculateRefinedComplexityScore(ast);
    const { ccs, cognitiveComplexity, lengthPenalty, maxNestingDepth, longFunctions, complexityHotspots } = complexityResult;

    // 3. 클린 코드 규칙 검사
    const cleanCodeResult = checkCleanCodeRules(ast);
    const { violations, violationCount } = cleanCodeResult;

    // 4. 랭크 부여
    const rank = assignRefinedRank(ccs, violationCount);
    const rankDescription = getRankDescription(rank);

    // 5. 상태바 업데이트
    const detailedTooltip = [
      `종합 복잡도 점수: ${ccs.toFixed(1)}`,
      `인지 복잡도: ${cognitiveComplexity}`,
      `최대 중첩 깊이: ${maxNestingDepth}`,
      `클린 코드 위반: ${violationCount}건`,
      '',
      rankDescription,
    ].join('\\n');

    statusBarManager.updateRank(rank, Math.round(ccs), detailedTooltip);

    // 6. 분석 결과 저장
    lastAnalysisResult = {
      ccs,
      cognitiveComplexity,
      lengthPenalty,
      maxNestingDepth,
      violationCount,
      violations,
      rank,
      rankDescription,
      longFunctions,
      complexityHotspots,
      filePath,
    };

    return lastAnalysisResult;
  } catch (e) {
    console.error('Error analyzing code:', e);
    statusBarManager.hide();
    throw e;
  }
};

 

이 함수는 Style Rank의 두뇌 역할을 한다. AST 파싱부터 UI 업데이트까지 전체 분석 과정을 관장한다.

 

 

실시간 상태바 표시


src/statusBar.ts의 StatusBarManager 클래스는 분석 결과를 시각화한다.

export class StatusBarManager {
  private statusBarItem: vscode.StatusBarItem;

  constructor(commandId: string) {
    this.statusBarItem = vscode.window.createStatusBarItem(
      vscode.StatusBarAlignment.Right,
      100
    );
    this.statusBarItem.command = commandId;
  }

  updateRank(rank: Rank, complexity: number, description: string): void {
    const icon = this.getRankIcon(rank);
    const color = this.getRankColor(rank);

    this.statusBarItem.text = `${icon} Rank: ${rank}`;
    this.statusBarItem.tooltip = `순환 복잡도: ${complexity}\\n${description}\\n\\n클릭하여 상세 보기`;
    this.statusBarItem.backgroundColor = color;
    this.statusBarItem.show();
  }

  private getRankIcon(rank: Rank): string {
    const icons: Record<Rank, string> = {
      S: '$(star-full)',
      A: '$(별)',
      B: '$(check)',
      C: '$(warning)',
      D: '$(alert)',
      F: '$(error)',
    };
    return icons[rank];
  }

  private getRankColor(rank: Rank): vscode.ThemeColor | undefined {
    if (rank === 'D' || rank === 'F') {
      return new vscode.ThemeColor('statusBarItem.warningBackground');
    }
    return undefined;
  }
}

 

등급에 따라 다른 아이콘과 색상을 표시하여 직관적인 피드백을 제공한다. D와 F 등급은 경고 색상으로 강조된다.

 

 

상세 분석 결과 제공


상태바를 클릭하면 QuickPick UI를 통해 상세 분석 결과를 볼 수 있다.

const showDetailedReport = () => {
  if (!lastAnalysisResult) {
    vscode.window.showInformationMessage('분석 결과가 없습니다. 파일을 저장하여 분석을 시작하세요.');
    return;
  }

  quickPickManager.showAnalysisResult(lastAnalysisResult);
};

const showDetailsCommand = vscode.commands.registerCommand('style-rank.showDetails', showDetailedReport);

 

QuickPick은 복잡도 핫스팟, 긴 함수, 클린 코드 위반 항목을 보여주고, 선택하면 해당 코드 위치로 즉시 이동한다.

 

 

분석 메트릭

Style Rank는 다양한 메트릭을 종합하여 코드 품질을 평가한다

.

 

인지 복잡도 (Cognitive Complexity)

 

중첩 깊이를 고려한 복잡도 측정이다. Early Return 패턴을 감안하고, 깊은 중첩에 가중치를 부여한다.

// 좋은 예: Early Return (복잡도 낮음)
function validateUser(user) {
  if (!user) {
    return false;
  }
  if (!user.email) {
    return false;
  }
  return true;
}

// 나쁜 예: 중첩된 조건문 (복잡도 높음)
function validateUser(user) {
  if (user) {
    if (user.email) {
      return true;
    }
  }
  return false;
}

 

 

함수 길이 패널티

 

30줄을 초과하는 함수를 감지한다. 단, JSX를 포함한 React 컴포넌트는 제외한다.

// React 컴포넌트의 길이는 제외(추후 개선 예정)
function MyComponent() {
  return (
    <div>
      {/* 50줄의 JSX */}
    </div>
  );
}

// 비즈니스 로직이 40줄이면 경고
function processData(data) {
  // 40줄의 복잡한 로직
  // 리팩토링 권장
}

 

 

 

클린 코드 규칙

 

4가지 핵심 규칙을 검사한다.

  • 느슨한 동등 연산자: == 대신 === 사용
  • 매직 넘버: 하드코딩된 숫자를 상수로 선언
  • 파라미터 플래그: boolean 플래그 대신 함수 분리
  • 과다한 파라미터: 5개 초과 시 객체로 그룹화

 

등급 시스템

 

점수 등급 설명
≤5, 위반 0건 S 완벽 - 클린하고 이해하기 쉬운 코드
≤10, 위반 ≤1건 A 우수 - 가독성과 유지보수성이 높은 코드
≤20, 위반 ≤3건 B 양호 - 약간의 개선 여지가 있는 코드
≤30, 위반 ≤5건 C 주의 - 복잡도 또는 코드 스타일 개선 필요
≤40, 위반 ≤8건 D 나쁨 - 즉시 리팩토링 권장
>40 또는 위반 >8건 F 위험 - 긴급 리팩토링 필수

 


프로젝트 구조

style-rank/
├── src/
│   ├── extension.ts           # 확장 진입점 및 이벤트 리스너
│   ├── analyzer.ts            # AST 파싱 엔진
│   ├── complexity.ts          # 복잡도 계산 로직
│   ├── ranking.ts             # 랭킹 시스템
│   ├── cleanCodeRules.ts      # 클린 코드 규칙 검사
│   ├── statusBar.ts           # 상태바 UI 관리
│   ├── quickPickManager.ts    # QuickPick UI 관리
│   └── suggestions.ts         # 타입 정의
├── package.json               # 확장 메타데이터
└── esbuild.js                # 빌드 설정

 

 

사용 방법

1. VSCode에서 JavaScript/TypeScript 파일 열기
2. 파일 저장 (Ctrl+S)
3. 하단 우측 상태바에서 랭크 확인
4. 상태바 클릭 시 상세 분석 결과 보기
5. 개선 항목 선택 시 해당 코드 위치로 이동

 

 

향후 계획

  • 프로젝트 전체 분석 및 리포트 생성
  • 클린 코드 규칙 사용자 설정
  • 커밋 기준 분석 및 깃허브 연동

 

 

마치며

익스텐션을 개발해보며 여태까지 경험해본 개발들은 전반적으로 비슷한 느낌으로 진행된다는걸 알게되었다. 전혀 다른 생태계라면 개발이 생소하게 느껴질 수는 있겠다고 생각되지만, 적어도 유사한 생태계에선 목적과 주로 쓰이는 도구, 언어들이 다를 뿐 전반적인 구조는 같고 동시에 각각 다양한 툴이 존재하기에 접근성도 좋았다.

새로운 시도를 해보며 개발의 본질은 결국 문제를 정의하고 해결하는 과정이라는 점을 다시 한번 느꼈다. AST라는 낯선 개념도 문서와 예제를 통해 학습하면 충분히 활용할 수 있었고, VSCode API도 타입 정의만 잘 따라가면 원하는 기능을 구현할 수 있었다. 처음엔 막연했던 "코드 품질을 어떻게 측정할까?"라는 질문이 구체적인 메트릭과 알고리즘으로 구현되는 과정을 지켜보는 것은 즐거운 경험이었다.

특히 실제로 내가 작성한 코드에 Style Rank를 적용해보며 객관적인 피드백을 받는 경험은 신선했다. 평소에 "이 함수가 좀 복잡한 것 같은데?"라고 막연히 느끼던 것들이 구체적인 숫자와 등급으로 나타나니, 리팩토링의 우선순위를 정하기도 쉬워졌다. 개발 도구를 만드는 개발자로서, 내가 만든 도구가 실제로 도움이 된다는 것을 직접 체감할 수 있었다.

앞으로도 이런 작은 시도들을 계속 이어가며, 개발자로서의 도구 상자를 하나씩 채워나가고 싶다. 불편함을 느끼면 직접 해결하고, 필요한 도구가 없으면 만드는 것. 그것이 개발자가 가진 가장 큰 강점이 아닐까 싶다.