General

개발자를 위한 타자 연습기: 코드로 연습하자!


개발자라면 누구나 한 번쯤 “타자 속도가 빠르면 코딩도 빨라질까?”라는 생각을 해봤을 겁니다. 물론 코딩은 생각하는 시간이 더 많지만, 막힘없이 코드를 쳐내려가는 느낌은 꽤나 중독적이죠.

하지만 일반적인 타자 연습 사이트의 문장들은 개발자에게 큰 도움이 되지 않습니다. 우리는 function, return, import 같은 키워드와 괄호 {}, ()를 훨씬 더 많이 쓰니까요.

그래서 만들었습니다. 개발자를 위한, 개발자에 의한 타자 연습기!

🎮 직접 해보세요

아래 창에서 바로 시작할 수 있습니다. 실제 코드(JavaScript, Python, Java 등)가 무작위로 나옵니다.

DevTyper

Language:

Type the code exactly as shown.

const debounce = (func, wait) => { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; };

Press Tab to restart quickly (not implemented yet)

0 / 252 chars

🛠️ 어떻게 만들었나요?

이 프로젝트는 ReactFramer Motion을 사용하여 만들었습니다. 초보자도 이해할 수 있도록 단계별로 설명하겠습니다.

전체 구조

먼저 타자 연습기가 어떻게 동작하는지 전체적인 흐름을 살펴보겠습니다.

graph TD
    A[게임 시작] --> B[코드 스니펫 선택]
    B --> C[사용자 입력 대기]
    C --> D{입력한 문자가<br/>정답과 일치?}
    D -->|일치| E[초록색 표시<br/>콤보 증가]
    D -->|불일치| F[빨간색 표시<br/>콤보 초기화]
    E --> G{모든 문자를<br/>입력했는가?}
    F --> G
    G -->|아니오| C
    G -->|예| H[결과 화면 표시<br/>속도/정확도]
    H --> I{다시 시작?}
    I -->|예| B
    I -->|아니오| J[종료]

1. 상태 관리 (State Management)

React에서 가장 중요한 것은 상태(state) 관리입니다. 타자 게임에서 관리해야 할 상태들은 다음과 같습니다.

const [gameState, setGameState] = useState('start'); // 'start', 'playing', 'finished'
const [selectedLanguage, setSelectedLanguage] = useState('All'); // 선택된 언어
const [input, setInput] = useState(''); // 사용자가 입력한 텍스트
const [wpm, setWpm] = useState(0); // 타자 속도
const [accuracy, setAccuracy] = useState(100); // 정확도
const [combo, setCombo] = useState(0); // 현재 콤보

이 상태들이 어떻게 연결되어 있는지 다이어그램으로 이해해봅시다.

graph LR
    A[사용자 입력] --> B[input 상태 업데이트]
    B --> C[정확도 계산]
    B --> D[속도 계산]
    B --> E[콤보 계산]
    C --> F[화면에 표시]
    D --> F
    E --> F

2. 실시간 피드백 시스템

사용자가 타이핑하는 순간마다 즉각적인 피드백을 제공합니다. 이것이 타자 게임의 핵심입니다!

sequenceDiagram
    participant 사용자
    participant 입력필드
    participant 비교로직
    participant 화면

    사용자->>입력필드: 문자 입력 (예: 'c')
    입력필드->>비교로직: 입력값 전달
    비교로직->>비교로직: 타겟 코드와 비교
    alt 정답
        비교로직->>화면: 초록색 표시
        비교로직->>비교로직: 콤보 +1
    else 오답
        비교로직->>화면: 빨간색 표시
        비교로직->>비교로직: 콤보 초기화
    end
    화면->>사용자: 시각적 피드백

코드로 구현하면 다음과 같습니다:

const handleInput = (e) => {
  const value = e.target.value;
  const targetCode = currentSnippet.code;
  
  setInput(value);
  
  // 각 문자마다 정답 확인
  for (let i = 0; i < value.length; i++) {
    if (value[i] === targetCode[i]) {
      // 정답: 초록색 표시
      correctChars++;
    } else {
      // 오답: 빨간색 표시
      isError = true;
    }
  }
};

3. 자동 들여쓰기 기능

코드를 칠 때 가장 번거로운 것이 바로 들여쓰기입니다. 엔터를 누를 때마다 자동으로 들여쓰기를 채워넣는 기능을 추가했습니다.

flowchart TD
    A[사용자가 Enter 입력] --> B{다음 줄에<br/>공백이 있나?}
    B -->|있음| C[공백의 개수 계산]
    C --> D[자동으로 공백 추가]
    D --> E[커서를 들여쓰기 뒤로 이동]
    B -->|없음| F[그냥 줄바꿈만]

구현 코드:

if (lastChar === '\n') {
  // 다음 줄의 들여쓰기 확인
  const targetSubstring = targetCode.substring(lastCharIdx + 1);
  const match = targetSubstring.match(/^ +/); // 공백 찾기
  
  if (match) {
    const indentation = match[0]; // 공백 개수
    setInput(value + indentation); // 자동으로 추가!
  }
}

4. 속도 계산 (WPM → CPM)

타자 게임에서 가장 중요한 속도 측정! 우리는 CPM(분당 타수)을 사용합니다.

graph LR
    A[시작 시간 기록] --> B[현재 시간 - 시작 시간]
    B --> C[경과 시간 계산]
    C --> D[입력한 문자 수 / 경과 시간]
    D --> E[분당 타수 CPM 계산]
    E --> F[화면에 'XXX타' 표시]
useEffect(() => {
  if (gameState === 'playing' && startTime) {
    const interval = setInterval(() => {
      const timeElapsed = (Date.now() - startTime) / 60000; // 분 단위
      const wordsTyped = input.length / 5;
      const currentWpm = Math.round(wordsTyped / timeElapsed);
      setWpm(currentWpm);
    }, 500); // 0.5초마다 업데이트
    
    return () => clearInterval(interval);
  }
}, [gameState, startTime, input]);

5. 컴포넌트 구조

React 컴포넌트가 어떻게 구성되어 있는지 살펴봅시다.

graph TD
    A[TypingGame 메인 컴포넌트] --> B[언어 선택 버튼]
    A --> C[게임 상태 표시<br/>속도/정확도/콤보]
    A --> D[코드 표시 영역]
    A --> E[숨겨진 입력 필드]
    A --> F[결과 화면]
    
    D --> D1[문자별 색상 표시]
    D --> D2[커서 위치 표시]
    D --> D3[엔터 기호 표시]
    
    F --> F1[최종 속도]
    F --> F2[정확도]
    F --> F3[최대 콤보]

6. 주요 기능들

개발자들의 피드백을 반영하여 다음과 같은 기능들을 추가했습니다.

기능설명구현 방법
언어 선택JavaScript, Python, Java, CSS 중 선택버튼 클릭 시 필터링된 스니펫 로드
자동 들여쓰기Enter 시 다음 줄 공백 자동 입력정규식으로 공백 감지 후 자동 추가
스킵 기능마음에 안 드는 코드 건너뛰기새로운 랜덤 스니펫 선택
한글 표시속도를 “200타”로 표시CPM 계산 후 “타” 문자 추가

7. 기술 스택

graph LR
    A[React] --> B[상태 관리 & UI]
    C[Framer Motion] --> D[애니메이션]
    E[TypeScript] --> F[타입 안정성]
    G[Tailwind CSS] --> H[스타일링]
    
    B --> I[TypingGame 컴포넌트]
    D --> I
    F --> I
    H --> I

💡 배운 점

이 프로젝트를 만들면서 배운 것들:

  1. React의 상태 관리: 여러 상태가 서로 어떻게 영향을 주는지 이해
  2. 실시간 UI 업데이트: useEffectsetInterval을 활용한 동적 화면 갱신
  3. 사용자 경험(UX): 자동 들여쓰기 같은 작은 기능이 큰 차이를 만듦
  4. 정규식 활용: 공백 감지에 정규식 ^ + 사용

🚀 앞으로의 계획

지금은 간단한 프로토타입이지만, 앞으로 이런 기능들을 추가해보고 싶습니다.

  • 사용자 커스텀 스니펫: 내가 연습하고 싶은 코드를 직접 등록
  • 언어별 리더보드: 누가 가장 빠른지 경쟁
  • 통계 그래프: 시간대별 타자 속도 변화 추이
  • Vim 모드: hjkl로 이동하며 수정하기 (이건 좀 어렵겠네요 😅)

재미있게 즐기셨다면 댓글로 최고 기록을 공유해주세요!