Node.js를 사용한 3주차 실습 및 미션 코드 이번 3주차에서는 백엔드 서버가 직접 데이터베이스와 통신하여 데이터를 조회하고 조작하는 실제 API를 구현했습니다. 또한 DTO나 ORM 기술을 배제하고 오직 순수 SQL(Raw SQL)만을 사용해 서버를 구축했습니다. Spring 환경이 익숙하기에 이번 Wil은 Node.js(NestJS) 환경을 기준으로 진행하였고 일르 Spring과 비교하였습니다. 1. 데이터베이스 커넥션 풀 설정의 차이 애플리케이션이 데이터베이스와 통신하기 위해서는 연결 통로인 커넥션 풀(Connection Pool)을 구성해야 합니다. 이 초기 세팅 과정에서 두 프레임워크의 차이가 드러났습니다. Spring Boot: 자동 구성(Auto-Configuration) Spring Boot는 application.yml 파일에 데이터베이스 접속 정보만 작성해 두면, 서버 구동 시 내부적으로 HikariCP 커넥션 풀과 이를 제어하는 JdbcTemplate 객체를 스프링 컨테이너에 자동 생성합니다. 개발자는 별도의 설정 클래스를 작성할 필요 없이 즉시 의존성을 주입받아 사용할 수 있습니다. NestJS: 커스텀 Provider 직접 조립 반면 모듈화가 강조된 NestJS에서 순수 SQL 드라이버( mysql2 )를 사용할 때는, 개발자가 직접 커넥션 풀을 생성하고 컨테이너에 등록하는 커스텀 Provider를 작성해야 합니다. [NestJS: 데이터베이스 Provider 작성] // src/database.provider.ts import { ConfigService } from '@nestjs/config'; import * as mysql from 'mysql2/promise'; export const DATABASE_CONNECTION = 'DATABASE_CONNECTION'; export const databaseProviders = [ { provide: DATABASE_CONNECTION, inject: [ConfigService], useFactory: (configService: ConfigService) => { // .env 환경변수를 읽어와 커넥션 풀을 직접 생성합니다. return mysql.createPool({ host: configService.get<string>('DB_HOST', 'localhost'), port: configService.get<number>('DB_PORT', 3306), user: configService.get<string>('DB_USER', 'root'), password: configService.get<string>('DB_PASSWORD', ''), database: configService.get<string>('DB_NAME', 'study'), waitForConnections: true, connectionLimit: 10, queueLimit: 0, }); }, }, ]; 작성한 Provider는 app.module.ts 의 providers 와 exports 배열에 등록해야만 전체 애플리케이션에서 주입받아 사용할 수 있습니다. 2. 3계층 아키텍처와 의존성 주입(DI) 방식 비교 Controller, Service, Repository로 역할을 분리하는 3계층 아키텍처의 기본 개념은 동일하지만, 계층을 선언하고 의존성을 주입하는 방식에 차이가 있습니다. 계층 선언 데코레이터/어노테이션 : Spring은 역할에 따라 @RestController , @Service , @Repository 로 세분화하여 명시합니다. NestJS는 @Controller() 를 제외한 Service와 Repository 모두 범용적인 @Injectable() 데코레이터를 사용하여 주입 가능한 클래스임을 명시합니다. 의존성 주입 방식 : Spring은 주로 Lombok의 @RequiredArgsConstructor 를 사용하여 private final 필드에 대한 생성자 주입을 자동으로 처리합니다. NestJS는 TypeScript의 생성자(Constructor) 문법을 통해 명시적으로 주입합니다. 특히 앞서 직접 만든 커넥션 풀과 같은 커스텀 Provider를 주입받을 때는 반드시 @Inject() 데코레이터를 지정해야 합니다. 3. API 구현 실습 1) 특정 카테고리 도서 목록 조회 API (GET) Path Variable을 통해 카테고리 ID를 전달받아 해당 카테고리의 도서를 조회하는 기능입니다. [NestJS: Repository 및 Controller 구현] // src/book.repository.ts import { Injectable, Inject } from '@nestjs/common'; import type { Pool } from 'mysql2/promise'; import { DATABASE_CONNECTION } from './database.provider'; @Injectable() export class BookRepository { constructor(@Inject(DATABASE_CONNECTION) private readonly pool: Pool) {} async findByCategoryId(categoryId: number): Promise<any> { const sql = 'SELECT * FROM book WHERE category_id = ?'; // 구조 분해 할당으로 순수 행 데이터만 추출 const [rows] = await this.pool.query(sql, [categoryId]); return rows; } } // src/book.controller.ts import { Controller, Get, Param } from '@nestjs/common'; @Controller('books') export class BookController { constructor(private readonly bookService: BookService) {} @Get('category/:categoryId') async getBooksByCategory(@Param('categoryId') categoryId: number): Promise<any> { return await this.bookService.getBooksByCategory(categoryId); } } 조회 쿼리 실행 차이 : Spring의 jdbcTemplate.queryForList() 는 곧바로 리스트 형태의 데이터를 반환하지만, NestJS의 pool.query() 는 결과 데이터와 메타데이터 필드를 배열 형태로 반환하므로 [rows] 와 같이 구조 분해 할당을 통해 실제 데이터만 추출해야 합니다. 경로 변수 처리 : Spring은 @PathVariable 을 사용하며, NestJS는 @Param() 을 사용하여 URL 경로의 값을 추출합니다. 2) 도서 대여 기록 생성 (POST) 및 반납 처리 (PATCH) SQL Injection 공격을 방어하기 위해 파라미터 바인딩 기법을 적용하여 데이터를 삽입하고 수정하는 과정입니다. [NestJS: Repository 구현] // src/rental.repository.ts @Injectable() export class RentalRepository { constructor(@Inject(DATABASE_CONNECTION) private readonly pool: Pool) {} // 미션 2: 신규 도서 대여 기록 생성 async createRental(body: Record<string, any>): Promise<any> { const sql = ` INSERT INTO rental (user_id, book_id, rented_at, due_at, returned_at) VALUES (?, ?, NOW(), DATE_ADD(NOW(), INTERVAL 7 DAY), NULL) `; // 파라미터 배열 바인딩 const [result] = await this.pool.execute(sql, [body.userId, body.bookId]); return result; } // 선택 미션: 도서 반납 처리 async returnBook(rentalId: number): Promise<any> { const sql = 'UPDATE rental SET returned_at = NOW() WHERE rental_id = ?'; const [result] = await this.pool.execute(sql, [rentalId]); return result; } } 데이터 조작 쿼리 실행 차이 : Spring은 jdbcTemplate.update() 메서드에 파라미터를 가변 인자로 나열하여 전달합니다. 반면 NestJS는 보안과 성능을 위해 pool.execute() 메서드를 사용하며, 치환될 파라미터들을 두 번째 인자로 배열 형태로 묶어서 전달합니다. 요청 본문 처리 : 클라이언트의 JSON Body를 받을 때 Spring은 @RequestBody Map<String, Object> 를 사용하는 반면, NestJS는 @Body() Record<string, any> 타입을 사용하여 처리했습니다. 4. 한계 확인 이번 실습에서는 DTO 설정 없이 클라이언트의 요청( Record<string, any> )을 그대로 받아 데이터베이스에 삽입했습니다. 이 과정을 직접 수행해 보며 다음과 같은 치명적인 한계를 확인할 수 있었습니다. 타입 안정성의 부재 : 클라이언트 측에서 userId 를 오타로 잘못 입력하여 전송하더라도, TypeScript 컴파일러나 프레임워크 레벨에서 이를 사전에 차단하지 못했습니다. 결국 잘못된 키워드가 그대로 쿼리에 매핑되어 런타임 SQL 에러가 발생했습니다. 하드코딩으로 인한 유지보수 저하 : INSERT INTO 구문에 들어갈 물음표의 순서와 매핑될 파라미터 배열의 순서를 눈으로 확인하며 맞춰야 했습니다. 테이블의 컬럼이 늘어날수록 치명적인 버그를 유발하기 쉬운 구조입니다. Node.js 환경에서의 수동적인 설정 과정과 순수 SQL 작성의 불편함을 경험해 봄으로써, 다음주에 배울 ORM, DTO의 필요성을 체감할 수 있었습니다.
📚 기본 배경지식: 청킹(Chunking)이란? RAG(검색 증강 생성) 시스템을 만들 때, 수백 페이지짜리 책을 AI에게 통째로 주면 기억을 잘 못하거나 비용이 많이 듭니다. 그래서 책을 잘게 쪼개서 저장하는데, 이 쪼개는 과정을 청킹(Chunking) 이라고 합니다. 대표적인 방법 두 가지가 문제에 나왔습니다. 고정 창 청킹 (Fixed-window / Fixed-size Chunking): • 방식: 의미와 상관없이 무조건 글자 수나 토큰 수(예: 300글자씩)로 뚝뚝 자르는 방식입니다. • 장점: 속도가 매우 빠르고 컴퓨터 연산 비용이 거의 들지 않아 단순하고 예측 가능합니다. 시맨틱 청킹 (Semantic Chunking): • 방식: 문장들을 읽어 내려가다가 '이야기의 주제나 맥락이 바뀌는 지점(의미적 경계)' 을 찾아내어 유연하게 자르는 방식입니다. • 장점: 문맥이 중간에 끊기지 않아 이론적으로는 검색 품질이 더 좋아질 것이라 기대합니다. RAG 파이프라인 3단계 법칙 시험에서 시스템의 흐름(Pipeline)을 묻는 순서 배치나 역할 문제가 자주 나옵니다. • 1단계 (지식 베이스 분할): 대규모 문서를 인덱스에 저장/점수 매길 수 있도록 작은 조각(Chunk)으로 쪼갭니다. • 2단계 (임베딩 및 인덱싱): 각 청크를 숫자로 변환(Embedding)하여 저장(Index)합니다. • 3단계 (프롬프트 주입): 질문과 가장 관련 있는 청크를 뽑아 프롬프트에 주입(Context Grounding)하여 모델이 두뇌(메모리)가 아닌 주어진 본문에서 답변하게 만듭니다. • ⚠️ 시험 출제 포인트: "청킹은 후속 전체 프로세스의 천장(Ceiling)을 결정한다." 즉, 1단계(청킹)에서 데이터를 잘못 쪼개면 아무리 검색기나 LLM이 똑똑해도 오답을 냅니다. 많은 개발 팀이 "무조건 의미대로 쪼개는 시맨틱 청킹이 검색을 더 잘하겠지?"라고 착각(Assume)합니다. 하지만 대규모 벤치마크와 실제 연구 결과는 다릅니다. • 임베딩 품질의 중요성: 텍스트를 아무리 의미 있게 잘 쪼개도, 그 텍스트를 숫자로 변환해 주는 '임베딩 모델(Embedding Model)'의 지능(품질)이 낮으면 서로 관련 있는 내용을 찾아내지 못합니다. • 반대로, 훌륭한 임베딩 모델을 사용하면 약간의 텍스트 겹침(Overlap)을 둔 고정 창 청킹만 써도 시맨틱 청킹과 성능이 비슷하거나 오히려 더 안정적인 결과를 보여줍니다. 청킹 전략 자체보다 어떤 임베딩 모델을 썼느냐가 검색 품질을 좌우(Dominate)하는 경우가 대부분입니다. 청킹을 조절하는 3가지 노브 (Knobs) 아키텍처 설계 시 수치적 장단점(Trade-off)을 비교하는 문제로 출제됩니다. • 크기 (Size): 청크의 토큰 수 • 작게 쪼개면: 정밀도(Precision)가 높아져 좁은 범위의 질문에 강함. 대신 문맥이 끊김. • 크게 쪼개면: 주변 문맥을 잘 보존함. 대신 노이즈가 섞여 검색 신호가 희석(Dilute)됨. • 경계 (Boundary): 어디서 자를 것인가 • 고정 창(Fixed-window): 의미 무시, 정해진 토큰 수로 무조건 자름. • 시맨틱(Semantic): 문맥, 주제, 섹션이 바뀌는 지점을 찾아서 자름. • 오버랩 (Overlap): 앞뒤 청크 사이에 겹치게 두는 토큰 수 • 목적: 경계면에 걸쳐진 중요한 아이디어가 쪼개져 소실되는 것을 방지함. • 비용: 인덱스 저장 공간이 중복으로 늘어남. 3. [★가장 중요] 시험 단골 오답 함정과 진실 Anthropic(클로드 개발사)의 공식 가이드라인에 기반한 시험지 정답 단골 멘트들입니다. • ❌ 함정 선지: "시맨틱 청킹은 언제나 고정 창 청킹보다 뛰어난 검색 품질을 보장한다." • ⭕ 실제 정답: 고정 창 방식도 시맨틱과 비교할 만한(Comparable) 성능을 냅니다. 시맨틱은 비용이 많이 들고 튜닝이 어려우며, 노력 대비 얻는 이득이 적은 경우가 많습니다. • ⭕ 진실 (Priority): 임베딩 모델의 품질(Embedding Quality)이 청킹 전략보다 검색 품질을 지배(Dominate)합니다. 팀들이 성능 낮은 임베딩 모델을 쓰면서 청킹 방식만 고민하느라 시간을 낭비하는데, 이를 뒤집어(Flip) "똑똑한 임베딩 모델을 먼저 확보"하는 것이 핵심입니다. 4. 디버깅 및 트러블슈팅 용어 에러 상황이 주어지고 원인을 찾는 문제에 나오는 키워드입니다. • 파편화 문제 (Bare fragment problem): 청크 하나를 문서에서 떼어냈을 때 주변 맥락이 사라져 덩그러니 남는 현상. 질문이 누락된 맥락에 의존할 때 검색 품질을 떨어뜨림. • Recall at K: 상위 K개의 검색 결과 안에 진짜 관련된 청크가 얼마나 포함되어 있는지를 뜻하는 지표. 시스템 성능을 직관적으로 측정할 때 씀. 🎯 시험 합격을 위한 아키텍트의 표준 행동 지침 (Order of Method) 시험 문제에서 "새로운 지식 베이스를 구축할 때 아키텍트가 취해야 할 올바른 순서는?" 하고 물으면 이 순서를 고르세요. Baseline 구축: 단순하고 강력한 고정 창(Fixed-window) 방식으로 기준점을 잡는다. Overlap 추가: 경계면 데이터 손실을 막기 위해 적절한 오버랩을 설정한다. Embedder 투자: 청킹을 더 복잡하게 바꾸기 전에, 강력한 임베딩 모델을 도입한다. Measure (측정): 실제 쿼리를 던져 Recall at K 등의 지표(숫자)를 확인하고, 지표가 증명할 때만 시맨틱 청킹 등의 복잡성을 추가한다. (직관에 의존 금지) 콘텍스트 기반 검색(Contextual Retrieval)'**의 핵심 메커니즘 기술의 정의 및 개념 • Contextual Retrieval(콘텍스트 기반 검색): 텍스트를 쪼갠 각 청크(Chunk)가 전체 문서 내에서 어떤 위치와 의미를 가졌는지 설명하는 '짧은 콘텍스트 요약'을 작성하여, 청크 앞에 붙인(Prepend) 후 인덱싱하는 Anthropic의 독자적인 기술입니다. • Chunk Context Generation(청크 콘텍스트 생성): LLM을 사용해 각 조각이 원본 문서의 어느 위치에 속해 있는지 설명하는 약 50~100 토큰 내외의 짧은 설명을 자동으로 만들어내는 과정입니다. ⚠️ 시험에서 무조건 파고드는 '핵심 단서' (Timing) 시험 문제에서 아키텍처의 부하(Overhead)나 비용, 작동 타이밍을 묻는 보기가 나올 때 오답을 골라낼 수 있는 가장 중요한 포인트입니다. • 수행 시점은 무조건 '인덱싱 시간(Indexing Time)'입니다. • ❌ 시험 함정: "사용자가 질문을 던지는 실시간 검색(Query/Inference Time) 단계에서 각 청크의 콘텍스트를 생성한다." • ⭕ 진실: 질문을 받기 전, 지식 베이스(Knowledge Base)를 처음 구축하고 벡터 DB에 저장(Indexing)하는 시점에 미리 LLM을 돌려 콘텍스트를 붙여두는 것입니다. 이 기술이 해결하는 실전 아키텍처 문제 이 기술은 앞선 강의에서 언급된 '파편화 문제(Bare fragment problem)' 를 완벽하게 치료합니다. • 기존 문제점: 수백 페이지짜리 재무제표 문서에서 "2024년 2분기 순이익은 5% 증가했다"라는 한 줄을 뚝 떼어내어 청크로 만들면, 나중에 사용자가 "A회사의 2024년 2분기 순이익이 어때?"라고 물었을 때, 청크 자체에 'A회사'라는 단어가 없어서 검색기가 이 청크를 찾지 못하고 놓칩니다. • Contextual Retrieval의 해결책: 청크 앞에 [이 조각은 A회사의 2024년 재무제표 중 2분기 실적 발표 섹션에 포함된 내용입니다]라는 50~100 토큰짜리 배경 설명을 LLM이 미리 적어서 붙여줍니다. 덕분에 검색기가 핵심 키워드(A회사, 재무제표 등)를 쉽게 인식하고 정확하게 찾아올 수 있습니다. 🎯 시험 대비 핵심 요약 키워드 • 동작: 청크 앞에 50~100 토큰의 배경 설명을 Prepend(앞에 추가) 함. • 타이밍: 사용자가 질문할 때가 아니라, 데이터베이스를 만드는 Indexing Time(인덱싱 시점) 에 실행됨. • 효과: 컨텍스트가 단절된 파편화된 청크에 '문맥적 똬리(Anchor)'를 틀어주어 검색 정확도를 극적으로 향상시킴. 3단계 하이브리드 검색 적층(Stacking) 구조와 성능 지표 시험 문제에서 "Anthropic 가이드라인에 따라 하이브리드 검색 성능을 극대화하는 올바른 아키텍처 적층 방식은?" 또는 각 단계별 누적 효과를 묻는 연산형 문제가 출제됩니다. Anthropic은 검색 실패율 감소(Reduction in retrieval failure) 지표를 기준으로 설명합니다. • Layer 1: Contextual Embeddings (콘텍스트 기반 임베딩) • 설명: 배경 설명(Context)이 추가된 청크를 고차원 의미 매칭을 하는 밀집 벡터 인덱스(Dense Vector Index) 에 저장. • 성능: 단독 적용 시 검색 실패율 약 35% 감소. • Layer 2: Contextual BM25 (콘텍스트 기반 BM25) • 설명: 동일한 콘텍스트 강화 청크를 정확한 키워드/고유명사 매칭을 하는 희소 어휘 인덱스(Sparse Lexical Index) 에 중복 저장. • 성능: Layer 1과 결합 시(하이브리드) 실패율 약 49% 감소 (임베딩 단독 효과가 아님을 인지할 것). • Layer 3: Re-ranking (리랭킹) • 설명: 위 두 인덱스에서 넓게 뽑아온 후보군을 크로스 인코더(Cross-encoder) 리랭커 모델로 다시 정렬하여 최종 압축. • 성능: 전체 스택 완성 시 실패율 약 67% 감소. • ⚠️ 시험 출제 포인트: 이 수치들은 범용 상수가 아닌 Anthropic 자체 벤치마크 결과입니다. 시험에서는 "각 레이어는 독립적으로 도입 및 측정이 가능하며, 결합할수록 효과가 누적(Compound/Stacking)된다" 는 아키텍처적 본질이 정답으로 출제됩니다. 2. 경제성 및 지연 시간(Latency) 최적화의 핵심: 프롬프트 캐싱 시험에서 가장 많이 파고드는 "비용(Cost)과 성능의 트레이드오프" 단골 문제입니다. • 실시간 처리(Query Time)가 아님: 콘텍스트 생성은 사용자가 질문할 때 일어나는 것이 아니라, 데이터를 파싱하는 인덱싱 시점(Indexing Time)에 딱 한 번 실행됩니다. 따라서 사용자가 체감하는 실시간 답변 속도(Query Latency)에는 추가적인 오버헤드가 전혀 없습니다. • 프롬프트 캐싱(Prompt Cashing)의 역할: 매 청크마다 수백 페이지의 원본 문서를 처음부터 다시 읽히면 비용이 파산 수준으로 커집니다. 아키텍트는 원본 문서를 한 번 캐시(Cache)에 로드해 두고, 그 안에서 모든 청크의 콘텍스트(50~100 토큰)를 캐시 읽기 방식으로 저렴하게 생성해야 합니다. • ⚠️ 시험 출제 포인트: 콘텍스트 기반 검색을 대규모 환경에서 경제적으로 현실성 있게(Affordable/Economical) 만드는 일등 공신은 모델의 단가 하락이 아니라 "프롬프트 캐싱 아키텍처 기법" 그 자체입니다. 3. 아키텍트의 콘텍스트 기반 검색 도입 기준 (언제 쓸 것인가?) 이 기술은 앞선 강의에서 언급된 '파편화 문제(Bare fragment problem)' 를 완벽하게 치료합니다. • 기존 문제점: 수백 페이지짜리 재무제표 문서에서 "2024년 2분기 순이익은 5% 증가했다"라는 한 줄을 뚝 떼어내어 청크로 만들면, 나중에 사용자가 "A회사의 2024년 2분기 순이익이 어때?"라고 물었을 때, 청크 자체에 'A회사'라는 단어가 없어서 검색기가 이 청크를 찾지 못하고 놓칩니다. • Contextual Retrieval의 해결책: 청크 앞에 [이 조각은 A회사의 2024년 재무제표 중 2분기 실적 발표 섹션에 포함된 내용입니다]라는 50~100 토큰짜리 배경 설명을 LLM이 미리 적어서 붙여줍니다. 덕분에 검색기가 핵심 키워드(A회사, 재무제표 등)를 쉽게 인식하고 정확하게 찾아올 수 있습니다. 틀린 예시 ( Semantic chunking reliably outperforms fixed-window across most corpora and query types : 시맨틱 청킹이 대부분의 상황에서 고정 창을 압도한다): 실제 대규모 벤치마크 결과, 단순 고정 창 방식이 시맨틱 청킹보다 최종 답변 정확도가 더 높게 나오는 경우가 많아 틀린 설명입니다. 시맨틱 청킹은 문장이 너무 짧게 쪼개지거나 파이프라인이 복잡해지는 부작용이 있습니다 (Chunk boundary precision is the single largest factor in retrieval quality : 청크 경계의 정밀도가 검색 품질의 단일 최대 요인이다): 글자를 정확히 어디서 자르느냐(경계면)보다는 청크의 전체적인 크기(Size)나 임베딩/리랭커(Reranker) 모델의 성능이 품질에 훨씬 더 큰 영향을 미치므로 틀린 설명입니다. (Larger chunks tend to improve recall because more context is embedded : 청크가 커지면 컨텍스트가 더 많이 임베딩되므로 재현율이 향상되는 경향이 있다): 청크 크기가 너무 커지면 중요한 핵심 정보(Signal)가 주변의 쓸데없는 텍스트에 파묻혀 희석(Dilute)되기 때문에 검색 품질이 오히려 나빠집니다. 무조건 커진다고 검색 품질이 좋아지지 않으므로 틀린 설명입니다.
본 포스팅은 10x 체험단 활동의 일환으로 강의 수강권을 제공받아 작성한 후기입니다. 아이디어를 기획하고 화면으로 구현해본 바이브 코딩 학습 이번 코드잇 텐엑스 과정에서는 바이브 코딩의 기본 개념부터 서비스 기획, 그리고 Google Stitch를 활용한 UI 화면 제작까지 학습했다. 평소 서비스 기획에 관심이 있어 아이디어를 정리하거나 사용자 문제를 정의하는 경험은 있었지만, 내가 생각한 아이디어를 AI 도구를 활용해 실제 화면의 형태로 빠르게 만들어보는 것은 새로운 경험이었다. 특히 이번 2주간의 학습을 통해 단순히 “좋은 아이디어를 생각하는 것”에서 끝나는 것이 아니라, 사용자의 불편함을 발견하고 → 서비스 기능을 정의하고 → MVP와 PRD를 작성하고 → 실제 화면으로 구체화하는 과정을 직접 경험할 수 있었다. AI를 활용하며 내가 기획한 아이디어를 구체화하는 경험이었기에 실제로 AI 서비스 개발을 하는 것 같아서 작업할 때마다 흥미롭게 진행할 수 있었던 것 같다. 📍 1주차 – 바이브 코딩과 서비스 기획의 기초 익히기 1주차에는 먼저 바이브 코딩이 무엇인지 이해하고 Google AI Studio를 활용해 AI와 대화하는 방법을 학습했다. 처음에는 AI에게 원하는 내용을 이야기하면 결과물을 만들어주는 정도로 생각했지만, 학습을 진행하면서 결과물의 품질을 높이기 위해서는 사용자가 원하는 것을 얼마나 구체적으로 전달하는지가 중요하다는 것을 알게 됐다. 특히 AI에게 요청할 때 단순히 “이 기능을 만들어줘”라고 이야기 하기보다는 목적, 사용자, 필요한 기능, 조건 등을 구체적으로 설명 해야 원하는 결과에 가까워진다는 점이 인상적이었다. 이후에는 서비스 기획의 기본적인 과정을 학습했다. 가장 먼저 좋은 서비스 아이디어 는 새로운 기술에서 시작하는 것이 아니라 사용자가 실제로 경험하는 불편함에서 시작 해야 한다는 점을 배웠다. 이를 바탕으로 내가 평소 느끼고 있던 문제를 서비스 아이디어로 발전시켰다. 유튜브, 인스타그램, 틱톡 등에서 나중에 다시 보기 위해 콘텐츠를 저장하지만, 저장된 콘텐츠가 많아질수록 원하는 콘텐츠를 다시 찾기 어렵다는 불편함에 주목했다. 그래서 여러 플랫폼에서 저장하고 싶은 콘텐츠 링크를 하나의 서비스에 모으고, 카테고리별로 정리해 나중에 쉽게 다시 찾을 수 있는 서비스를 기획했다. 이 과정에서 단순히 기능을 많이 넣는 것이 아니라 가장 먼저 검증해야 할 핵심 기능이 무엇인지 결정하는 * MVP * 개념도 학습했다. 내가 기획한 서비스에서는 다음과 같은 흐름을 핵심 MVP로 설정했다. 콘텐츠 링크 저장 → 카테고리별 분류 → 저장 목록 확인 → 원본 콘텐츠로 이동 이를 통해 “처음부터 완성도 높은 서비스를 만드는 것” 보다 사용자가 실제로 이 기능에서 가치를 느끼는지를 먼저 확인하는 것 이 중요하다는 점을 이해할 수 있었다. 이후에는 서비스의 목적, 사용자, 주요 기능, 사용 흐름 등을 정리한 PRD(Product Requirements Document) 를 작성하면서 막연했던 아이디어를 하나의 서비스 기획서로 구체화했다. 📍 2주차 – 기획서를 실제 화면으로 표현하기 2주차에는 1주차에서 기획한 서비스를 실제 화면으로 표현하는 과정을 학습했다. 먼저 UI를 구성할 때 단순히 예쁜 화면을 만드는 것이 아니라 사용자가 어떤 행동을 해야 하는지 자연스럽게 안내하는 것이 중요하다는 점을 배웠다. 화면에 포함된 모든 요소를 동일하게 강조하면 오히려 사용자가 어디를 먼저 봐야 할지 알기 어렵기 때문에, 정보의 중요도 에 따라 크기와 배치, 강조 정도를 다르게 구성 해야 한다는 점도 학습했다. 이후 Google Stitch를 활용해 내가 기획한 서비스의 UI 초안을 직접 만들어보았다. AI에게 프롬프트를 제공하면 텍스트로만 정리되어 있던 서비스가 실제 화면으로 나타나는 과정이 가장 흥미로웠다. 처음 생성된 화면을 그대로 사용하는 것이 아니라, 원하는 서비스 방향과 다르게 표현된 부분을 다시 수정하면서 화면을 발전시켰다. 예를 들어 사용자가 가장 먼저 해야 하는 행동 을 더 잘 보이게 만들거나, 중요도가 상대적으로 낮은 요소 는 시각적인 강조를 줄이는 방식으로 화면을 조정했다. 또한 하나의 화면을 만드는 데서 끝나는 것이 아니라 다음 화면을 추가하면서 사용자의 전체 이용 흐름 을 연결하는 경험 도 할 수 있었다. 이 과정에서 기획 단계에서는 자연스럽다고 생각했던 사용자 흐름도 실제 화면으로 만들어보면 부족한 부분이 보인다는 것을 알게 됐다. 결국 화면 설계는 단순히 기획서를 시각화하는 과정이 아니라, 사용자 입장에서 서비스 흐름을 다시 검증하는 과정이라는 점을 배울 수 있었다. 📍 전문가 피드백으로 더 성장하기 텐엑스를 진행하면서 직접 작업한 과정 및 결과를 멘토님께 제출하면, 직접 피드백을 텍스트로 적어주시고 그와 동시에 내가 어느 부분에서 잘했고, 어느 부분에서는 부족하며, 이럴 때는 어떻게 고도화하면 좋은지 이해하기 쉽게 영상으로도 설명해주셔서 더욱더 성장할 수 있는 발판이 되었다. 실제로 멘토님께 받은 피드백 내용이다. 정보 위계에 요소 이름만 적혀 있는데, 왜 이러한 우선순위를 가져야 하는지나, 화면 상에서 어떻게 우선순위를 높여서 보여줄지를 더 구체화해보면 좋습니다. 예를 들어 메인 화면 1순위인 링크 입력 칸이라면 "핵심 가설의 주요 행동이므로 가장 접근성이 높아야 하고, 화면 최상단에 가로 전체 폭으로, 저장 버튼은 대표 색상으로 채워서 표시하기"와 같이 만들어 볼 수 있습니다. 피드백을 확인한 직후, 바로 적용시켜서 프롬프트를 작성하니 내가 수정하고자 한 부분을 AI가 완벽하게 수정하는 결과를 확인했다. 이를 기점으로 내가 판단한 이유와 그렇기에 어떻게 수정해야할 지 세세하게 설명하며 작업을 진행하는 습관을 가지게 되었다. 📍 가장 크게 달라진 점 이번 2주간의 학습을 통해 가장 크게 달라진 점은 아이디어를 바라보는 방식 이다. 이전에는 서비스 아이디어가 떠오르면 먼저 어떤 기능을 넣을지 생각하는 경우가 많았다. 하지만 지금은 먼저 “사용자가 어떤 불편함을 겪고 있는가?” 를 생각한 뒤, 문제 정의 → 핵심 가설 → MVP → PRD → UI 순서로 아이디어를 구체화하려고 한다. 또한 AI 도구 역시 단순히 결과물을 만들어주는 도구가 아니라, 내가 원하는 방향을 명확하게 전달하고 결과를 반복적으로 수정 하면서 함께 결과물을 만들어가는 도구라는 점을 경험했다. 특히 Google Stitch를 이용해 기획 내용을 실제 화면으로 빠르게 확인해보면서, 서비스 기획자가 아이디어를 전달할 때 문서뿐 아니라 화면 형태의 프로토타입까지 함께 제시할 수 있다면 훨씬 효과적인 커뮤니케이션이 가능 하겠다는 생각이 들었다. 📍 앞으로의 목표! 이번 2주차까지는 서비스 아이디어를 정의하고, MVP와 PRD를 작성한 뒤 Google Stitch를 활용해 UI 초안을 제작하는 단계까지 진행했다. 3주차에는 지금 만든 화면을 기반으로 사용자가 실제로 조작할 수 있는 형태의 서비스를 기획 및 제작해서 직접 배포하여 웹서비스 만들기 과정까지 배울 것 같다. 그렇기에 사용자의 입장이 되어, '나의 서비스를 직접 사용한다면 어디서 불편함을 겪을지', 또는 '기획한 기능 중 서비스 초기 단계 구현에서 필요가 있는가?'를 판단해서 기획을 구체화하고 싶다. 또한 AI를 활용해 기능을 구현하는 과정에서 단순히 AI가 만들어준 결과를 사용하는 것이 아니라, 내가 작성한 기획 의도가 실제 기능에 제대로 반영되었는지를 판단하고 수정할 수 있는 능력 을 기르고 싶다. 궁극적으로는 서비스 아이디어를 기획서에서 끝내지 않고, 직접 프로토타입을 제작하고 사용자 반응까지 확인할 수 있는 기획자로 성장하는 것이 목표다.
Đèn Exit VINALED được thiết kế để hoạt động ngay cả khi hệ thống điện gặp sự cố. Nhờ bộ pin sạc tích hợp, đèn có thể duy trì chiếu sáng và hiển thị hướng thoát hiểm trong thời gian cần thiết. Sản phẩm phù hợp lắp đặt tại chung cư, khách sạn, trường học, bệnh viện và các khu vực công cộng. Độ sáng ổn định, tiêu thụ điện thấp và tuổi thọ cao giúp đèn Exit VINALED trở thành lựa chọn đáng tin cậy cho các công trình hiện đại. >> Mua đèn exit VINALED cao cấp tại: https://vinaled.com/den-chieu-sang-trong-nha/den-exit-thoat-hiem-den-khan-cap #denexit #denthoathiem #denexitthoathiem #denchiloithoathiem #VINALED