[4주차 크루 미션 - 최종 발표 & 회고] ellipsis 미션 제출합니다.#20
Conversation
다나와 크롤러 데이터 기반 키보드 추천 웹앱(Vite+React+TS) 이관. node_modules/dist/.env.local 등 빌드 산출물과 실제 키 파일은 제외하고 .env.local.example만 포함. README 경로를 impl 기준으로 갱신.
추천 정확도 저하(제약 무시·의도 빗나감)를 고치기 위한 태그 파이프라인 전환 요구사항을 Seed로 명세. LLM은 태그 추출만, 검색/스코어링/결과는 빌드 시 1회 생성한 정적 규칙표로 결정론 처리. 하드 제약 위반 0건 단위테스트 + 의도 골드셋으로 검증. (ooo interview/seed, fallback QA 0.92)
- tagSchema.ts: HARD_NUMERIC_KEYS, HARD_ENUM_KEYS, HARD_CONSTRAINT_KEYS, HARD_CONSTRAINT_ENUMS, SOFT_INTENT_VOCAB 상수 정의 및 export - isSoftIntentTag / isHardConstraintKey / isValidHardEnumValue 런타임 검증 헬퍼 포함 - tagSchema.test.ts: 28개 단위 테스트 (키 목록, 열거형 값, 중복 없음, 헬퍼 동작 검증) - vitest devDependency 추가, npm test 스크립트 설정
스키마 상수 기반으로 임의 객체의 태그 스키마 준수 여부를 검증하는 validateTagSchema 함수 구현. - 최상위 알 수 없는 키, hardConstraints 미지원 키, 열거형 허용 외 값, 숫자 키 타입 오류, softIntentTags 어휘 외 값 감지 - 복수 오류 한 번에 수집하는 방식으로 구현 - 유효/무효 케이스 총 20개 단위 테스트 추가 (전체 47개 통과)
자유형 자연어를 LLM에 전달해 hardConstraints + softIntentTags 구조의 ExtractedTags를 반환하는 extractRawTags() 함수를 구현한다. - extractRawTags.ts: AnthropicClient 주입 구조로 테스트 격리 지원, 스키마 밖 키/값은 parseAndSanitize에서 폐기, 비정상 JSON 안전 처리 - extractRawTags.test.ts: LLM 호출을 _setClientForTest로 모킹, hardConstraints/softIntentTags 키 존재 확인, 스키마 외 값 폐기 등 19개 테스트
extractRawTags의 출력(unknown)을 받아 스키마 밖 키/값을 제거하고 정제된 ExtractedTags를 반환하는 sanitizeTags(raw: unknown) 구현. - 최상위 hardConstraints/softIntentTags 외 키 무시 - HARD_CONSTRAINT_KEYS 밖 hardConstraints 키 제거 - 열거형 키의 HARD_CONSTRAINT_ENUMS 밖 값 제거 - 숫자 키에 number 외 타입 값 제거 - SOFT_INTENT_VOCAB 밖 softIntentTags 항목 제거 - 비정상 입력(null/배열/문자열) 안전 처리 - 알 수 없는 키 제거 / 잘못된 열거형 폐기 / 유효한 값 보존 검증 27개 테스트 추가 (전체 93개 통과)
- extractRawTags -> sanitizeTags -> validateTagSchema 순서 파이프라인을 실행하는 extractAndValidateTags(input: string) 함수를 extractRawTags.ts에 추가 - validateTagSchema 실패 시 오류를 throw하도록 구현 - sanitizeTags가 스키마 밖 값을 폐기하므로 정상 조건에서 항상 유효한 출력 보장 - extractRawTags.ts의 tagSchema 임포트에 validateTagSchema 추가 - extractAndValidateTags.test.ts: LLM 모킹으로 23개 통합 단위 테스트 추가 (정상 응답, 스키마 밖 값 폐기 후 통과, 비정상 JSON 안전 처리, 출력 구조 보장)
- src/lib/hardFilter.ts: 레이아웃 하드 제약 위반 판정 함수 구현 - layoutTag 없음(빈 문자열) -> false(제약 없음) - keyboard.layout과 layoutTag 일치 -> false(통과) - 불일치 -> true(위반) - src/__tests__/hardFilter.test.ts: 17개 단위테스트 - 6개 레이아웃 값 일치 케이스(false) - 8개 불일치 케이스(true) - 3개 제약 없음 케이스(false) - 전체 테스트: 133개 통과 (기존 116개 + 신규 17개)
- softTagRules.ts: SOFT_INTENT_VOCAB 24개 태그 전체를 커버하는 정적 규칙표 생성 - 태그별 AttributePredicate(field/op/value) 술어 매핑 - checkRuleTableCompleteness 함수 구현 - softTagRules.test.ts: 19개 단위 테스트 추가 - 정적 규칙표 구조 무결성 검사 (7개) - 현재 규칙표 완전성 검증 - 누락 0건 확인 (2개) - 누락 태그 감지 시나리오 (6개): 빈 규칙표/특정 태그 누락/predicates 빈 배열 - 경계 케이스 (3개): 빈 vocab/중복 엔트리/순서 보장 전체 152개 테스트 통과 (기존 133개 + 신규 19개)
hardFilter.ts에 checkSwitchViolation(keyboard, switchTag) 함수 추가. 일치->false, 불일치->true, 빈 문자열->false(제약 없음) 케이스 18개 테스트.
guidedInputMapper 모듈을 추가하고 단위 테스트 51개 작성. LLM 호출 없이 결정론적으로 동작하는 순수 함수로 구현: - mapBudgetToConstraints: 예산 범위 -> price_min/price_max - mapConnectionToConstraints: 연결방식 선택지 -> connection/wireless_type - mapLayoutToConstraints: 크기 선택지 -> layout (매핑 불가 선택지는 하드 제약 미생성) - mapEngravingToConstraints: 각인 선택지 -> engraving - mapBacklightToConstraints: 백라이트 선택지 -> backlight - mapKeyFeelToConstraints: 키감 선택지 -> switch_type - guidedAnswersToHardConstraints: 전체 answers+budget 통합 변환 전체 테스트 221개 통과
폼팩터 하드 제약 위반 판정 함수(checkFormFactorViolation)를 hardFilter.ts에 추가하고, 19개 단위테스트를 작성했다. - 일치 시 false(6케이스), 불일치 시 true(9케이스), 태그없음 시 false(4케이스) - 전체 테스트 240개 통과 (기존 221개 + 신규 19개)
Sub-AC 3-2-a: extractDatasetSchema(keyboards) 함수 추가 - Keyboard[] 입력 -> Record<속성명, Set<값>> 반환 - getFieldValues / hasField / hasValue 헬퍼 함수 포함 - 단위 테스트 39개 작성 (빈 배열, 속성명 목록, 값 추출, 중복 제거, 실제 샘플 검증 등) - 전체 279개 테스트 통과
- hardFilter.ts에 checkBudgetViolation(keyboard, budgetTag) 추가 - budgetTag <= 0: 제약 없음으로 간주하여 false 반환 - keyboard.price > budgetTag: 위반(true) - keyboard.price <= budgetTag: 통과(false), 경계값 포함 - hardFilter.test.ts에 13개 테스트 케이스 추가 - 가격 < 상한, 가격 = 상한(경계값), 가격 > 상한, budgetTag <= 0 시나리오 포함 - 전체 292개 테스트 통과
- datasetSchema.ts에 findInvalidFieldNames 함수 추가 - 규칙표 술어의 모든 field 이름 수집 후 스키마 맵과 대조 - 스키마에 없는(무효) 속성명을 중복 없이 반환 - PredicateRuleEntry 제네릭 인터페이스로 순환 의존 없이 SoftTagRuleEntry 호환 - datasetSchema.test.ts에 findInvalidFieldNames 단위 테스트 9건 추가 - 모두 유효: 빈 배열 반환 검증 - 모두 무효: 전체 반환 검증 - 유효/무효 혼재: 무효 속성명만 정확히 탐지 - 중복 field: Set 기반 중복 제거 보장 - 빈 규칙표/빈 스키마 경계 케이스 처리 - 전체 테스트 301개 통과 (기존 292개 + 신규 9개)
- guidedInputMapper에 소프트 태그 전용 상수 추가 (PURPOSE_OPTIONS, PORTABILITY_OPTIONS, SOUND_OPTIONS, KEY_FORCE_OPTIONS) - 소프트 전용 단계 매핑 함수: mapPurposeToSoftTags, mapPortabilityToSoftTags, mapSoundToSoftTags, mapKeyForceToSoftTags - 하드 제약 단계의 소프트 태그 보완 함수: mapKeyFeelToSoftTags, mapLayoutToSoftTags, mapConnectionToSoftTags, mapBacklightToSoftTags, mapEngravingToSoftTags - guidedAnswersToSoftTags 통합 함수 (중복 제거 포함) - guidedSoftTagMapper.test.ts: 소프트 태그 매핑 단위 테스트 75개 추가 - 모든 매핑 함수는 LLM 호출 없는 동기 순수 함수, 전체 376개 테스트 통과
- HardTag 타입 정의: type(판별자) + value(제약값) 구조 - checkHardConstraintViolation 함수 구현: - 'layout' -> checkLayoutViolation (Sub-AC 4-1-1) - 'switch_type' -> checkSwitchViolation (Sub-AC 4-1-2) - 'form_factor' -> checkFormFactorViolation (Sub-AC 4-1-3) - 'price_max' -> checkBudgetViolation (Sub-AC 4-1-4) - 알 수 없는 유형 -> false (안전한 기본값) - 디스패처 단위테스트 추가 (6개 describe, 30개 케이스): 라우팅 정확성, 직접 호출과의 결과 동일성, 알 수 없는 유형, 복합 시나리오
- datasetSchema.ts에 findRulesWithInvalidValues 함수 추가 - 속성명이 스키마에 존재하는 경우에 한해 허용 값 집합 밖 값을 참조하는 규칙 반환 - eq 술어: 스키마 값 집합에 정확히 포함되는지 검사 - contains 술어: 스키마 값 중 하나라도 부분 문자열로 포함하는지 검사 - lte/gte 술어: 수치 비교 임계값이므로 검사 대상에서 제외 - 속성명이 스키마에 없으면 해당 술어는 검사 범위 아님(findInvalidFieldNames 담당) - PredicateWithValue, RuleEntryWithValues 제네릭 인터페이스 추가 - datasetSchema.test.ts에 19개 단위 테스트 추가 (총 421개 통과)
keyboards 배열과 hardTags 배열을 받아 모든 하드 제약을 만족하는 키보드만 반환하는 filterByHardConstraints 함수 구현 (Sub-AC 4-2). - hardFilter.ts: filterByHardConstraints 추가 (checkHardConstraintViolation 기반) - hardFilter.test.ts: filterByHardConstraints 단위테스트 5개 describe 블록 추가 - 빈 태그 배열 / layout 단일 / price_max 단일 / 복합(layout+price+switch) / violations===0 보장 - 전체 테스트 434개 통과 (기존 401개 + 신규 33개)
- TagSet 인터페이스 추가 (hard: HardConstraints, soft: SoftIntentTag[])
- dispatchStepToTagSet(stepIndex, value): 0-9 단계 번호와 선택값을 받아
하드/소프트 매핑 함수에 라우팅하고 TagSet 반환
- STEP_ID_TO_INDEX 테이블 및 dispatchStepIdToTagSet 헬퍼 추가
- 예산 단계(7)는 { min, max } range 입력, 나머지 string 입력 처리
- 타입 불일치/알 수 없는 단계 -> { hard: {}, soft: [] } 안전 반환
- LLM 호출 없이 결정론적 동작
- 10단계 전체 시나리오 단위 테스트 (stepDispatcher.test.ts) 추가
- 전체 511개 테스트 통과
하드 제약 필드 누락/타입 오류/소프트 의도 필드 누락 케이스를 명시적으로 커버 - hardConstraints: null, [], string 타입 오류 검증 - price_min 숫자/문자열 검증 - softIntentTags: null, 숫자 요소, null 요소 검증 - 각 필드 누락 시 상대 필드 오류 미발생 확인 tagSchema.test.ts: 47 -> 57개 테스트 (전체 521개 통과)
… 테스트 작성
- guidedInputMapper에 selectionOptionConverter 함수 추가
- guidedAnswersToHardConstraints + guidedAnswersToSoftTags를 ExtractedTags 인터페이스로 통합
- 자유형 자연어 경로(extractRawTags)와 동일한 { hardConstraints, softIntentTags } 반환
- LLM 호출 없이 결정론적으로 동작
- selectionOptionConverter.test.ts 신규 작성 (Sub-AC 2-2b)
- 출력 구조 보장: hardConstraints(객체) + softIntentTags(배열) 항상 존재
- validateTagSchema 통과 검증: 빈/부분/전체 입력 + 대표 시나리오 8개
- 하드 제약 단계 단일 입력 15케이스 스키마 통과 확인
- 소프트 전용 단계 7케이스 스키마 통과 확인
- 예산 입력 4케이스 스키마 통과 확인
- softIntentTags 항목이 모두 SOFT_INTENT_VOCAB에 속함 검증
- 결정론성: 동일 입력 -> 항상 동일 출력
- LLM 호출 없는 동기 순수 함수 확인
전체 583개 테스트 통과
선택 변환 태그(selectionOptionConverter)와 자유형 태그(sanitizeTags 시뮬레이션)가 동일한 하드 제약을 표현할 때 filterByHardConstraints 결과가 일치함을 검증하는 24개의 단위 테스트를 작성한다. - layout(텐키리스/미니/풀배열) 단일 제약 동일성 검증 - switch_type(기계식/무접점) 단일 제약 동일성 검증 - price_max 단일 제약 동일성 검증 - 복합 제약(layout + switch_type + price_max) 동일성 검증 - 빈 제약, 불가능한 제약(결과 0건) 경우 검증 - 소프트태그 차이가 하드 필터 결과에 영향 없음 검증 - 1800배열 선택 시 layout 하드 제약 없음 동일성 검증 - 8개 시나리오 테이블 기반 통합 검증 - hardConstraintsToHardTags 변환 헬퍼를 테스트 내부에 정의 - 모든 결과에서 violations === 0 단언 포함
- softScorer.ts: SOFT_TAG_RULE_TABLE 기반 결정론 스코어링 함수 구현
- evaluatePredicate: 속성 술어 평가 (eq/contains/lte/gte)
- scoreBySoftTags: 키보드별 점수 벡터 산출 (LLM 없이 순수 함수)
- deriveRankOrder: 점수 벡터 -> 순위 배열 변환
- softScoreParity.test.ts: 40개 단위 테스트 추가
- 선택 경로(guidedAnswersToSoftTags) 소프트태그와
자유형 경로(sanitizeTags 시뮬레이션) 소프트태그를
scoreBySoftTags에 전달했을 때 스코어 벡터가 일치하는지 검증
- 7개 의도 시나리오: 사무용+조용함, 게이밍+RGB, 무선+미니+휴대성,
기계식+타건감+경쾌함, 무접점+조용함, 가성비+풀배열, 복합 전체 단계
- 결정론성, 태그 순서 무관 점수 동일, 순위 배열 일치 검증
- 전체 647개 테스트 통과
코드 리뷰(PR #21) 피드백 반영. - recommend.ts: 클라이언트 sanitizeExtraction의 hardConstraints가 단순 캐스트라 키별 타입·값 검증이 빠져 2중 방어가 무력했다. extractRawTags의 sanitizeTags를 재사용해 숫자/열거형 검증을 거치도록 수정(softIntentTags도 함께). - index.ts(Edge Function): parseExtractJson이 JSON.parse SyntaxError를 던져 500으로 떨어지던 문제를 null 폴백으로 변경 → sanitizeExtraction이 빈 추출로 graceful degrade. - index.ts: 추출 프롬프트에서 사용자 쿼리의 큰따옴표를 이스케이프해 프롬프트 구조 파손 가능성 제거. - 테스트 규약: guided 경로 LLM 미호출 불변식을 recommendLlmNoCall.test.ts로 분리 (*LlmNoCall.test.ts 규약 준수). recommendTop3는 포인터 주석만 남김. - vocabularyParity.test.ts 추가: Edge Function vocabulary.ts 사본과 프론트 tagSchema/intentProfile 어휘 드리프트를 CI에서 감지. - AGENTS.md: 결정론 하네스 UI 배선 반영. 현행 프로덕션 경로(Edge Function OpenAI 태그추출 + 클라 결정론 검색)와 레거시(Edge Function 전체 추천 생성, 클라 claude 추출)를 구분하도록 아키텍처 섹션 갱신.
feat(keybuddy): 결정론 의도 하네스 UI 연결 및 추천 점수순 상위 3개 제한
추천 가설 검증용 데이터를 모으기 위해 두 가지 사용자 행동을 Supabase에 적재한다(실결제 없음).
- events 테이블 마이그레이션: 단일 events(id, event_type, session_id, payload jsonb, created_at) + anon insert-only RLS
- lib/session.ts: 로그인 없는 익명 세션 UUID(localStorage)
- lib/events.ts: purchase_click('구매하기' 클릭, payload product_code)·rating(추천 전체 별점) 이벤트를 PostgREST /rest/v1/events로 직접 insert. best-effort라 실패는 삼켜 UX를 막지 않음
- App.tsx: 구매하기 버튼·별점 클릭에 계측 연결(토스트/링크 동작은 그대로)
- events.test.ts: payload 형태·PostgREST 요청/실패 동작 단위검증(9 케이스)
- 문서: AGENTS.md 이벤트 수집 경로·스위트 수, README 마이그레이션 적용·수동 확인 절차
단계별 선택 결과 완화 제거
YouTube 타건 영상 링크 수집 기능 추가
feat(switch_catalog): 키보드 스위치 데이터 추가
fix: 비기계식 키보드 레벨미터 고정
…ction feat(keybuddy): 구매 클릭·추천 별점 Supabase 이벤트 수집
Co-authored-by: first-woosun <dbdntjs620@gmail.com>
PR #20 충돌 해소. committhekermit(3주차 제출 스냅샷)은 ellipsis의 옛 버전이라 가져올 고유 변경이 없어 결과 트리를 ellipsis 최신본 그대로 유지한다(-s ours).
Keep
Problem
TRY
팀이 다음에 가져갈 1가지
|
malibinYun
left a comment
There was a problem hiding this comment.
최종 발표까지 정말 고생 많으셨어요.
제가 알림이 안와서 너무 늦게 봐버렸네요.. 죄송해요.
더 이야기 나누고 싶은 게 있거나, 제 의견이 더 궁금한 점들이 있다면 코멘트로 남겨주세요.
슬랙 방에다 말씀해주셔도 좋아요.
| - 처음에는 문제 정의를 너무 가볍게 생각했다. 인터뷰 결과 우리가 세운 가설은 깨졌으며, 우리가 생각한 문제는 사용자들이 문제라고 인식하지 않았다. 그래서 아이디어를 피봇하였다. | ||
| - 사용자들은 본인이 원하는 키보드를 찾는데 불편함을 겪었고 우리가 세운 가설과 문제를 지지받을 수 있었다. |
There was a problem hiding this comment.
내가 만든 걸 어쨌든 팔기 위해서는 결국 쓰는 사람, 고객이 중요하죠.
고객의 목소리에 귀기울이고 피봇한 것 굉장히 쉽지않지만 멋진 결정이라 생각해요.
| > 초기엔 태그 chip을 통한 단어 중심 정보로 제작하려 했으나, 두 값 모두 “강도”와 관련된 필드여서 단어만으로 사용자가 어떤 느낌인지 파악하는데 한계가 있을 것이라고 판단해 레벨미터를 사용해 조금 더 시각적인 정보를 제공하고자 구현 방향을 변경함 | ||
| > | ||
| - 해당 키보드의 유튜브 영상 링크 | ||
| - Youtube Data API v3 콜을 통해 영상 링크 수집 | ||
|
|
||
| > 타건음을 태그 chip을 사용해 의서어로 제공하려 했으나, 소리의 경우 사람마다 다르게 받아들일 수 있겠다고 판단해 억지로 의성어를 제공하는 것 보단 동영상을 통해 사용자가 직접 판단하는 것이 더 좋겠다고 판단해 의성어 chip을 제거하고 영상 링크를 제공 | ||
| > |
There was a problem hiding this comment.
판단에 대한 근거를 좀 더 써보는 건 어떨까요?
위 항목에서는 피드백을 통해 반영했던 것 처럼요.
There was a problem hiding this comment.
위 내용들의 경우 모두 “사용자의 감각”에 관련된 요소들로 단순히 태그로만 표현되면 제공된 정보를 봤을 때 직관적으로 이해되지 않을 것 같다는 피드백이 있었습니다.
“걸림”의 경우 여러 종류의 키보드를 타건해본 경험이 없는 사용자의 경우 걸림이라는게 어떤 느낌인지 조차 인식되어있지 않은 경우가 많았고, 소음의 경우에도 단순히 “조용함”, “보통”, “시끄러움”등으로 나타낼 경우 타건 소리가 얼마나 큰지 잘 안 와 닿을 것 같다는 피드백이 있었습니다.
따라서 단순히 단어로만 표시하는 것 보다, 좀 더 시각적인 정보로 제공해 사용자의 이해를 돕고자 레벨미터의 형태를 채택했습니다.
타건 소리 의성어 태그의 경우에도 위와 마찬가지로 사용자의 감각적 주관에 크게 의존하는 정보라고 생각했습니다. 다만 이 부분은 어떤 피드백을 받고 변경된 것이 아닌 제작과정에서 든 의문과 그 의문이 결과물에 반영된 결과입니다.
동일한 키보드 타건 소리에 대해 어떤 사람을 “보글보글”이라고 느끼고, 어떤 사람은 “부글부글”이라고 느낀다고 가정해보겠습니다. 이 때 서비스를 제공하는 측에서 “보글보글”이라는 의성어로 픽스해 제공한다면 “부글부글”이라고 느낀 사용자의 입장에서 “이건 부글부글 아닌가? 이 서비스 이상하네?”라는 부정적 경험으로 이어질 수 있겠다고 생각했습니다.
물론 의성어 태그만 제공했을 때의 사용자 경험이 어떤지와 타건 영상을 제공했을 때, 두 정보 모두 제공했을 때의 사용자 피드백을 수집했다면 서비스 운영에 유의미한 데이터를 뽑아낼 수 있는 부분인 것 같은데, 실패 경험을 회피했다는 점에서 아쉬움이 남는 부분입니다.
There was a problem hiding this comment.
위 내용을 바탕으로 그러한 피드백 기반으로 이러이러해서 변경햇다~ 이런식으로 문서를 개선하시면 좋겠네요!
| - 파이어베이스 | ||
| - 서버 운영 부담을 최소화하기 위해서 사용하려 하였습니다. | ||
| - 수파베이스 | ||
| - 파이어베이스와 제공하는 기능이 크게 다르지 않고, 서버 운영 비용을 최소화할 수 있어 선택하였습니다. |
There was a problem hiding this comment.
조금 더 이유가 구체적이면 좋겠는걸요. 제가 생각하는 파이어베이스의 가장 강점은 무료 사용량이 매우 많은 거라 생각해요. 짧은 시간 내 높은 트래픽을 처리하긴 어렵지만요.
There was a problem hiding this comment.
Firebase의 가장 큰 장점은 무료 사용량이 넉넉하다는 점이라고 생각합니다. 실제로 Firebase Spark Plan은 결제수단 없이 사용할 수 있고, Firestore도 일 단위 읽기/쓰기 무료 한도, Cloud Functions도 월 호출 무료 한도를 제공합니다. 그래서 초기 MVP나 짧은 기간의 실험 서비스에는 Firebase가 비용 측면에서 매우 유리하다고 판단하였습니다.
다만 KeyBuddy에서는 단순히 무료 사용량보다 데이터 구조와 이후 확장성을 더 중요하게 봤습니다. 저희 서비스는 키보드 catalog를 조건별로 필터링하고, 추천 결과와 사용자 이벤트를 구조화해서 다뤄야 했기 때문에 문서 기반 NoSQL보다 PostgreSQL 기반의 관계형 모델이 더 잘 맞았습니다. Supabase는 PostgreSQL을 그대로 사용하므로 SQL 쿼리, 테이블 구조, RLS 정책을 명확하게 설계할 수 있다는 장점이 있었습니다.
또한 Firebase는 Google Cloud 생태계와 강하게 결합되어 있어 Firestore,Firebase Auth, Cloud Functions 중심으로 구현하면 이후 다른 환경으로 옮길 때 데이터 모델과 인증 흐름, 함수 배포 방식을 다시 설계해야 할 가능성이 큽니다. 반면 Supabase는 PostgreSQL 기반이고 self-hosting 옵션도 제공하기 때문에, 장기적으로는 특정 벤더에 대한 종속을 조금 줄일 수 있다고 판단했습니다.
Edge Functions 측면에서도 Supabase는 Deno 기반 TypeScript 함수를 전 세계 edge에 배포할 수 있고, 로컬 실행 및 Deno 호환 환경으로의 이식 가능성을 제공합니다.
| - 파이어베이스 사용 → 수파베이스 사용 | ||
| - 파이어베이스에서는 Blaze 요금제로 바꿨을 때 서버 운영 비용이 발생하나, 수파베이스에서는 서버 운영 비용이 발생하지 않아 서버 운영 비용을 최소화할 수 있어 변경하였습니다. | ||
| - 공통 하네싱 | ||
| - 코드 컨벤션, 깃 컨벤션, PR 포맷 컨벤션, 브랜치 컨벤션 등등 공통으로 작업할 내용에 하네싱이 필요했는데 이 부분에서 놓친 점이 많아, 사람과 AI에 불필요한 혼동을 줬다고 생각합니다. |
There was a problem hiding this comment.
깃, PR 포맷, 브랜치 컨벤션은 정말 필요한 하네스였을까요?
그만큼 정밀했어야했는지요. 이런 경우 필요한 하네스는 무엇이었을지 고민해보는 것도 좋은 고민이란 생각이 들어요.
There was a problem hiding this comment.
이번 프로젝트를 돌아보면, 에이전트의 작업과 코드의 흐름을 잘 따라 가고 있었는가? 하고 질문을 던지자면 그렇지 않았다고 생각합니다. 전체적인 흐름은 잘 알고 있으나, 어떻게 태그를 추출했는지? 어떻게 추천을 하는지? 큰 흐름은 설명할 수 있지만 세부적인 흐름은 잘 모른다고 생각합니다.
대AI 시대에 "몇번째 줄에 어떠한 코드가 있다" 정도는 아니더라도, "이 기능은 이러한 흐름으로 작동한다."를 잘 설명할 수 있어야 한다고 생각합니다. 그렇기에 AI를 사용해 개발을 했더라도, 흐름을 잘 따라가기 위해서라면 "PR은 손으로 작성해야겠다."라는 생각이 들었습니다. 이처럼 에이전트의 흐름을 따라가기 위해서 직접 읽고 직접 쓰는 부분이 많아야겠다라는 생각입니다.
깃 컨벤션 하네싱은 PreToolUse 하네싱을 통해서 할 수 있습니다. 정확히는 Bash Tool을 사용하기 전에 내가 정해진 포맷을 주입할 수 있습니다. 기존에는, Skill이나 MEMORY를 통해서 하네싱을 달성하려고 했는데, Skill은 항상 발동된다고 보장하기 어렵고 메모리는 Advisory 성격이 강해, 문맥이 너무 길어지면 클로드가 듣지 않는 경우가 있어 항상 규칙을 준수한다고 보장하기 어렵습니다.
그렇기에, git 명령어를 사용할 때 내가 원하는 포맷을 강제하도록 하고 만약 포맷을 따르지 않았다면 아예 에이전트 흐름을 Stop되게 하려고 합니다.
There was a problem hiding this comment.
"이 기능은 이러한 흐름으로 작동한다를 잘 설명할 수 있어야 한"다 했을 때, PR을 손으로 작성하는 것과 어떤 연관이 있나요?
설계자체는 사람끼리 하고, ai의 도움을 받으면서, 그 결정과 내용들을 잘 담아서 ai에게 정리시키고, 그 정리된 문서를 팀원들이 다시 검토하고 하는 것은 어떨까요?
설계문서만 있으면 구현은 ai가 금방 해내니까요.
설계한 걸 까먹는 건 저처럼 청년 치매를 극복해야하는 문제가 될지도요..
| - 파이어베이스 사용 → 수파베이스 사용 | ||
| - 파이어베이스에서는 Blaze 요금제로 바꿨을 때 서버 운영 비용이 발생하나, 수파베이스에서는 서버 운영 비용이 발생하지 않아 서버 운영 비용을 최소화할 수 있어 변경하였습니다. | ||
| - 공통 하네싱 | ||
| - 코드 컨벤션, 깃 컨벤션, PR 포맷 컨벤션, 브랜치 컨벤션 등등 공통으로 작업할 내용에 하네싱이 필요했는데 이 부분에서 놓친 점이 많아, 사람과 AI에 불필요한 혼동을 줬다고 생각합니다. |
There was a problem hiding this comment.
깃, PR 포맷, 브랜치 컨벤션은 정말 필요한 하네스였을까요?
그만큼 정밀했어야했는지요. 이런 경우 필요한 하네스는 무엇이었을지 고민해보는 것도 좋은 고민이란 생각이 들어요.
There was a problem hiding this comment.
이번 프로젝트를 돌아보면, 에이전트의 작업과 코드의 흐름을 잘 따라 가고 있었는가? 하고 질문을 던지자면 그렇지 않았다고 생각합니다. 전체적인 흐름은 잘 알고 있으나, 어떻게 태그를 추출했는지? 어떻게 추천을 하는지? 큰 흐름은 설명할 수 있지만 세부적인 흐름은 잘 모른다고 생각합니다.
대AI 시대에 "몇번째 줄에 어떠한 코드가 있다" 정도는 아니더라도, "이 기능은 이러한 흐름으로 작동한다."를 잘 설명할 수 있어야 한다고 생각합니다. 그렇기에 AI를 사용해 개발을 했더라도, 흐름을 잘 따라가기 위해서라면 "PR은 손으로 작성해야겠다."라는 생각이 들었습니다. 이처럼 에이전트의 흐름을 따라가기 위해서 직접 읽고 직접 쓰는 부분이 많아야겠다라는 생각입니다.
깃 컨벤션 하네싱은 PreToolUse 하네싱을 통해서 할 수 있습니다. 정확히는 Bash Tool을 사용하기 전에 내가 정해진 포맷을 주입할 수 있습니다. 기존에는, Skill이나 MEMORY를 통해서 하네싱을 달성하려고 했는데, Skill은 항상 발동된다고 보장하기 어렵고 메모리는 Advisory 성격이 강해, 문맥이 너무 길어지면 클로드가 듣지 않는 경우가 있어 항상 규칙을 준수한다고 보장하기 어렵습니다.
그렇기에, git 명령어를 사용할 때 내가 원하는 포맷을 강제하도록 하고 만약 포맷을 따르지 않았다면 아예 에이전트 흐름을 Stop되게 하려고 합니다.
| - 끝까지 검증 못 한 가설이 있다면 그 사실 그대로 | ||
| - 자연어 입력이 사용자에게 편한 방법일까? | ||
| - 자연어 입력을 통하여 정말로 사용자의 취향을 반영한 키보드가 추천될까? No newline at end of file |
There was a problem hiding this comment.
이 가설들도 나중에 검증해보기 위해서 어떤 것들을 지표삼아볼 수 있을지 정리해보는 것도 좋은 방법이란 생각이 드네요!
There was a problem hiding this comment.
저희가 제공하는 서비스에는
-
자연어 입력을 통한 검색
-
선택지 입력을 통한 검색
이 두가지 방식을 통해서 내가 원하는 키보드를 찾을 수 있도록 하고 있는데
이 두 방식 중에서 1번:자연어 입력을 통한 방식으로 검색하여 사용하는 비율이 높다면, “자연어 입력을 통한 검색이 사용자에게 편한 방법일 것이다.” 라는 결론을 낼 수 있을 것 같습니다.
한 세션 내에서 사용자가 자연어 검색을 통해서 키보드를 검색하는 횟수, 자연어 압력을 통한 검색을 사용하는 빈도 등의 데이터를 수집하여 지표로 삼을 수 있을 것으로 보입니다.만약 최초 검색 이후에 사용한 문구가 이전 검색과 동일한 의도를 가지고 재검색을 수행한다면 이것은 추천 결과가 만족스럽지 않았다는 것을 의미할 것 같습니다. 동일한 의도를 갖는지 여부는 입력된 자연어에서 추출한 태그들의 유사도를 분석하는 방법이 있을 것 같습니다.
설계와 구현을 잘 나누는 게 중요해보여요. 설계대로 잘 구현해냈는지에 대한 테스트, e2e 테스트 목록을 마련해서 그것을 모두 통과하는지 점검한다면 구현을 어떻게 했느냐는 사실 크게 중요하지 않아보여요. 분산 처리를 했다던지, 트래픽 감당을 위한 전략을 어떻게 했다던지, 실패에 대한 처리는 어떤식으로 마련되어있는지 등등.. 설계와 방향을 잘 정해둔다면 그것들을 어떻게 코드로 실제로 구현했는지는 이제는 중요하지 않은 시대가 왔다고 생각해요.
ADR을 잘 쌓아서 이것을 ai가 참조하도록 하는 것이 가장 좋지요. 문서를 여러곳에 분산하는 것도 장점이 있을 수 있지만, 아예 하나 (깃) 에서 관리하는 것도 나쁘지 않다고 생각해요. ai가 mcp나 툴을 활용해서 보는 것 보다는 로컬 문서를 보는 게 더 즉각적이니까요. 장단점이 뚜렷해서 상황에 맞춰서 잘 활용하면 좋겠어요. |
malibinYun
left a comment
There was a problem hiding this comment.
빠른 호흡의 프로젝트 진행하시느라 고생 많으셨어요.
중간에 아이디어 피봇까지 해서 더 힘들었을텐데 결국 완료까지 잘 하셨네요 👍
피드백은 이만 마무리 짓도록 하겠습니다.
그룹 DM 방 만들어놓은 것이나, 1:1 DM으로 언제든지 궁금한 점들 물어보셔도 좋으니 메시지 남겨주세요.
남은 3 4 레벨도 화이팅입니다 💪
bd9f35e
into
woowacourse:committhekermit
어느덧 마지막 PR이네요. 고생많으셨습니다~
4주차 보고서(수정)
A. 처음 의도 vs 결과
쉬운 용어 풀이 키워드
각 키보드별 주의할 사항
접점 방식, 스위치 설계에 따른 키감, 소음 레벨미터
해당 키보드의 유튜브 영상 링크
B. 가설 검증 종합