<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>for now in Stream(life): now.step()</title>
    <link>https://nowallnow.tistory.com/</link>
    <description>탐구하고 깨달으며 살고 싶어요  ⋆ ₊ ﾟ ☽ * ⋆</description>
    <language>ko</language>
    <pubDate>Wed, 15 Apr 2026 18:48:28 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>승실</managingEditor>
    <image>
      <title>for now in Stream(life): now.step()</title>
      <url>https://tistory1.daumcdn.net/tistory/6998916/attach/ef47323eab494a908fd472515fa809c4</url>
      <link>https://nowallnow.tistory.com</link>
    </image>
    <item>
      <title>Python Property</title>
      <link>https://nowallnow.tistory.com/entry/Python-Property</link>
      <description>&lt;blockquote data-ke-style=&quot;style2&quot;&gt;함수인데 변수처럼 쓰는 것&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;내부에 계산이나 검증 로직을 포함시키고 싶지만, 외부에서는 이를 그저 단순한 attribute처럼 사용하게 만들고 싶을 때 property를 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;c.f. 단일 접근 원칙(Uniform Access Principle) : 내부 로직이 단순한 변수인지, 복잡한 함수 계산인지 사용자는 알 필요 없이 똑같이 접근할 수 있어야 한다는 개념.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1775817410462&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Person:
	def __init__(self):
    	self._age = 20
        
    @property
    def age(self):
    	return self._age

p = Person()
print(p.age)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로는 메서드이지만 attribute처럼 접근 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내부에 로직을 넣을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #eeece9; text-align: start;&quot; data-ke-size=&quot;size26&quot; data-darkreader-inline-color=&quot;&quot;&gt;활용 예시&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.&amp;nbsp;데이터&amp;nbsp;검증(Validation)&lt;/h3&gt;
&lt;pre id=&quot;code_1775817447444&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Person:
    def __init__(self):
        self._age = 20

    @property
    def age(self):
        return self._age

    @age.setter
    def age(self, value):
        if value &amp;lt; 0:
            raise ValueError(&quot;나이는 음수 불가&quot;)
        self._age = value

p = Person()
p.age = 10   # setter 실행됨&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1775818174670&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class User:
    def __init__(self, name, age):
        self.name = name
        self.age = age  # 여기서 자연스럽게 setter가 호출됩니다!

    # 1. Getter: 값을 읽을 때 실행되는 함수
    @property
    def age(self):
        return self._age

    # 2. Setter: 값을 할당할 때 실행되는 함수
    @age.setter
    def age(self, value):
        if value &amp;lt; 0:
            raise ValueError(&quot;나이는 음수가 될 수 없습니다!&quot;)
        self._age = value

# 사용 예시
user1 = User(&quot;파이썬&quot;, 20)
print(user1.age)  # 출력: 20 (변수처럼 접근)

# 데이터 검증 테스트
try:
    user1.age = -5  # 변수처럼 값을 넣지만, 내부적으로는 함수가 실행되어 에러를 발생시킴!
except ValueError as e:
    print(f&quot;에러 발생: {e}&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 동적 계산 (Computed Properties)&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&amp;nbsp;e.g. first_name과 last_name이라는 변수만 저장해 두고, full_name을 호출할 때마다 두 개를 합쳐서 반환하게 만들기. (메모리 낭비를 줄이는 방법)&lt;/p&gt;
&lt;pre id=&quot;code_1775818193896&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Person:
    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

    # 별도의 변수로 저장하지 않고, 호출될 때마다 계산해서 반환!
    @property
    def full_name(self):
        return f&quot;{self.first_name} {self.last_name}&quot;

# 사용 예시
person = Person(&quot;길동&quot;, &quot;홍&quot;)

# 1. 함수형태인 full_name()이 아니라 변수처럼 full_name 으로 호출
print(person.full_name)  # 출력: 길동 홍

# 2. 이름이 바뀌면?
person.first_name = &quot;철수&quot;

# 3. full_name도 자동으로 업데이트된 결과를 보여줌!
print(person.full_name)  # 출력: 철수 홍&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스나 메모리에 굳이 저장할 필요 없는 값들을, 호출하는 순간에 계산해서 던져주는 패턴이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;full_name 이라는 변수를 따로 만들어서 저장해두면, first_name이 바뀔 때마다 full_name도 업데이트해 줘야 하는 번거로움과 버그의 위험이 생긴다. 하지만 @property를 쓰면 메모리도 아끼고 데이터의 일관성도 지킬 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 이 예제에서는 setter를 구현하지 않았기 때문에 person.full_name = &quot;김철수&quot; 처럼 강제로 값을 넣으려고 하면 AttributeError가 발생하며 읽기 전용(Read-only) 속성이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Languages  </category>
      <author>승실</author>
      <guid isPermaLink="true">https://nowallnow.tistory.com/38</guid>
      <comments>https://nowallnow.tistory.com/entry/Python-Property#entry38comment</comments>
      <pubDate>Fri, 10 Apr 2026 19:52:38 +0900</pubDate>
    </item>
    <item>
      <title>FastAPI로 Local에 RAG 백엔드 서버 띄워 응답 받기</title>
      <link>https://nowallnow.tistory.com/entry/FastAPI%EB%A1%9C-RAG-%EB%B0%B1%EC%97%94%EB%93%9C-%EC%84%9C%EB%B2%84-%EB%9D%84%EC%9B%8C-%EC%9D%91%EB%8B%B5-%EB%B0%9B%EA%B8%B0</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;백엔드 코드&lt;/h2&gt;
&lt;pre id=&quot;code_1768268053941&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# main.py
from dotenv import load_dotenv
load_dotenv()
import os
from typing import List, Literal, Optional
from fastapi import FastAPI, HTTPException
from fastapi.responses import StreamingResponse
from pydantic import BaseModel

from llm import stream_ai_response  # 아래 llm.py에서 만들 함수

app = FastAPI()

class ChatMessage(BaseModel):
    role: Literal[&quot;system&quot;, &quot;user&quot;, &quot;assistant&quot;]
    content: str

class ChatRequest(BaseModel):
    messages: List[ChatMessage]


@app.post(&quot;/v1/chat&quot;)
async def chat(req: ChatRequest):
    if not req.messages:
        raise HTTPException(status_code=400, detail=&quot;No messages provided&quot;)

    # 마지막 user 메시지
    last_user = next((m.content for m in reversed(req.messages) if m.role == &quot;user&quot;), None)
    if not last_user:
        raise HTTPException(status_code=400, detail=&quot;No user message found&quot;)

    # system은 프론트가 넣었을 수도/아닐 수도. 여기서는 user/assistant만 히스토리로 사용 추천
    history = [m.model_dump() for m in req.messages if m.role in (&quot;user&quot;, &quot;assistant&quot;)]

    def generate():
        for chunk in stream_ai_response(user_input=last_user, history=history):
            yield chunk

    return StreamingResponse(generate(), media_type=&quot;text/plain&quot;)

if __name__ == &quot;__main__&quot;:
    import uvicorn
    port = int(os.getenv(&quot;PORT&quot;, &quot;8080&quot;))
    uvicorn.run(app, host=&quot;0.0.0.0&quot;, port=port)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768268133945&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# llm.py (stateless 버전)
from typing import Iterable, Dict, List
from langchain_core.messages import HumanMessage, AIMessage, BaseMessage
from langchain_upstage import UpstageEmbeddings
from langchain_pinecone import PineconeVectorStore
from langchain_openai import ChatOpenAI
from langchain_core.prompts import MessagesPlaceholder, ChatPromptTemplate, FewShotChatMessagePromptTemplate
from langchain_classic.chains import create_history_aware_retriever, create_retrieval_chain
from langchain_classic.chains.combine_documents import create_stuff_documents_chain

from config import answer_examples

def _to_lc_messages(history: List[Dict[str, str]]) -&amp;gt; List[BaseMessage]:
    # history: [{&quot;role&quot;:&quot;user&quot;,&quot;content&quot;:&quot;...&quot;}, {&quot;role&quot;:&quot;assistant&quot;,&quot;content&quot;:&quot;...&quot;}]
    out: List[BaseMessage] = []
    for m in history:
        if m[&quot;role&quot;] == &quot;user&quot;:
            out.append(HumanMessage(content=m[&quot;content&quot;]))
        elif m[&quot;role&quot;] == &quot;assistant&quot;:
            out.append(AIMessage(content=m[&quot;content&quot;]))
    return out

def get_retriever():
    embedding = UpstageEmbeddings(model=&quot;solar-embedding-1-large&quot;)
    index_name = &quot;analects-upstage-index&quot;  # env로 빼는 것도 추천
    database = PineconeVectorStore.from_existing_index(index_name=index_name, embedding=embedding)
    return database.as_retriever(search_kwargs={&quot;k&quot;: 4})

def get_llm(model: str = &quot;gpt-4o&quot;):
    return ChatOpenAI(model=model, max_tokens=512, temperature=0.6)

def build_rag_chain():
    llm = get_llm()
    retriever = get_retriever()

    contextualize_q_system_prompt = (
        &quot;Given a chat history and the latest user question &quot;
        &quot;which might reference context in the chat history, &quot;
        &quot;formulate a standalone question which can be understood &quot;
        &quot;without the chat history. Do NOT answer the question.&quot;
    )

    contextualize_q_prompt = ChatPromptTemplate.from_messages(
        [(&quot;system&quot;, contextualize_q_system_prompt),
         MessagesPlaceholder(&quot;chat_history&quot;),
         (&quot;human&quot;, &quot;{input}&quot;)]
    )

    history_aware_retriever = create_history_aware_retriever(llm, retriever, contextualize_q_prompt)

    # few-shot
    example_prompt = ChatPromptTemplate.from_messages([(&quot;human&quot;, &quot;{input}&quot;), (&quot;ai&quot;, &quot;{answer}&quot;)])
    few_shot_prompt = FewShotChatMessagePromptTemplate(example_prompt=example_prompt, examples=answer_examples)

    system_prompt = (
        &quot;You are an expert in Eastern Philosophy and a sincere counseling chatbot &quot;
        &quot;specializing in answering user questions. You must always respond in Korean. &quot;
        &quot;...\n\n{context}&quot;
    )

    qa_prompt = ChatPromptTemplate.from_messages(
        [(&quot;system&quot;, system_prompt),
         few_shot_prompt,
         MessagesPlaceholder(&quot;chat_history&quot;),
         (&quot;human&quot;, &quot;{input}&quot;)]
    )

    question_answer_chain = create_stuff_documents_chain(llm, qa_prompt)
    rag_chain = create_retrieval_chain(history_aware_retriever, question_answer_chain)
    return rag_chain

# 서버 시작 시 1회 생성(권장)
_RAG_CHAIN = build_rag_chain()

def stream_ai_response(user_input: str, history: List[Dict[str, str]]) -&amp;gt; Iterable[str]:
    chat_history = _to_lc_messages(history)

    # create_retrieval_chain 결과는 보통 {&quot;answer&quot;: &quot;...&quot;, ...} 형태라서
    # stream이 어떤 타입을 내는지는 체인 구현에 따라 달라질 수 있다.
    # 아래는 &quot;answer&quot; 스트림을 뽑을 때 기준.
    for chunk in _RAG_CHAIN.stream({&quot;input&quot;: user_input, &quot;chat_history&quot;: chat_history}):
        # chunk가 dict로 오면 answer 키에서 꺼내기
        if isinstance(chunk, dict) and &quot;answer&quot; in chunk and chunk[&quot;answer&quot;]:
            yield chunk[&quot;answer&quot;]
        elif isinstance(chunk, str):
            yield chunk&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 띄우기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`(rag-backend)&amp;nbsp;D:\llm\rag-backend&amp;gt;uvicorn&amp;nbsp;main:app&amp;nbsp;--reload&amp;nbsp;--host&amp;nbsp;127.0.0.1&amp;nbsp;--port&amp;nbsp;8080&amp;nbsp;--log-level&amp;nbsp;debug`&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;서버에 요청 보내서 확인&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`FastAPI docs`에서 테스트 (`http://localhost:8080/docs`)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`/v1/chat` 클릭, `Try it out` 클릭, `Body`에 아래 입력 후 `Execute`&lt;/p&gt;
&lt;pre id=&quot;code_1768268486487&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;messages&quot;: [
    {
      &quot;role&quot;: &quot;user&quot;,
      &quot;content&quot;: &quot;공자가 말한 군자란?&quot;
    }
  ]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;517&quot; data-origin-height=&quot;537&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfLbLW/dJMcac2RZDv/PDMx9pkeFU9x6zkwp6vfg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfLbLW/dJMcac2RZDv/PDMx9pkeFU9x6zkwp6vfg0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfLbLW/dJMcac2RZDv/PDMx9pkeFU9x6zkwp6vfg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfLbLW%2FdJMcac2RZDv%2FPDMx9pkeFU9x6zkwp6vfg0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;291&quot; height=&quot;537&quot; data-origin-width=&quot;517&quot; data-origin-height=&quot;537&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1380&quot; data-origin-height=&quot;796&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OAVRX/dJMcaiWjF0b/pUzedVkPK3cITmDrc7ABmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OAVRX/dJMcaiWjF0b/pUzedVkPK3cITmDrc7ABmK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OAVRX/dJMcaiWjF0b/pUzedVkPK3cITmDrc7ABmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOAVRX%2FdJMcaiWjF0b%2FpUzedVkPK3cITmDrc7ABmK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;898&quot; height=&quot;518&quot; data-origin-width=&quot;1380&quot; data-origin-height=&quot;796&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Project Log  ️</category>
      <author>승실</author>
      <guid isPermaLink="true">https://nowallnow.tistory.com/35</guid>
      <comments>https://nowallnow.tistory.com/entry/FastAPI%EB%A1%9C-RAG-%EB%B0%B1%EC%97%94%EB%93%9C-%EC%84%9C%EB%B2%84-%EB%9D%84%EC%9B%8C-%EC%9D%91%EB%8B%B5-%EB%B0%9B%EA%B8%B0#entry35comment</comments>
      <pubDate>Tue, 13 Jan 2026 10:45:59 +0900</pubDate>
    </item>
    <item>
      <title>Flutter UI 그리기 (기본 Widget 익히기)</title>
      <link>https://nowallnow.tistory.com/entry/Flutter-%EC%B1%97%EB%B4%87-UI%EC%97%90-Gemini-%EC%97%B0%EB%8F%99</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;3️⃣4️⃣5️⃣6️⃣7️⃣8️⃣9️⃣&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;0️⃣ 개념&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  Flutter란?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Google이 개발한 Dart 언어 기반의 선언형 UI 프레임워크로,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 코드베이스로 모바일,웹,데스크톱 앱을 동시에 만들 수 있는 기술이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Flutter는 자체 렌더링 엔진(Skia)을 사용해 플랫폼에 의존하지 않는 UI를 구현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  UI 단위 : Widget&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Flutter에서는 모든 것이 Widget이다. (버튼, 텍스트, 레이아웃, 화면 전체)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  React와 비교&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Flutter의 Widget은 React의 Component와 개념적으로 동일하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Flutter는 UI를 자체 엔진으로 그리는 반면, React는 DOM을 통해 브라우저가 UI를 그린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1️⃣ 기본 위젯&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. Icon, IconButton&lt;/h3&gt;
&lt;pre id=&quot;code_1767668158129&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;child: Icon(
      Icons.format_overline,
      size: 100,
      color: Colors.deepPurple,
),&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Icon에 커서를 두고 `ctrl` + `.` (`Extract` 또는 `wrap with ~` ... 을 할 수 있다) &amp;rarr; wrap with widget&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1767668400373&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;child: IconButton(
  onPressed: () {},
  icon: Icon(
        Icons.format_overline,
        size: 100,
        color: Colors.deepPurple,
  ),
),&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 return 옆에 const를 지워주면 button이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`onPressed:`에는 이벤트를 넣어주는 것인데 함수 대신에 `null`을 넣으면 버튼 비활성화된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`icon:`에 들어가는 건 Widget&amp;nbsp; 타입이므로 Icon()대신 Text()를 넣어줘도 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1767668817719&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;child: IconButton(
      onPressed: () {},
      icon: Text(
        'nowallnow',
        style: TextStyle(
          color: Colors.red,
          fontSize: 48,
          fontWeight: FontWeight.w100,
        ),  // TextStyle
      ),  // Text
),  // IconButton&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 글씨가 버튼처럼 된다. 글씨에 style도 지정해주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1767669533190&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;child: IconButton(
    onPressed: () {}, // Null이면 비활성화
    iconSize: 40,
    color: Colors.blueAccent,
    hoverColor: Colors.yellow,
    disabledColor: Colors.grey, // Button이 비활성화 되었을 때 색상
    icon: Icon(
          Icons.format_overline,
    ),
),&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IconButton이 가진 기능들 활용하기(`iconSize`, `color`, `hoverColor`, `disabledColor`...)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. TextButton&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 텍스트면 위처럼 하지 말고 TextButton을 활용하자.&lt;/p&gt;
&lt;pre id=&quot;code_1767670384161&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;body: Center(
  // Center is a layout widget. It takes a single child and positions it
  // in the middle of the parent.
  child: TextButton(
    child: const Text('안녕하십니까?'),
    onPressed: () {},
  ),
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  OutlinedButton, ElevatedButton, FilledButton도 같이 보자.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767773091219&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
    children: [
      TextButton(
        child: const Text('안녕하십니까?'),
        onPressed: () {},
      ),
      const SizedBox(height:8),
      ElevatedButton(
        child: const Text('Elevated'),
        onPressed: () {},
      ),
      OutlinedButton(
        child: const Text('Outlined'),
        onPressed: () {},
      ),
      FilledButton(
        child: const Text('Filled'),
        onPressed: () {},
      ),
    ],
  ), // Column
) // Center&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;196&quot; data-origin-height=&quot;185&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rp9u3/dJMcagc8nIh/WvklGd4BxptCbTd0KkNNd1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rp9u3/dJMcagc8nIh/WvklGd4BxptCbTd0KkNNd1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rp9u3/dJMcagc8nIh/WvklGd4BxptCbTd0KkNNd1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Frp9u3%2FdJMcagc8nIh%2FWvklGd4BxptCbTd0KkNNd1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;196&quot; height=&quot;185&quot; data-origin-width=&quot;196&quot; data-origin-height=&quot;185&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  TextButton에 스타일을 줘 보자.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767773561860&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;children: [
    TextButton(
      child: Text('안녕하십니까?'),
      onPressed: () {},
      style: ButtonStyle(
      backgroundColor: WidgetStateProperty.all(Colors.amber),
      )
    ),
],&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;176&quot; data-origin-height=&quot;45&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2Z9aM/dJMcaiWhxj0/7ScszHhzkNlhEceF1EKcw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2Z9aM/dJMcaiWhxj0/7ScszHhzkNlhEceF1EKcw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2Z9aM/dJMcaiWhxj0/7ScszHhzkNlhEceF1EKcw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2Z9aM%2FdJMcaiWhxj0%2F7ScszHhzkNlhEceF1EKcw0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;176&quot; height=&quot;45&quot; data-origin-width=&quot;176&quot; data-origin-height=&quot;45&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 주면 `WidgetStateProperty.all()`로 일일이 감싸줘야 하는 불편함이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 아래와 같이 스타일을 주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1767773908940&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;children: [
    TextButton(
        child: Text('안녕하십니까?'),
        onPressed: () {},
        style: TextButton.styleFrom(
          backgroundColor: Colors.lightBlueAccent,
        )
    ),
],&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;167&quot; data-origin-height=&quot;43&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blgdVB/dJMcab3XrFP/xQzx4ffKkhR6tfLojWPgNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blgdVB/dJMcab3XrFP/xQzx4ffKkhR6tfLojWPgNK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blgdVB/dJMcab3XrFP/xQzx4ffKkhR6tfLojWPgNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblgdVB%2FdJMcab3XrFP%2FxQzx4ffKkhR6tfLojWPgNK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;167&quot; height=&quot;43&quot; data-origin-width=&quot;167&quot; data-origin-height=&quot;43&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1767776100698&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;children: [
  TextButton(
    onPressed: () {},
    child: const Text('안녕하십니까?'),
    style: TextButton.styleFrom(
      backgroundColor: Colors.lightBlueAccent, // 버튼 배경색
      foregroundColor: Colors.white, // 글자색
      disabledBackgroundColor: Colors.grey,
      disabledForegroundColor: Colors.black,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(14),
      ),
      side: const BorderSide( // 버튼 테두리
        color: Colors.blue,
        width: 2,
      ),
      textStyle: const TextStyle(
        fontSize: 20,
        fontWeight: FontWeight.bold,
      ), // TextStyle
    ), // style
  ), // TextButton
], // children&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;216&quot; data-origin-height=&quot;47&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSTfPK/dJMcafrK1IT/fUdhmL8vJ0UTbbWvsA3KeK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSTfPK/dJMcafrK1IT/fUdhmL8vJ0UTbbWvsA3KeK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSTfPK/dJMcafrK1IT/fUdhmL8vJ0UTbbWvsA3KeK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSTfPK%2FdJMcafrK1IT%2FfUdhmL8vJ0UTbbWvsA3KeK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;216&quot; height=&quot;47&quot; data-origin-width=&quot;216&quot; data-origin-height=&quot;47&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  아이콘을 넣어 보자.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767776622720&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;TextButton.icon(   // ➕.icon을 넣었음
  // .icon속성은 OutlinedButton, ElevatedButtond에도 있음.
  // 7번째 라인의 style: 에서도 해당 Button으로 변경해서 쓰면 됨.
  label: const Text('안녕하십니까?'),  // ➕ child 대신 label
  icon: const Icon(Icons.ac_unit_sharp), // ➕ icon 추가
  onPressed: () {},
  style: TextButton.styleFrom(
    backgroundColor: Colors.blueGrey, // 버튼색깔
    disabledBackgroundColor: Colors.grey,
    foregroundColor: Colors.white, // 글자색깔
    disabledForegroundColor: Colors.black,
    iconColor: Colors.yellow, // ➕
    disabledIconColor: Colors.green, // ➕
    iconAlignment: IconAlignment.end, // ➕ 아이콘 위치 오른쪽으로
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.circular(14),
    ), // RoundedRectangleBorder
    side: const BorderSide(   // 버튼 테두리
      color: Colors.purple,
      width: 2,
    ), // BorderSide
    textStyle: const TextStyle(
      fontSize: 20,
      fontWeight: FontWeight.bold,
    ), // TextStyle
  ), // TextButton.styleFrom
), // TextButton.icon&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;247&quot; data-origin-height=&quot;47&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVZgqW/dJMcaaxdnew/wJ7aqqmqQilWNYkiviB6WK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVZgqW/dJMcaaxdnew/wJ7aqqmqQilWNYkiviB6WK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVZgqW/dJMcaaxdnew/wJ7aqqmqQilWNYkiviB6WK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVZgqW%2FdJMcaaxdnew%2FwJ7aqqmqQilWNYkiviB6WK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;247&quot; height=&quot;47&quot; data-origin-width=&quot;247&quot; data-origin-height=&quot;47&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. TextField&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;b&gt;  사용자가 text를 입력할 수 있는 글상자를 만들어 보자.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767777271505&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;body: Center(
  // Center is a layout widget. It takes a single child and positions it
  // in the middle of the parent.
  child: TextField(),
), // Center&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;340&quot; data-origin-height=&quot;97&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eEWY1w/dJMcaiBXYBw/byVZZujlXzVwKC0x52y2JK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eEWY1w/dJMcaiBXYBw/byVZZujlXzVwKC0x52y2JK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eEWY1w/dJMcaiBXYBw/byVZZujlXzVwKC0x52y2JK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeEWY1w%2FdJMcaiBXYBw%2FbyVZZujlXzVwKC0x52y2JK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;340&quot; height=&quot;97&quot; data-origin-width=&quot;340&quot; data-origin-height=&quot;97&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;텍스트를 처리해서 활용하는 방법 중 하나는 Controller를 쓰는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;플러터 객체 중에 TextEditingController()를 써보겠다.&lt;/p&gt;
&lt;pre id=&quot;code_1767789707436&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class _MyHomePageState extends State&amp;lt;MyHomePage&amp;gt; {
  final controller = TextEditingController();

  @override
  Widget build(BuildContext context) {
    debugPrint('controller.text: ${controller.text}');
    return Scaffold(
      body: Center(
        child: TextField(
          controller: controller,
          onChanged: (value) { // textField에 변화가 있을 때마다 호출
            setState(() {}); // 상태가 변경되었음을 알림
            debugPrint(value);
          },
          onSubmitted: (value) { // enter키를 눌렀을 때 호출
            debugPrint('onSubmitted: $value');
          },
        ), // TextField
      ), // Center
    ); // Scaffold
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  controller의 역할&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 텍스트를 보관.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;텍스트필드에서 입력되는 값이 컨트롤러에 담기게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  `build()`의 역할&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 state를 기준으로 UI를 그리는 함수.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매우 자주 호출 된다.(화면 회전, 키보드 표시, 부모 위젯변경, `setState()`등)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  `setState()`의 역할&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상태가 바뀌었다고 플러터에게 알리는 신호&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`setState()`를 호출하면 플러터가 다음 프레임에서 `build()`를 다시 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  옳은 흐름&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 발생(버튼 클릭, API 응답 등) &amp;rarr; setState()호출 &amp;rarr; Flutter가 build() 다시 호출 &amp;rarr; UI 갱신&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  이제 스타일링을 해보자.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스타일을 줄 때, Button에서는 Button이 자식으로 갖고 있는 `TextStyle`에다가 했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TextField에서는 `TextStyle`이 decoration 바깥에 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1767798112835&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;body: Center(
  child: TextField(
    controller: controller,
    onChanged: (value) {
      // textField에 변화가 있을 때마다 호출
      setState(() {}); // 상태가 변경되었음을 알림
      debugPrint(value);
    },
    onSubmitted: (value) {
      // enter키를 눌렀을 때 호출
      debugPrint('onSubmitted: $value');
    },
    decoration: InputDecoration(
      hintText: '고민이 있나요?', // Placeholder
      hintStyle: const TextStyle(
        color: Colors.black54, // 반투명한 검정
      ), // TextStyle
      filled: true,
      fillColor: Colors.yellow.withValues(alpha: 0.5), // 투명도
      border: OutlineInputBorder(
        borderRadius: BorderRadius.circular(10),
        borderSide: const BorderSide(
          color: Colors.black, // 검정 테두리
          width: 2,
        ), // BorderSide
      ), // OutlineInputBorder
      contentPadding: const EdgeInsets.all(8), // 텍스트필드 세로 폭
    ), // InputDecoration
    style: const TextStyle(	// 텍스트필드 글씨 스타일
      fontSize: 24,
      fontWeight: FontWeight.w600,
      color: Colors.black,
    ), // TextStyle
  ), // TextField
),&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;285&quot; data-origin-height=&quot;82&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oyAt7/dJMcafSP0hx/BD0KrerO68wPKPbvSh9Yk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oyAt7/dJMcafSP0hx/BD0KrerO68wPKPbvSh9Yk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oyAt7/dJMcafSP0hx/BD0KrerO68wPKPbvSh9Yk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoyAt7%2FdJMcafSP0hx%2FBD0KrerO68wPKPbvSh9Yk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;198&quot; height=&quot;57&quot; data-origin-width=&quot;285&quot; data-origin-height=&quot;82&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. TextFormField&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TextField랑 거의 비슷한데 TextFormField에는 `onSubmitted`가 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한편, TextField와 달리 `validator`가 있다. 폼에서의 검증 역할이다.&lt;/p&gt;
&lt;pre id=&quot;code_1767800120928&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class _MyHomePageState extends State&amp;lt;MyHomePage&amp;gt; {
  final controller = TextEditingController();
  final formKey = GlobalKey&amp;lt;FormState&amp;gt;();

  @override
  Widget build(BuildContext context) {
    debugPrint('controller.text: ${controller.text}');
    return Scaffold(
      body: Center(
        child: Column(
          children: [
            Form(
              // 폼이 여러개일 수 있으므로 key 필요
              key: formKey,
              child: TextFormField(
                controller: controller,
                onChanged: (value) {
                  // textField에 변화가 있을 때마다 호출
                  setState(() {}); // 상태가 변경되었음을 알림
                  debugPrint('onChanged: $value');
                }, // onChanged
                validator: (value) {
                  debugPrint('value: $value');
                  if (value == null || value.isEmpty) {
                    return '값을 입력해주세요'; // 에러 메시지로 나옴
                  }
                  return null; // 입력이 유효한 경우 null 반환
                }, // validator
                decoration: InputDecoration(
                  hintText: '고민이 있나요?', // Placeholder
                  hintStyle: const TextStyle(
                    color: Colors.black54,
                  ), // TextStyle
                  filled: true,
                  fillColor: Colors.yellow.withValues(alpha: 0.5),
                  border: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(10),
                    borderSide: const BorderSide(
                      color: Colors.black,
                      width: 2,
                    ), // BorderSide
                  ), // OutlineInputBorder
                  contentPadding: const EdgeInsets.all(8),
                ), // InputDecoration
                style: const TextStyle(
                  fontSize: 24,
                  fontWeight: FontWeight.w600,
                  color: Colors.black,
                ), // TextStyle
              ), // TextFormField
            ), // Form
            TextButton(
              onPressed: () {
                debugPrint('validate ${formKey.currentState!.validate()}');
                if (formKey.currentState!.validate()) {
                  debugPrint('전송 텍스트: ${controller.text}');
                }
              }, // onPressed
              child: const Text('전송'),
            ), // TextButton
          ], // children
        ), // Column
      ), // Center
    ); // Scaffold
  } // build
} // _MyHomePageState&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;241&quot; data-origin-height=&quot;132&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/L6lJ7/dJMcacaJsxA/MQYsszQ5HVi7ydzqJiCOM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/L6lJ7/dJMcacaJsxA/MQYsszQ5HVi7ydzqJiCOM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/L6lJ7/dJMcacaJsxA/MQYsszQ5HVi7ydzqJiCOM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FL6lJ7%2FdJMcacaJsxA%2FMQYsszQ5HVi7ydzqJiCOM1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;219&quot; height=&quot;120&quot; data-origin-width=&quot;241&quot; data-origin-height=&quot;132&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;253&quot; data-origin-height=&quot;111&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yVCfY/dJMcagc8u8m/T1M4LTOAj4qvWIIlkHlP71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yVCfY/dJMcagc8u8m/T1M4LTOAj4qvWIIlkHlP71/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yVCfY/dJMcagc8u8m/T1M4LTOAj4qvWIIlkHlP71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyVCfY%2FdJMcagc8u8m%2FT1M4LTOAj4qvWIIlkHlP71%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;221&quot; height=&quot;97&quot; data-origin-width=&quot;253&quot; data-origin-height=&quot;111&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;243&quot; data-origin-height=&quot;301&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c3yZiD/dJMcahJSVhT/YLwTVUlXJRJ0OEYpX40FU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c3yZiD/dJMcahJSVhT/YLwTVUlXJRJ0OEYpX40FU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c3yZiD/dJMcahJSVhT/YLwTVUlXJRJ0OEYpX40FU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc3yZiD%2FdJMcahJSVhT%2FYLwTVUlXJRJ0OEYpX40FU1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;224&quot; height=&quot;277&quot; data-origin-width=&quot;243&quot; data-origin-height=&quot;301&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;플러터위젯의&amp;nbsp;가장&amp;nbsp;기초가&amp;nbsp;되는&amp;nbsp;구조&lt;/p&gt;
&lt;pre id=&quot;code_1768135458650&quot; class=&quot;scala&quot; style=&quot;background-color: #222425; color: #c7c2ba; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;typescript&quot; data-darkreader-inline-bgcolor=&quot;&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;code&gt;class ChatPage extends StatelessWidget {
  const ChatPage({super.key});

  @override
  Widget build(BuildContext context) { // widget을 리턴하는 build 메서드 
    throw UnimplementedError();
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #cec9c2; text-align: start;&quot; data-ke-size=&quot;size16&quot; data-darkreader-inline-color=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;const는&amp;nbsp;constructor.&amp;nbsp;클래스니까&amp;nbsp;우선&amp;nbsp;constructor가&amp;nbsp;들어가고&amp;nbsp;build&amp;nbsp;메서드에서&amp;nbsp;리턴하는&amp;nbsp;값이&amp;nbsp;화면에&amp;nbsp;그려지는&amp;nbsp;것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Playground  </category>
      <author>승실</author>
      <guid isPermaLink="true">https://nowallnow.tistory.com/34</guid>
      <comments>https://nowallnow.tistory.com/entry/Flutter-%EC%B1%97%EB%B4%87-UI%EC%97%90-Gemini-%EC%97%B0%EB%8F%99#entry34comment</comments>
      <pubDate>Tue, 6 Jan 2026 11:56:39 +0900</pubDate>
    </item>
    <item>
      <title>Opic AL 후기, 모든 꿀팁, 국내파 IH에서 AL 받은 후기</title>
      <link>https://nowallnow.tistory.com/entry/Opic-AL-%ED%9B%84%EA%B8%B0-%EA%BF%80%ED%8C%81-%EA%B5%AD%EB%82%B4%ED%8C%8C-IH%EC%97%90%EC%84%9C-AL-%EB%B0%9B%EC%9D%80-%ED%9B%84%EA%B8%B0</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1463&quot; data-origin-height=&quot;667&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ytGnf/dJMcadHmt5n/5HzIhKQMjkfDKcDPHBwbh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ytGnf/dJMcadHmt5n/5HzIhKQMjkfDKcDPHBwbh0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ytGnf/dJMcadHmt5n/5HzIhKQMjkfDKcDPHBwbh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FytGnf%2FdJMcadHmt5n%2F5HzIhKQMjkfDKcDPHBwbh0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;798&quot; height=&quot;364&quot; data-origin-width=&quot;1463&quot; data-origin-height=&quot;667&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;ℹ️ Intro&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제목을 화려하게 적었는데, IH 받다가 AL 받은 사람으로서 내가 쌓은 오픽 경험치를 풀어보고자 이렇게 썼다ㅎㅎ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글이 너무 긴 것 같은데 시간 없으면 요약 부분이랑&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이렇게 된 부분&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만 봐도 될 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 영어를 독해 위주로 공부해 온 전형적인 국내파 사람이다. 영어권 나라에는 5일 가봤고 회화 학원에는 2~3달 다녀본 적 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 온라인 언어 교환 채널에서 외국인한테 말 걸어 친구하고 소통해본 적이 꽤 많다. (소통이 길게 이어지는 인연은 없었지만..)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영어 공부하는 거 좋아하는 편이어서 그냥 오랫 동안 조금씩 메모하며 꾸준히 공부해왔다고 생각하는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스피킹 실력이 별로 늘지는 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오픽 IH 받고 나서 &lt;span style=&quot;color: #f89009; --darkreader-inline-color: var(--darkreader-text-ef6f53, #f5795e);&quot; data-darkreader-inline-color=&quot;&quot;&gt;AL 받으려면 어떤 점에 주력해야 하는지 &lt;/span&gt;찾아봤다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 모로 파악한 결과, IH 받은 시험에서보다 AL 받은 시험에서 &lt;span style=&quot;color: #f89009; --darkreader-inline-color: var(--darkreader-text-ef6f53, #f5795e);&quot; data-darkreader-inline-color=&quot;&quot;&gt;확실히 나아졌다고 느꼈고 &lt;/span&gt;결과도 상승하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;0️⃣ 최근 시험 복기&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;나의 Survey 선택&lt;br /&gt;독신, 일경험 없음, 학생 아님, 교육 수강 5년 지남.&lt;br /&gt;영화-공연-콘서트, 음악감상, 공원-해변, 주거개선-집에서보내는휴가,&lt;br /&gt;운동을 전혀 안함, 조깅, 걷기, 헬스장&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;AL 받았을 때 답변을 어떤 식으로 했는지 기억나는 대로 간략히 아래에 적었다.&lt;br /&gt;대부분은 그냥 그 표현을 할 수 있는 가장 쉬운 영어를 사용해서 이야기 했고,&lt;br /&gt;약간은 수준 있어 보이는 표현을 사용하려 했던 부분들 위주로 영어 단어도 함께 적어봤다. (아래에)&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고 정도로 봐주시고 제가 쓴 해설(?)만 읽으셔도 될 듯합니다!&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;1. 자기 소개&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;My name is ~~. I'm looking for a job. I have two dogs. I'm quite nervous. Let's have fun. 정도로 짧게 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;2,3,4&amp;nbsp; &quot;집에서 보내는 휴가&quot; 선택 질문 콤보 세트&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- Staycation 중에 하는 일&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: 그냥 평소랑 같다. 개들 산책시키고 청소도 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 집에 누가 방문하면 하는 일&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: 엄마랑 식당에 가서 맛있는 걸 먹으며 서로의 취미에 대해 얘기한다. 엄마는 라인댄스를 좋아하시고 나는 클라이밍을 좋아한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엄마는 요즘 배운 댄스의 음악, 댄스할 때의 outfit 등에 대해 얘기하시고 나는 주로 듣는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nothing special. 대화가 깊지는 않지만, 부담 없이 서로에 대해 얘기하는 시간이라 참 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 최근 staycation 중에 있었던 일&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: 문 손잡이를 교체했다. 가진 tools가 없어서 community center에서 screw driver를 빌렸다. 유튜브 튜토리얼 보고 따라했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;별로 어렵지 않았다. 손잡이가 기존 건 knob 형태였는데 lever 형태인 걸로 바꿨다. 원래 거는 rusty해서 iron smell이 났는데 새로운 거는 깨끗해서 손잡이를 사용할 때마다 기분이 좋아졌다. &lt;span style=&quot;color: #cec9c2; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot;&gt;사소한 일이지만 스스로 해내서 자랑스러웠다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;5,6,7&amp;nbsp; &quot;지형(Geography)&quot; 돌발 질문 콤보 세트&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 당신의 나라의 지형적 특징&lt;/b&gt; : 국토의 70%가 산이고 3면이 바다인 반도 지형이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 놀러 갔던 곳?의 지형이 어땠나?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: 가족이랑 바닷가에 놀러갔는데 바닷바람이 gusty. biting winter wind 때문에 너무 freezing, cold했다. 우리는 내륙(inland) 지방 사람들이라 추운 날씨에도 바다를 참 좋아했다. 바다의 자연 경관이 멋졌다(scenic).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 지형적 특징이 있는 곳에 가봤던 경험&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대학시절, 한라산에 가봤다. 남한에서 가장 높은 산이다. 한국의 유명한 휴양지인 제주도에 있다. 총 9시간이나 걸리는 트레킹이었는데 친구들이랑 종일 떠드느라 재미있었다. 풍경은 진짜 꿈 같았고 아름다웠다. 힘들었지만 너무 좋은 기억이다. 하지만 누가 한번 더 가라고 하면 안갈 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;8,9,10&amp;nbsp; &quot;집&quot;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 너의 집 묘사해봐라.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: 사무실 건물에 살고 있다. private bathroom 없다. 헬스장에서 샤워한다. 불편하지만 난 내가 사는 곳이 좋다. 개들이랑 살아도 될 만큼 넓다. 주변에 공원도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 집에서 있었던 문제, 뭔가 부러졌을 수도 있고 ~~ 어떻게 해결했나?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: 아.. 아까 집 수리한 거 이미 말했는데,, 흠 또 뭐가 있었을까? 아 에어컨이 고장났었어. service center에 전화했는데 내 거 outdated해서 새로 사는 게 낫다고 했어. 난 돈이 없었어. 그래서 고민했지만 날씨가 너무 sweltering해서 I had no choice but to buy a new one.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 집에서 있었던 일&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: 아.. 방금 질문이랑 비슷하네? 뭐 말하지..? 아 우리 집 개 두마리가 서로 싸운 거 얘기해 줄게. One day, my dogs got in a fight all of sudden. They are as big as a Siberian Husky. They are so strong. So, seperating them by myself was not easy because they are two and I am one!! Just,,, the only human. (이렇게 약간 유치원생 같이 말해도 별 문제 없는듯.) ...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;One of them was bleeding, so I took her to the vet. The reason they fought was that they had gotten jealous of each other. They often want to get affection from me at the same time. So, I have to watch out for it. I don't wanna encounter similar situation again. (의미는 명확히 전달되고 문법 상 틀린 건 없지만, 원어민이 자주 쓰는 부드러운 표현들이 아님.) It was awful. But thankfully, my dog was not,,, didn't hurt very much. (많이 다치진 않았어.라고 표현하고 싶었고 사실 문법 상 was not이 맞음)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;마무리도 좀 어색하고 중간에 내가 말하고 바로 정정한 부분도 꽤 많았다.(even if... even though ~... 이런 식으로 고침)&lt;br /&gt;쓰는 표현도 원어민이 쓰는 표현과는 거리가 먼 부분이 많았지만서도 AL을 받은 걸 보면&lt;br /&gt;디테일은 좀 틀리더라도&lt;br /&gt;의미전달이 명확한 것, 흐름이 자연스러운 것, 의사소통에 장애 없이(막힘 없이) 말하는 바의 논리적 구조(메인 포인트. 뒷받침하는 원인, 결과, 예시, 그에 따른 나의 감정 및 태도 등)를 명확히 표현하는 게 오픽에선 더 중요한 것 같다는 걸 말하고 싶었다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;11,12,13&amp;nbsp; &quot;전자기기&quot; 롤플레이&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 친구한테 mp3에 대한 질문 3개 물어봐라.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안녕? It's me. I'm interested in buying an MP3 player. 근데 니 거 맘에 들어. I have some questions about your MP3 player.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 질문 1: Is it durable?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 질문 2: Does it have Bluetooth feature?&amp;nbsp; (원어민은 보통 뒤에 'feature'를 붙이지 않는다고 한다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 질문 3: 얼마였어?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번주 주말에 사러 가야겠다. 고마워.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;질문 하고 대답 들은 것처럼 Awesome~~ Oh, What a steal! It's so cheap! 이런 식으로 반응했다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 친구 거 고장냈다. 어쩌다 그렇게 됐는지 말하고 대안 2개 제시해라.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;I'm terribly sorry. I dropped your MP3 player and its screen shattered.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(좀 캐쥬얼한 버전 : I've looked into a few ways to fix this. Let me know if any of these sound okay to you.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;I have some back-up options. If any of these work, please let me know.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 대안 1: 새거 사줄게. 아 부담스럽다고? (Is it too much?가 자연스럽다는데 나는 표현이 생각 안나서 Is it too burdensome?이라고 했음. - 좀 무거운 표현이라고 함.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 대안 2: 내가 서비스센터 가서 수리해서 돌려줄게.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 고장낸 경험 있나?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아... 너 아까부터 계속 똑같은 거 물어본다ㅠㅠ 나 이미 다 말해서 생각나는 게 없어.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;흠.. 마우스가 고장났었어. 컴퓨터 마우스 말이야. 그래서 새로 샀어. 그게 다야.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(딱 이정도만 말하고 넘겼음. 가장 짧게 답변한 문항.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&amp;nbsp;14,15&amp;nbsp; 국가간 관계&amp;nbsp;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 너의 나라와 다른 나라 사이의 관계 변화&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아이돌 산업이 발전하면서 우리나라와 아시아 국가들은 전보다 더 get along well하게 됐어.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 아시아 국가들은 한국의 문화와 cosmetic 산업 등 여러 sectors에 관심을 가지게 되었어.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것은 국가간의 정치, 경제에도 큰 영향을 주었어.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한국의 문화가 붐을 일으키면서 한국사람들도 그 변화에 많이 놀라고 있어.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세계적으로도 What's next from Korea? 하며 주목하고 있어.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&quot;비교&quot; 카테고리인 만큼,&lt;br /&gt;뒷 부분에 한국 문화의 세계적 인기에 대해 말할 것이 아니라&lt;br /&gt;과거에는 어땠는지를 말하며 대조시켰으면 좀더 좋았을 것 같다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 너의 나라와 주변국의 관계에 대해 설명해라. 역사적 관계 등...&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일본이 한국을 36년간 점령했었다. 한국은 지배 당하길 원하지 않았다. resistance가 많이 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tragic한 역사이다. Korean과 Japanese는 이 역사를 잊으면 안된다. it deserves more attention.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 일본 역사 교육은 well-organized 돼있지 않은 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 그게 내 생각이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;왜 잊으면 안되는지의 근거를 말했으면 좋았을 것 같다. (한국인이 착취 당했다는 문장 등을 넣어서)&lt;br /&gt;근거 없이 무지성 주장(더 관심 가져야한다)밖에 없었던 것 같아서 아쉬웠다.&lt;br /&gt;일본의 역사 교육이 잘 안돼있다고 생각하는 근거(예를 들면 일본 정치인이 이따금씩 이 문제에 대해 망언을 한다든지)도 넣고 옵션이지만 역사를 잊은 민족에게 미래는 없다 이런 명언도 넣어주면 좋을듯.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 질문에 대한 대답은 실제 답변했던 것보다 간략히 적기도 하였으나&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;14, 15번은 딱 위에 적은 대로만 대답했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간이 부족하여 14, 15번 풀 때 질문 청취를 한번만 하고서 답변했는데도 15번 다 말하고 나니 15초 남은 상황이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 심장이 너무 쫄깃했다. 괜히 더 풍부하게 한답시고 화제 꺼내서 애매한 문장으로 끝날 바엔 마무리 짓자 싶어서 그렇게 끝냈다. 빈약한 답변이라고 생각했는데 AL을 받아서 너무 다행이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1️⃣ 오픽이 좋아하는 답변&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 다들 알다시피&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 즉석에서 떠올려서 말하는 답변을 추구한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이상하게 막힘 없고 미리 준비한 것처럼 술술술 말하면 오히려 점수 낮게 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시험 복기에서 말했다시피&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 발화량이나 발화 시간, 고급 표현 사용 여부보다는 아래 사항이 더 중요한 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간결하지만 &lt;span style=&quot;color: #f89009; --darkreader-inline-color: var(--darkreader-text-f89009, #ffa127);&quot; data-darkreader-inline-color=&quot;&quot;&gt;논리적&lt;/span&gt;인(원인-결과, 예시, 그에 따른 감정, 생생한 묘사) &lt;span style=&quot;color: #f89009; --darkreader-inline-color: var(--darkreader-text-f89009, #ffa127);&quot; data-darkreader-inline-color=&quot;&quot;&gt;구성&lt;/span&gt;, 그로 인해 &lt;span style=&quot;color: #f89009; --darkreader-inline-color: var(--darkreader-text-f89009, #ffa127);&quot; data-darkreader-inline-color=&quot;&quot;&gt;말하고자 하는 바가 명확&lt;/span&gt;한 스피킹. &lt;span style=&quot;color: #f89009;&quot; data-darkreader-inline-color=&quot;&quot;&gt;이를 위한 플로우가 원활&lt;/span&gt;한지.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좋은 글쓰기가 뭔지 가르칠 때 응집성 있는 글쓰기를 하라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;말하기도 비슷한 것 같다. MP(메인 포인트)를 제시하고 뒤에 예시, 인과관계, 그에 따른 감정, 생동감 넘치는 설명 등이 나오지만 이것들은 모두 MP를 가리킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오픽에서는 1분 남짓 말하므로 개요 속 예시, 인과관계 등이 각각 1~2문장 정도만 차지해도 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 한 주제에 대해서만 응집성 있게 말하면 심플하고 알아듣기 쉬울 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 오픽노잼에서도 메인포인트를 한 가지로 잡고 1분~1분30초만 말하라고 한다. (발화 시간은 긴 것보다는 짧은 게 나은 듯)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영어는 수단이고 목적은 의사 전달이다. 영어 시험이지만 '말하기' 시험이기도 하니까 답변 구성도 중요한 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;+) 오픽노잼에서 배운 내용들, 첨삭 받은 답변 구성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오픽노잼의 SMART, PERFECT 전략에 대해서도 찾아봤는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@snghyun/%EC%98%A4%ED%94%BD%EB%85%B8%EC%9E%BC-PERFECT-%EC%A0%84%EB%9E%B5&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://velog.io/@snghyun/%EC%98%A4%ED%94%BD%EB%85%B8%EC%9E%BC-PERFECT-%EC%A0%84%EB%9E%B5&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 전략의 핵심은 뭔가 자유분방해 보이면서도 결국 MP에 대해 여러 방식(생생한 묘사, 비교대조, 교훈)으로 설명하는 말하기를 하라인 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 그 핵심은 지키되 세부 항목들에 엄청 연연하지는 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;caret-color: auto; letter-spacing: 0px;&quot;&gt;그리고 아래는 오픽노잼 관계자 분이 내 답변을 SMART 전략에 맞게 첨삭해주신 샘플이다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;우선 첫 번째 답변 피드백드릴테니, 참고하셔서 다른 답변에도 적용해보세요&lt;br /&gt;S: MP는 항상 간결하고 깔끔해야 해요! 지금 적어주신 MP는 너무 길고 내용이 헷갈려요. 아래 수정해드린 내용 보시고 다른 답변에도 이 느낌으로 적용해보세요!&lt;br /&gt;What: 나는 내 사무실에 살아 Feeling: 만족해 Why: 강아지들이랑 살 수 있어서&lt;br /&gt;M: 여기서 불편한 점을 예시로 드시는 거예요 ex) 렌트가 비싸다, private bathroom이 없다 등등&lt;br /&gt;A: MP로 다시 돌아오기 ex) 하지만 좋은 점이 더 많아. 왜냐하면 내 강아지들 사이즈가 좀 큰데, 얘네랑 살기 딱 좋을 만큼 넓어. 그리고 근처에 공원도 있어서 산책하기도 좋아. 등등(헬스장 얘기는 MP에서 너무 벗어나버리는 것 같아 뺐어요~)&lt;br /&gt;R: 항상 주제와 MP를 기억하셔서 연결지어주세요! ex) 렌트가 비싸도 여기 계속 사는 게 좋겠다는 걸 깨달았어(집 토픽에서 벗어나지 않게)&lt;br /&gt;T: 내용 조금만 짧게 줄여주시면 더 좋을 것 같아요&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;+) 내 케이스, 약점 보완&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;말의 속도에 자신 없는 사람은 곁가지 설명을 약간 덧붙이고 말하려 하면 팍팍 치고 나가는 말하기가 되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 초초반에 살짝 고민하는 척만 한 다음에 바로 메인포인트부터 말해버리는 게 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;곁가지를 표현하려다가 20초 이상 지나버리기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나의 경우엔 말이 느리니까 표현도 기억하기 쉽고 짧은 거 위주로 쓰려고 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(When I was an elementary student라고 하지 않고 그냥 When I was a kid라고 하는 식)&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;스피킹을 공부할 때 어려운 표현 위주로 외우며 공부하는 건 추천하지 않는다.&lt;br /&gt;내가 영어 유튜브 같은 거 보며 표현을 메모하기도 하면서 조금씩 공부해왔는데 스피킹 실력이 늘지 않았던 건 이러한 이유 때문이었다.&lt;br /&gt;I'll make good use of it.(잘 쓸게) 이런 표현 좋지만, 막상 말하려고 하면 표현이 헷갈린다.&lt;br /&gt;결국 난 전반적으로 내가 말하고자 하는 바를 잘 표현하지 못했다. 그러면 스피킹 평가자는 얘는 의사소통이 원활하지 않구나라고 판단한다. &lt;br /&gt;&quot;잘 쓸게&quot;를 말하고 싶을 때 사실 그냥 I'll use it well.이라고 말하면 되는데 그게 안되는 단계에서 I'll make good use of it.을 외우면 오히려 입이 안트이는 것이다.&lt;br /&gt;&lt;br /&gt;즉,&lt;br /&gt;몰랐던 관용 표현 등을 넓게 많이 알아두면 리스닝 할 때에는 좋겠지만,&lt;br /&gt;그런 표현을 배웠다면 그걸 표현하는 쉬운 방식도 필히 말로 뱉을 수 있어야 한다.&lt;br /&gt;말할 때 쓸 표현은 쉬운 영어를 쓰는 표현 방식들로 여러 가지 알아두는 게 좋다. (하나가 기억 안나면 바로 다른 걸로 땜빵 가능하게 여러 어휘 알기.)&lt;br /&gt;&lt;br /&gt;어려운 표현을 공부하려면 그냥 알아두는 정도로 공부해야하는 게 아니라 내가 자유자재로 활용하는 연습을 해봐야 시험 상황에 자연스럽게 입에서 나올 수 있다.&lt;br /&gt;의사 소통을 할 때에는 내가 이 다음에 무슨 말을 할지 내용을 생각하기도 바쁜데&lt;br /&gt;그 영어표현 자체를 구사하기에도 어색해 버리면 머릿속 작업기억 용량이 부족해진다.&lt;br /&gt;&lt;br /&gt;다시 예를 들자면, I'm in the middle of something. (나 지금 뭐 좀 하는 중이야.)이라는 표현을 외웠다고 해서 사용하려고 하는데 막상 말할 때 in이던가 on이던가 헷갈려하며 말하면 이미 말하는 속도가 쳐지고 내가 말하고자 하는 바를 말하는 데에 시간이 걸리게 된다. &lt;br /&gt;그니까 한국어랑 비슷해서 직관적으로 받아들여지는 표현 위주로 알아두고, 쉬운 영어를 사용해서&lt;br /&gt;말할 때 처짐 없이 탁탁 치고 나가는 게 좋다.&lt;br /&gt;사실 영어를 자연스럽게 구사하려면 원어민이 자주 쓰는 word choice를 익히는 것이 중요한데&lt;br /&gt;오픽 AL에서는 플로우가 원활하고 의사소통의 명확성이 있다면, 사소한 부자연스러운 word choice 정도는 봐주는 듯하다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2️⃣ 내가 생각하는 전략&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 다양한 상황에서 내 의사를 표현하는 능력이 뒷받침되어야 고득점이 나올 테지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(오픽의 다양한 질문 카테고리를 연습해보는게 좋고 예상 못한 질문에 대해서도 말할 수 있어야 하지만)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런 능력이 좀 부족하더라도 그렇게 보일 수 있는 방법은 있을 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 나올 수 있는 여러 질문 종류들을 포괄하는 답변을 연습해두기.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;선택 주제&quot;는 내가 survey에서 선택한 주제고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;돌발 주제&quot;는 선택 주제와 상관 없이 나올 수 있는 주제들이다. 예를 들면, 지형, 가족/친구, 재활용, 모임, 날씨, 가구, 교통수단, 미용실, 기술/인터넷, 다른나라? 등이 있을 수 있다.(엄청 많으니까 찾아보시길)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위는 topic에 대한 것이었고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유형에 대해서도 알아둬야 한다. Description, Habit, Past Experience, Comparison의 카테고리가 있고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Past Experience에서는 전형적으로 과거 경험, 그 토픽 관련된 생애 첫번째 경험, 가장 최근 경험, 문제 경험 이런 걸 물어본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 유형은 콤보세트(3문제씩) 3세트, 11번 롤플레이(질문하기), 12번 롤플레이(대안 제시), 13번 그런 문제 상황과 관련된 나의 경험, 14번 비교, 15번 사회적 이슈(범위를 '나'에서 '사람들'로 확장시켜 발화하기.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주제들을 보고, 여러 주제들을 포괄할 수 있는 답안을 개인적 버전으로 만들어 준비하며 연습해본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들면, 주거 개선, 집에서 보내는 휴가, 집, 집에서 일어난 문제 상황, 가구 질문 등등을 모두 포괄할 만한 소재인 '내 방의 책상 다리의 균형이 안맞아서 두꺼운 종이 넣어서 수평 맞춘 썰' 같은 걸 연습해두는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;+) 미리 구성한 답안이라면 오픽노잼 선생님처럼 약간의 재미 요소를 집어넣으면 좋다. 웃긴 썰을 푼다든지, 과장을 한다든지 (걔 완전 쓰레기였어!! 이런 거) 재미 요소를 집어 넣으면 생동감 있기도 하고 수많은 답변을 들어야 할 감독관이 듣기에도 좋을 듯. 아니면 뭔가 임팩트 있는 본인의 생각을 넣는다든가...&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 썰을 조직하고 연습할 때는 그 답안을 스크립트로 써서 읽어 보면서 외우는 게 아니라&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 뭔 말 할지 개요를 생각해두는 것이다. Main point, 예시, 원인, 배운 점, 결과, 태도나 감정 등의 플로우(개요)를 기억해두는 정도로 연습하고 그 플로우를 통한 의사 표현을 위해 쓰려고 하는 영어 단어들을 정리해둔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(이렇게 정리해 둔 거는 시험 전에도&amp;nbsp; 읽으면 리마인드가 될 것이고 시험장에서 문제를 딱 듣고 고민하는 시간에 어떤 표현들을 쓸 지를 빠르게 떠올려 둔 다음에 그걸 바탕으로 즉석에서 답변을 조직하는 것이다. 그러면 즉석에서 직접 떠올려서 답변하는 자연스러운 느낌이 든다.) 개요의 세부 요소들은 당연히 다 있을 필요는 없다. 그저 &lt;span style=&quot;color: #f89009;&quot; data-darkreader-inline-color=&quot;&quot;&gt;MP에 대한 논리가 드러나면 MP가 더 명료하게 설명되기 때문에&lt;/span&gt; 저런 논리적 흐름을 만들자는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 답안에서 쓸 수 있는 고정된 프레임을 만들기.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오픽노잼 선생님이 답변은 꼭 1분~1분30초 안에 하라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;늘어지고 장황해지지 않도록 MP를 필두로 한 심플하고 명확한 플로우 만들기를 염두에 둔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1분은 짧은 시간이다. 짧은 시간 동안 영어 자유롭게 쓰는 것처럼 보이려면 프레임을 어느 정도 만들어둠으로써 인지적 자원(작업 기억 용량)을 절약하는 것이 좋다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프레임을 만든다는 얘기는 다음과 같다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1) form 이 있는 문장을 연습해 두기.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; It makes ~ , I find ~(5형식).&amp;nbsp; It makes는 사물을 주어로 하는 영어스러운 문장이어서 좋음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; It takes 사람 시간 to부정사, have difficulty -ing,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; It was not until 일어난 일(과거형) that 그로인한 결과(과거형) : 이거는 체화되지 않았으면 안쓰는 게 좋을듯.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; For the most part, ~ but that doesn't mean there aren't any exceptions. In some case- on rare occasions ~~.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; The reason that~~ is because~~.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 문장 덩어리들을 체화해두면 인지 자원도 아끼고 프레임 안에 가정법(If I had to choose one, I would choose ~~. If I were given the choice, I would definitely opt for A rather than B)이나 과거완료 문장(I should have bought Bitcoin. If I hadn't missed that opportunity, I might have become a rich person by now.) 등을 넣어둔다면 문법적 수준이 있는 말하기를 하는 것도 보여줄 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;+) 문법 지식을 드러내는 문장을 꼭 넣어줘야하냐 싶을 수도 있는데 나는 AL 받은 시험에서 과거완료 문장을 말하긴 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 어떤 강사가 오픽 발화 상황에서 과거완료를 말할 일이 잘 없다고 하시기도 했고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 영상에서는 형용사 위주의 발화를 했으니 굳이 고급문법?을 넣어야 하는 건 아닌 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;난 아래 영상을 많이 봤는데 이 선생님께서는 길지 않은 문장을 풍부한 형용사를 써서 이야기하신다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좋은 방법이라고 생각한다. 그래서 나도 주제 별로 여러 형용사를 알려고 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 말하는 속도감도 약간 생기 있게 빠르셔서 좋았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 말이 느리기 때문에 시험 전에 이 영상을 보며 비슷한 텐션을 유지하려고 노력했다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://youtu.be/D4O4DrlGHBc?si=Tt1Cb2A_NQDlKUkj&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://youtu.be/D4O4DrlGHBc?si=Tt1Cb2A_NQDlKUkj&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=D4O4DrlGHBc&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/j2Dal/hyZQQBYwmv/JJWo0QGyShhRWk6e0FFuEk/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=354_128_888_366,https://scrap.kakaocdn.net/dn/gaZg9/hyZQ4UwC0j/ywMEzaRZzsHiD7z5kijxF0/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=354_128_888_366&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-title=&quot;오픽 AL 실제 시험 영상! 쉬운 답변으로 AL 받는 법&quot; data-original-url=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/D4O4DrlGHBc&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2) 답변 초초반, 후반의 프레임&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 답변을 하다보면 초초반(질문에 대한 반응), 후반 마무리에 무슨말 해야할지 모르겠어서 어정쩡해질 때가 많았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 문제 수만큼 초초반, 후반에 어떤 표현 쓸 건지 정리해두었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 답변 콘텐츠에 대한 고민만 해도 되며, 할말 없어질 때 바로바로 자신감있게 쓰기 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오픽노잼에서 알려주는 Positive-negative 전략, Quick comparison 전략, direct quotation 전략 등도 이런 프레임(할말 없을 때 딱 쓰기 좋은)의 일종이라고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초초반 :&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Yes I've had sth like that happened to me before.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Oh You wanna know about ~~.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Telling about ~~? Well, let me see...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- (생각할 시간 벌어야할 때. &quot;이런 질문 받아본 적 없어..&quot;, &quot;I can't think of anything on the spot right now... Let me see...&quot;)This is a pretty huge question. I haven't thought it before. Could you give me a minute to think? Alright, let me try.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- I've got a couple of things on my list.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초반 :&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- There's time when ~~. (~~때가 있어요.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- I'm gonna talk about the time when ~~.&lt;/p&gt;
&lt;p style=&quot;color: #cec9c2; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;- My first ~ experience was when I was ~~&lt;/p&gt;
&lt;p style=&quot;color: #cec9c2; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;- Let me start off with this. / Let me put it this way.&lt;/p&gt;
&lt;p style=&quot;color: #cec9c2; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #cec9c2; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #cec9c2; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;후반:&lt;/p&gt;
&lt;p style=&quot;color: #cec9c2; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;Long story short, It was quite an experience. (굉장한 경험이었어요.)&lt;/p&gt;
&lt;p style=&quot;color: #cec9c2; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;I feel as if ~&lt;/p&gt;
&lt;p style=&quot;color: #cec9c2; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;Hopefully I'll learn my lesson that ~~.&lt;/p&gt;
&lt;p style=&quot;color: #cec9c2; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;That's pretty much it. To sum up, ~&lt;/p&gt;
&lt;p style=&quot;color: #cec9c2; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;Overall, ~&lt;/p&gt;
&lt;p style=&quot;color: #cec9c2; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;All in all, ~&lt;/p&gt;
&lt;p style=&quot;color: #cec9c2; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #cec9c2; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;후후반:&lt;/p&gt;
&lt;p style=&quot;color: #cec9c2; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;I hope that answers your question.&lt;/p&gt;
&lt;p style=&quot;color: #cec9c2; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;I think that pretty much sums it up.&lt;/p&gt;
&lt;p style=&quot;color: #cec9c2; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;That's why I think ~&lt;/p&gt;
&lt;p style=&quot;color: #cec9c2; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;I guess that's all I can say about this for now.&lt;/p&gt;
&lt;p style=&quot;color: #cec9c2; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;That's my take on (주제).&lt;/p&gt;
&lt;p style=&quot;color: #cec9c2; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;Let's move on to the next question.&lt;/p&gt;
&lt;p style=&quot;color: #cec9c2; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3) 유형별로 쓸 수 있는 프레임&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;11, 12 롤플레이는 항상 같은 유형들이 나오니까 어떤 말을 쓸지 예상해둘 수 있고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비교 질문에서 쓰기 좋은 문장들도 미리 생각해둘 수 있고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;15번은 사회적 이슈에 대해 나오니까&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;규제가 더 필요하다든지,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사람들의 관심과 노력이 더 필요하다든지 등의 말은 미리 생각해두고 어떤 주제가 나오든 갖다 붙이기 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 '만능 패턴'이라고 검색하면 나오듯이 어느 주제에서도 말할 수 있는 썰을 생각해두고 약간의 주제 특화요소만 약간씩 집어넣어서 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어서 싸우다 헤어지는 커플을 본 썰은 카페 주제에서 말할 수 있겠지만 뭐 헬스장 주제에서도 어떤 커플이 헬스장 앞에서 언쟁하고 있었다. 그 커플은 gym crush에서 발전한 관계 같다. 하며 풀 수 있을 것이다.(주제 특화요소는 옵션이다. 즉석에서 생각해서 집어넣는 게 어렵다면 안 넣어도 될 것 같다.) 어디서든 커플은 싸울 수 있을 테니까.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;꼼수 같을 수도 있지만 공부 양이 적진 않았던 것 같은데 성적이 안나온다고 느꼈다면 구조적인 노력도 하는 게 좋다고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cf. 각자의 약점에 맞는 방법을 찾으시길!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 방법들은 작업 기억 용량이 크지 않은 나에 맞추어 생각해 본 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 분들도 각자 답변을 녹음하여 들어보면서 어떤 게 문제인지, 오픽에서 좋아하는 답변을 하기 위해선 어떤 방법을 쓰는 게 좋을지 고민하여 각자의 문제를 해결하는 방법을 쓰는 게 좋을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cf. 시험에 맞춘 공부법이 아니라 영어 스피킹 실력을 올리기 위해 내가 했던 기본적 스피킹 공부법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 주제에 대해 1분간 녹음하며 말해보고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 말하고싶었는데 잘 안됐던 부분이나 어색한 부분 보완한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후, 다시 그 주제에 대해 2분 말해보고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 보완해서 시간 제한 없이 할 수 있는 만큼 떠들어보기.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;+) 시험 문제 예상하기.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2번 ~ 10번 : 콤보세트 3*3,&amp;nbsp; 11번~13번 : 롤플레이 세트 3*1&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;14, 15번 : 한 주제로 2문제&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이고 콤보세트에서는 6-6 난이도를 선택했을 때 첫문항으로 Description이나 Habit, 두번째세번째문항으로 과거경험이나 비교가 나온다고 한다. 그리고 오픽은&lt;span style=&quot;color: #f89009;&quot; data-darkreader-inline-color=&quot;&quot;&gt; 한 문항 풀고 넘기고서 다음문항의 질문 청취하기 버튼을 클릭하기 전에 살짝 쉴 수 있다&lt;/span&gt;.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그때 다음 문항이 무엇일지 예상하며 대략 풀 썰이나 표현들을 생각할 수가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 &lt;b&gt;&lt;span style=&quot;color: #f89009;&quot; data-darkreader-inline-color=&quot;&quot;&gt;시험시간이 생각보다 길지 않&lt;/span&gt;으&lt;/b&gt;므로 시험 시간 계산을 잘해야한다. 나는 그렇게 시간 쓰다가 매번 시간 분배 실패해서 14,15번은 질문 청취 한번만 하고 바로 답변해야 했다.ㅠㅠ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;+) 문제에서 나온 어휘 활용하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초반에 할말이 정 기억 안난다면 문제에서 말한 어휘를 기억해뒀다가 사용하는 것도 괜찮을 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3️⃣ 시험에 대한 정보&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 오픽 공부하는 분들과 소통하다가 얻은 정보인데 오픽 시험 정책은 언제든 바뀔 수 있는 것이니 혹시 틀린 정보여도 책임 지지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- survey에서 운동을 전혀 안함, 조깅, 걷기, 헬스를 선택했을 때에는 보통 헬스에 대해서만 나온다고 함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- survey에서 영화,콘서트,공연보기를 선택했을 때 콤보세트에서는 콘서트, 공연보기가 잘 나오지 않는다고 함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 Role play에서는 live music 보러간 role play 등이 나올 수 있음. (아파서 공연 못 가게 됐을 때 대안 제시, 티켓 구매 후 공연 갈 수 없었던 경험.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 영화 선택했을 시에 14,15번 영화 관련 질문 답할 수 있어야 함. 영화 관련 사회적 이슈, 영화 배우에 대한 뉴스 등이 나올 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 반려동물 선택했을 시에 14,15번 반려동물 종류 비교, 반려동물에 대한 사회적 이슈 등이 나올수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 음악 감상 선택했을 시에 전자기기, 장비나 기술 발전에 대한 질문이 나올 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 휴가 선택했을 시에 과거와 현재의 휴가 방법 비교, 휴가의 장점과 중요성에 대한 질문이 나올 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 내가 선택한 주제 별로 나올 수 있는 기출 질문을 대비하면 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;평가자가 채점할 시에 가장 중요하게 생각하는 부분이 롤플레이, 14, 15번, 돌발 주제이기 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 IH는 나오는데 AL이 안나온다면 이 부분들을 잘 대비하는 것이 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;➡️ Outro&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;말하고자 하는 바를 영어로 잘 표현할 수 있는 프리토킹이 꽤 되면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 위에 말했던 것들 딱히 익힐 필요 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'메인 포인트 한 가지에 대해서만 말하기' 정도만 염두에 두면 AL 받을 수 있을 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 틀린 부분이 좀 있어도 AL 나올 수 있으니까&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;틀린 거에 연연하지 말고 기세 있게! 플로우를 신경 쓰는 말하기(+감정 표현도 좀 섞어서)를 하면 아! 얘 의사소통이 되는 스피킹을 하는구나!라고 여길 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하고 싶은 말이 너무 많아지는 순간 AL 받기 어려워지는 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;심플하고 명확하게 말하자. 그리고 할말 없어질 때에도 자신감 있게 말하기 위해서 답변에서 고정될 만한 프레임들은 좀 준비해 가자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 내가 만약 벼락치기를 한다면 주제별(선택,돌발), 유형별로 할 말의 개요를 짜놓고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관련 어휘, 영어표현들을 적어 놓을 것이다. 메인 포인트는 답변 중 반복할 가능성이 높은데 같은 단어 반복하는 것보다는 paraphrase한 여러 표현들을 알아둔다면 어휘력이 좋아보일 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 시험 전에 리마인드할 것이다. 말하기를 연습할 때에는 여러 주제를 포괄할 수 있는 썰을 준비한다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시험장에서 문제를 들을 때는 첫번째 들을 때 주의 깊게 듣고 잘 파악(유형도 캐치)한 다음에, 두번째 들으면서 미리 생각해놓은 표현들, 개요(무슨 말 할지)를 빠르게 떠올린다. 떠올린 표현들 위주로 엮어가며 답변한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 단기기억형들은 하루 종일 공부하여 뇌를 영어 체제로 만들어 놓고 늦은 시간 시험을 보는 게 확실히 도움된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 18시 대 시험을 봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 IH 받은 시험에서랑 AL 받은 시험에서 달랐던 점.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: IH 받은 시험에서는 내가 하고자 하는 말을 영어로 잘 표현하지 못했음. 그래서 말하다가 막히는 부분이 있었음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(말하다가 막혔을 때 바로 다른 방식으로 표현해내면 딱히 감점 요인이 아닐 텐데 나는 그것도 잘 안됐음.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 말을 할 때 몇몇 부분에서 떠올리고 싶은 단어가 떠오르지 않아 딜레이가 생겼음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;⏹️ 여담&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디스코드에서 원어민들과 교류해보며 느낀 건데 한국인이 생각하는 영어 잘하는 사람이랑 원어민이 생각하는 영어 잘하는 사람은 좀 다른 것 같다. 한국인들은 원어민처럼 발음이 자연스럽고 문장을 길게 말하는데도 유려한 모먼트들이 있을 때 영어를 잘한다고 생각한다. 하지만 원어민이 봤을 때에는 그런 모먼트들이 없어도 그냥 전반적으로 의사소통이 잘 되는 사람을 잘한다고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중간 중간 실수도 하고 발음이 좋지 않고 짧은 영어를 한다 해도 자신의 플로우로 의사를 명확히 전달할 수 있는 사람!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://youtube.com/shorts/kTveq-4Df4w?si=H0k3OZTRxduUq3QP&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://youtube.com/shorts/kTveq-4Df4w?si=H0k3OZTRxduUq3QP&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많이 과장하자면, 영어를 잘 못해도 &lt;span style=&quot;color: #f89009; --darkreader-inline-color: var(--darkreader-text-006dd7, #51b5ff);&quot; data-darkreader-inline-color=&quot;&quot;&gt;리스닝&lt;/span&gt;이 잘 되고 상대의 니즈를 이해하여 감정을 교류할 수 있는 가와사키식 영어가 한 예시이다. 맞고 틀리는 게 중요한 게 아니라 전달이 중요한 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무튼 가와사키처럼 스피킹을 잘 못해도 원어민이 대화 나누고 싶어 하는 호감캐가 될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무튼 나는 그닥 잘하진 못해도 오픽에서 장황한 말을 삼가고 문법적 오류를 줄인 답변을 해서 AL을 받은 것 같다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 나름 흥미가 있어서 열심히 공부한 것 같다. 혼자 답변을 조직하는 시간도 필요하지만 다른 사람들이랑 서로 답변 피드백 해주면서 공부하는 것도 추천한다. 같이 하면 강제성이 생기고 기억에 잘 남고 노는 것처럼 공부하는 느낌이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간이 되면 오픽 커뮤니티(오픽 강사별로 운영하는 커뮤니티가 있을듯)를 찾아서 사람들과 같이 연습하는 것 추천!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞으로도 영어는 꾸준히 공부할 것이다!!! 영어 열심히 공부하시는 분들과 같이 공부하고 싶다!&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;niniz&quot; data-emoticon-name=&quot;022&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/niniz/large/022.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/niniz/large/022.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Achievements  </category>
      <author>승실</author>
      <guid isPermaLink="true">https://nowallnow.tistory.com/33</guid>
      <comments>https://nowallnow.tistory.com/entry/Opic-AL-%ED%9B%84%EA%B8%B0-%EA%BF%80%ED%8C%81-%EA%B5%AD%EB%82%B4%ED%8C%8C-IH%EC%97%90%EC%84%9C-AL-%EB%B0%9B%EC%9D%80-%ED%9B%84%EA%B8%B0#entry33comment</comments>
      <pubDate>Fri, 26 Dec 2025 14:43:06 +0900</pubDate>
    </item>
    <item>
      <title>Spring Boot &amp;amp; React 초간단 REST API 게시판 만들기</title>
      <link>https://nowallnow.tistory.com/entry/Spring-Boot-React-%EC%B4%88%EA%B0%84%EB%8B%A8-REST-API-%EA%B2%8C%EC%8B%9C%ED%8C%90-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;0️⃣ 목표&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #f89009;&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;b&gt;프론트엔드&lt;/b&gt;와 &lt;b&gt;백엔드&lt;/b&gt;의 상호작용&lt;/span&gt;을 통해 &lt;b&gt;데이터를 주고 받는 흐름&lt;/b&gt; 읽기.&lt;br /&gt;&lt;b&gt;REST API&lt;/b&gt; 기본 개념 배우고 실습을 통해 경험하기.&lt;br /&gt;간단한 게시판 프로젝트를 통해 &lt;b&gt;웹 애플리케이션 개발의 흐름&lt;/b&gt; 이해하기.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;할일&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;color: #f89009; --darkreader-inline-color: var(--darkreader-text-f89009, #ffa127);&quot; data-darkreader-inline-color=&quot;&quot;&gt;React.js&lt;/span&gt;를 사용한 간단한 사용자 인터페이스(&lt;span style=&quot;color: #f89009; --darkreader-inline-color: var(--darkreader-text-f89009, #ffa127);&quot; data-darkreader-inline-color=&quot;&quot;&gt;UI&lt;/span&gt;) &lt;span style=&quot;color: #f89009; --darkreader-inline-color: var(--darkreader-text-f89009, #ffa127);&quot; data-darkreader-inline-color=&quot;&quot;&gt;구현&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Spring Boot를 이용한 &lt;span style=&quot;color: #f89009; --darkreader-inline-color: var(--darkreader-text-f89009, #ffa127);&quot; data-darkreader-inline-color=&quot;&quot;&gt;RESTful API 구축&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;CRUD 기능(생성, 조회, 수정, 삭제)이 포함된 게시판 기능 구현&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;color: #f89009; --darkreader-inline-color: var(--darkreader-text-f89009, #ffa127);&quot; data-darkreader-inline-color=&quot;&quot;&gt;Axios&lt;/span&gt;를 활용한 클라이언트와 서버 간 데이터 통신&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;간단한 MySQL 데이터베이스 연동 및 사용법&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;+) JPA는 간단히 사용만 할 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;ℹ️ 배경지식&lt;/span&gt;&lt;/h2&gt;
&lt;h3 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot; data-darkreader-inline-color=&quot;&quot;&gt;1. CSS는 전역(Global)이다.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CSS는 한번 로드되면 전체 페이지에 적용된다. 이건 React를 쓰든 안 쓰든 똑같이 적용되는 웹의 기본 동작이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #cec9c2; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot;&gt;태그에 전에 쓰던 클래스 이름을 똑같이 쓰면,&lt;/span&gt; 다른 React 컴포넌트 파일에 import된 css여도 적용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 따로 스타일 주고 싶으면 클래스 이름을 바꾸거나 CSS Module을 쓴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;jsx&lt;/p&gt;
&lt;pre id=&quot;code_1765772905027&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import styles from &quot;./PostEdit.module.css&quot;;

&amp;lt;div className={styles.postEditContainer}&amp;gt;내용&amp;hellip;&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;css&lt;/p&gt;
&lt;pre id=&quot;code_1765772928404&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/* PostEdit.module.css */
.postEditContainer {
  background: #fafafa;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1️⃣ Spring Boot와 React 실행하기&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. Spring Boot&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Spring-Boot-Workflow-Architecture-1024x614-photoaidcom-invert.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;614&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mZlvO/dJMcacBDPBH/KGEOGTuf3vBPRfhM2TFYxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mZlvO/dJMcacBDPBH/KGEOGTuf3vBPRfhM2TFYxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mZlvO/dJMcacBDPBH/KGEOGTuf3vBPRfhM2TFYxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmZlvO%2FdJMcacBDPBH%2FKGEOGTuf3vBPRfhM2TFYxk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;647&quot; height=&quot;388&quot; data-filename=&quot;Spring-Boot-Workflow-Architecture-1024x614-photoaidcom-invert.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;614&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;img src=&quot;https://velog.velcdn.com/images/snghyun/post/ba33f9c8-5da8-46fb-86f0-36afe0f896a7/image.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;만약 남이 하던 프로젝트를 받아서 node_modules 디렉터리 이하의 라이브러리들이 없다면 터미널에서 `npm i(npm install)`를&amp;nbsp; 명령한다. 그러면 package.json에 있는 내용들에 따라 라이브러리들이 설치된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. React&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;⚛️ React dev server&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; ️&amp;zwj; ️ React 실행하면 왜 localhost:3000이 뜰까?&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React 자체는 브라우저에서만 실행되는 프론트엔드 라이브러리이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 개발할 때는&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;화면 자동 새로고침(Hot Reload)&lt;/li&gt;
&lt;li&gt;코드 변경 즉시 반영&lt;/li&gt;
&lt;li&gt;파일 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 기능이 필요하기 때문에 Vite, CRA 등이 임시 서버(dev server) 를 띄워주는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 React 실행하면 다음이 뜬다:&lt;/p&gt;
&lt;pre class=&quot;groovy&quot;&gt;&lt;code&gt;npm start    &amp;rarr;   http://localhost:3000&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 돌아가는 건 개발 편의용 임시 서버(Dev Server)이다.&lt;br /&gt;빌드 후 배포하면 이 dev server는 사라지고, React는 단순 정적 파일(HTML/JS)로 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 이는 일반적 웹서버와는 다르고 리액트는 서버 기능이 없음!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #456771; --darkreader-inline-color: var(--darkreader-text-006dd7, #51b5ff);&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;b&gt; &lt;span style=&quot;color: #0593d3;&quot; data-darkreader-inline-color=&quot;&quot;&gt; Web Server란?&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;브라우저에게 웹페이지를 전달해주는 프로그램(혹은 컴퓨터)&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;사용자가 주소창에 URL(예: &lt;a href=&quot;https://naver.com&quot;&gt;https://naver.com&lt;/a&gt;) 을 입력하면,&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;브라우저는 웹서버에 요청을 보내고&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;웹서버는 HTML, CSS, JS 같은 파일을 되돌려주는 역할을 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;즉,&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;⚡ &amp;ldquo;브라우저의 요청을 받아서, 필요한 웹페이지나 데이터를 되돌려주는 프로그램&amp;rdquo;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #456771;&quot; data-darkreader-inline-color=&quot;&quot;&gt; &lt;span style=&quot;color: #0593d3;&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;b&gt; 웹서버가 하는 일&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #456771;&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;웹서버는 크게 두 가지를 제공할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;  정적 파일 제공&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;정적 파일 = 내용이 고정된 파일&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;e.g. HTML, CSS, JavaScript, 이미지(jpg, png), React로 빌드한 결과물(정적 파일)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;브라우저가 아래처럼 요청하면 그대로 보내주기만 하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;GET /index.html&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&amp;rarr; index.html 파일 전달&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;  동적 데이터 제공 (API 서버 역할 포함 가능)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;서버가 요청을 받아서 로직을 처리하고 결과를 만들어 반환하는 것.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;GET /users/1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&amp;rarr; DB에서 사용자 정보 조회&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&amp;rarr; JSON 형태로 응답&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;즉, 동적 데이터 처리 = 백엔드의 영역이며,&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Spring Boot, Node.js(Express), Django 등이 이 역할을 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2️⃣ React UI 구현하기&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. React Router&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React에서 페이지 이동(라우팅)을 가능하게 해주는 라이브러리&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;React는 원래 한 페이지(Single Page Application)로 동작한다. 그래서 기본적으로는 URL이 바뀌어도 새 페이지로 이동하지 않는다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;하지만 웹사이트는 보통 /home, /about, /products처럼 페이지가 여러개이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이걸 가짜 페이지처럼 만들어서 URL에 따라 다른 화면을 보여주는 역할을 하는 것이 React Router이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;npm i react-router-dom
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;React Router 페이지 처리 완료&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;App.js&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1765466568822&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import './App.css';
import Home from './Home';
import CreatePost from './CreatePost';
import PostDetail from './PostDetail';
import{BrowserRouter as Router, Routes, Route} from &quot;react-router-dom&quot;;
import PostEdit from &quot;./PostEdit&quot;;

function App() {
  return (
      &amp;lt;Router&amp;gt;
          &amp;lt;div className=&quot;App&quot;&amp;gt;
              &amp;lt;Routes&amp;gt;
                  &amp;lt;Route path={&quot;/&quot;} element={&amp;lt;Home/&amp;gt;} /&amp;gt;
                  &amp;lt;Route path={&quot;/create&quot;} element={&amp;lt;CreatePost/&amp;gt;}/&amp;gt;
                  &amp;lt;Route path={&quot;/post/:id&quot;} element={&amp;lt;PostDetail/&amp;gt;}/&amp;gt;
                  &amp;lt;Route path={&quot;/post/edit/:id&quot;} element={&amp;lt;PostEdit/&amp;gt;}/&amp;gt;
              &amp;lt;/Routes&amp;gt;
          &amp;lt;/div&amp;gt;
      &amp;lt;/Router&amp;gt;
  );
}

export default App;

// 만들 page들
/*
*      /                 - post list
*      /create           - post create
*      /edit/:id         - post edit
*/&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;index.js&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1765466605569&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  &amp;lt;React.StrictMode&amp;gt;
    &amp;lt;App /&amp;gt;
  &amp;lt;/React.StrictMode&amp;gt;
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;PostEdit.js&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1765466656416&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let PostEdit = ()=&amp;gt;{
    return &amp;lt;div&amp;gt;게시글 수정&amp;lt;/div&amp;gt;
}

export default PostEdit;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;PostDetail.js&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1765466683784&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function PostDetail() {
    return &amp;lt;div&amp;gt;PostDetail&amp;lt;/div&amp;gt;;
}

export default PostDetail;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Home.js&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1765466712073&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Home() {
    return &amp;lt;h1&amp;gt;Home&amp;lt;/h1&amp;gt;;
}

export default Home;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CreatePost.js&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1765466736620&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function CreatePost() {
    return &amp;lt;div&amp;gt;Create&amp;lt;/div&amp;gt;;
}

export default CreatePost; // 있어야 함&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. React 컴포넌트를 정의하는 두 가지 문법&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #0593d3; --darkreader-inline-color: var(--darkreader-text-456771, #96b8c1);&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;b&gt;1) 함수 선언&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #456771;&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1765606189514&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Home() {
    return &amp;lt;h1&amp;gt;Home&amp;lt;/h1&amp;gt;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▪️ 전통적인 함수 선언 방식.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▪️ 컴포넌트 이름은 대문자로 시작해야 React가 컴포넌트로 인식함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▪️ 함수 이름이 호이스팅됨. (Hoisting : Javascript에서 코드를 실행하기 전에 전체 스코프를 한번 훑으며 선언을 위로 끌어올리는 과정)&amp;nbsp; 함수 선언식은 전체 함수 정의가 통째로 호이스팅되기 때문에(복사된다는 건 아니고 등록된다. 실행 전에 수행되는 '생성' 단계에서 함수 객체를 미리 메모리에 만들고 함수 이름을 해당 함수 객체를 가리키는 포인터로 스코프의 environment record에 등록한다.) 실행 단계에 들어갈 때 이미 함수 선언식의 전체 정의가 메모리에 포인터로 등록돼있다. 그래서 선언보다 위에서 호출해도 문제 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #0593d3; --darkreader-inline-color: var(--darkreader-text-456771, #96b8c1);&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;b&gt;2) 함수 표현식(Function Expression) + 화살표 함수(Arrow Function)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1765606303960&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const Home = () =&amp;gt; {
	return &amp;lt;h1&amp;gt;Home&amp;lt;/h1&amp;gt;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▪️ 변수를 선언한 뒤 그 변수에 화살표 함수를 넣는 방식&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▪️ `let` 또는 `const`를 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▪️ 호이스팅이 되지 않음,&amp;nbsp; Home이라는 변수 이름만 호이스팅 됨. &amp;rarr; 선언 전에 사용하면 오류 발생&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▪️ return 값이 하나면&amp;nbsp; `const Home = () =&amp;gt; &amp;lt;h1&amp;gt;Home&amp;lt;/h1&amp;gt;;` 이렇게 작성 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;React는 불변성(immutability)을 기본 철학으로 한다.&lt;br /&gt;리액트 컴포넌트는 함수이며 UI를 만드는 설계도다. 이 UI를 만드는 틀(컴포넌트)이 바뀌면 안되므로 const로 선언한다.&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot; data-darkreader-inline-color=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  axios란?&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저나 Node.js에서 백엔드랑 통신하기 위해 보내는 HTTP 요청을 쉽게 만들어주는 라이브러리&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;React에서 서버에 데이터를 요청하거나, 서버로 데이터를 보낼 때 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;vbscript&quot;&gt;&lt;code&gt;axios.get(&quot;http://localhost:8080/users&quot;)
  .then(response =&amp;gt; console.log(response.data))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;의미&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;/users API로 GET 요청 보냄&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Spring Boot가 JSON 데이터를 보내줌&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;React가 그 데이터를 화면에 표시함&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Playground  </category>
      <author>승실</author>
      <guid isPermaLink="true">https://nowallnow.tistory.com/32</guid>
      <comments>https://nowallnow.tistory.com/entry/Spring-Boot-React-%EC%B4%88%EA%B0%84%EB%8B%A8-REST-API-%EA%B2%8C%EC%8B%9C%ED%8C%90-%EB%A7%8C%EB%93%A4%EA%B8%B0#entry32comment</comments>
      <pubDate>Thu, 11 Dec 2025 16:52:55 +0900</pubDate>
    </item>
    <item>
      <title>LangChain 기본기 &amp;amp; LLM 호출 실습 (가상 환경 구축부터 자세히)</title>
      <link>https://nowallnow.tistory.com/entry/LangChain-%EA%B8%B0%EB%B3%B8%EA%B8%B0-LLM-%EC%8B%A4%EC%8A%B5</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;&lt;a title=&quot;강의 링크&quot; href=&quot;https://inf.run/KXFBf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;한 시간으로 끝내는 LangChain 기본기(강병진T)&lt;/a&gt;&quot; 강의를 시청하며 정리한 내용입니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt; ️ &amp;nbsp;Anaconda로 가상환경 만들고 에디터로는 Cursor를 쓴다.&amp;nbsp;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Langchain 기본기는 향후 반복적으로 활용할 것 같아서 정리해보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; ⛓️&amp;zwj;  Langchain이란? LLM 기반 애플리케이션을 쉽게 개발할 수 있게 해주는 Python / Javascript 프레임워크이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;0️⃣ 실습 환경 구축&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. Local에서 돌릴 LLM 다운로드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선, local에서 LLM을 돌려볼 것이다. local에서 돌릴 수 있는 모델들은 무료이며 오픈 소스로 공개된 모델들이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ollama를 설치하고서 터미널에서 `ollama pull llama3.2:1b` (llama라는 모델을 다운로드 받는다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`llama3.2:1b`는 Ollama 홈페이지에서 골라서 복사한 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;딥시크도 가져올 수 있다. (터미널에서 `ollama pull deepseek-r1:1.5b`)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1160&quot; data-origin-height=&quot;499&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Tl8mK/dJMcaaDBYo8/1rubKwvqwwprmUgXk7qSy1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Tl8mK/dJMcaaDBYo8/1rubKwvqwwprmUgXk7qSy1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Tl8mK/dJMcaaDBYo8/1rubKwvqwwprmUgXk7qSy1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTl8mK%2FdJMcaaDBYo8%2F1rubKwvqwwprmUgXk7qSy1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;848&quot; height=&quot;365&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1160&quot; data-origin-height=&quot;499&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 가상환경을 만들자.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뒤이어 나올 실습을 위한 가상 환경 세팅.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;강사님은 pyenv를 사용하셨고 나는 anaconda를 사용했다.&lt;/p&gt;
&lt;blockquote data-end=&quot;172&quot; data-start=&quot;127&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;p data-end=&quot;172&quot; data-start=&quot;129&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;text-align: left;&quot;&gt;cf. 가상 환경이란?&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;text-align: left;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #0593d3;&quot; data-darkreader-inline-color=&quot;&quot;&gt;프로젝트별로 독립된 Python 실행 공간&lt;/span&gt;을 만드&lt;/b&gt;는 기술.&lt;/span&gt; &lt;br /&gt;즉, &amp;ldquo;각 프로젝트가 자기 전용 파이썬 공간과 라이브러리를 따로 가지는 것&amp;rdquo;이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;anaconda prompt에서 `conda create -n langchain-basics python=3.11`을 명령하여 가상환경을 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 명령어로는 가상환경이 &quot;생성만&quot; 된다.현재 폴더에 생기는 것이 아니라 Conda가 관리하는 전역 환경 저장소 (예를 들면 C:\Users\&amp;lt;이름&amp;gt;\anaconda3\envs\langchain-basics)안에 만들어진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가상환경은 Conda 내부에 있으므로 어떤 폴더에서든 `activate`&amp;nbsp;를 하면 사용 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 루트가 되는 디렉토리 이름을 가상 환경 이름과 똑같이 하겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만든 langchain-basics 디렉토리로 들어가서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`conda activate langchain-basics(가상환경 이름)`&amp;nbsp; &amp;nbsp;(가상 환경 활성화)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 cursor 에디터를 써서 작업을 하겠다. (vscode, jupyter notebook 등 쓰고 싶은 에디터 쓰면 된다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`cursor .`&amp;nbsp; (cursor를 환경 변수에 등록해야지 된다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;➕ 강사님은 `pyenv local langchain-basics`를 하셨다. 하지만 아나콘다에는 이에 상응하는 것이 없다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 명령어는 &quot;이 프로젝트 폴더에서만 langchain-basics 가상환경을 기본 Python으로 쓰겠다&quot;는 뜻이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`pyenv`는 폴더 단위로 가상환경을 자동 선택하게 해주지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;폴더 진입 시 자동으로 특정 환경을 활성화하는 기능은 conda에 기본적으로 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 프로젝트 폴더에 들어갈 때마다 `conda activate langchain-basics`를 입력해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;➕ 가상환경 삭제하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`conda env list`&amp;nbsp; 가상환경 목록 보기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`conda remove --name 가상환경이름 --all`&amp;nbsp; &amp;nbsp;지정한 가상 환경 전체 삭제&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1️⃣ local LLM 호출&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 에디터에서 패키지 설치&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1540&quot; data-origin-height=&quot;260&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PTUC8/dJMcaiuSuVE/kWoJDcS7YU6JHN8ikf0R0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PTUC8/dJMcaiuSuVE/kWoJDcS7YU6JHN8ikf0R0K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PTUC8/dJMcaiuSuVE/kWoJDcS7YU6JHN8ikf0R0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPTUC8%2FdJMcaiuSuVE%2FkWoJDcS7YU6JHN8ikf0R0K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;815&quot; height=&quot;138&quot; data-origin-width=&quot;1540&quot; data-origin-height=&quot;260&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노란색으로 표시한 부분에서 환경을 내가 사용할 환경으로 골라줘야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Python 인터프리터 경로를 `langchain-basics` 환경의 파이썬으로 지정하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 ipykernel package를 설치해야 Jupyter notebook(.ipynb)를 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. local로 다운받은 LLM 호출&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치한 패키지 import 후, 아까 다운 받은 Ollama 호출해서 말 시켜본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ollama 데몬이 실행 중이어야 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1516&quot; data-origin-height=&quot;245&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bz66ro/dJMb99Y0tqW/swm29KgpGeOW1pjkVCLjzK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bz66ro/dJMb99Y0tqW/swm29KgpGeOW1pjkVCLjzK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bz66ro/dJMb99Y0tqW/swm29KgpGeOW1pjkVCLjzK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbz66ro%2FdJMb99Y0tqW%2Fswm29KgpGeOW1pjkVCLjzK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;791&quot; height=&quot;128&quot; data-origin-width=&quot;1516&quot; data-origin-height=&quot;245&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2️⃣ 상용화된 LLM 호출&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상용화된 모델을 API를 통해 호출해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GPT 호출할 때도 역시 패키지 설치한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;561&quot; data-origin-height=&quot;98&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oUtdb/dJMcaaXUNYd/49YFLxOtzQpqpHy7XZ9Nq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oUtdb/dJMcaaXUNYd/49YFLxOtzQpqpHy7XZ9Nq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oUtdb/dJMcaaXUNYd/49YFLxOtzQpqpHy7XZ9Nq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoUtdb%2FdJMcaaXUNYd%2F49YFLxOtzQpqpHy7XZ9Nq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;395&quot; height=&quot;69&quot; data-origin-width=&quot;561&quot; data-origin-height=&quot;98&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1762582274094&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model=&quot;gpt-4o-mini&quot;)

llm.invoke(&quot;What is one of the native dog breeds of Korea?&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번엔 이걸 실행하면 api key를 set하라며 에러가 난다.&lt;/p&gt;
&lt;pre id=&quot;code_1762595664107&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;The api_key client option must be set either by passing api_key to the client
or by setting the OPENAI_API_KEY environment variable&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OPENAI_API_KEY라는 환경 변수를 선언해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;API key 환경 변수 세팅&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OpenAI 홈페이지에서 발급받은 API key를 복사해온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`.env`파일에 `OPENAI_API_KEY=` 뒤에 붙여 넣어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;환경 변수 세팅을 위한 패키지 설치한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`%pip install -q python-dotenv`&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1762595921712&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from dotenv import load_dotenv

load_dotenv()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 실행했을 때 True 뜨면 잘 불러온 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;True가 안 뜬다면 Cursor 오른쪽 하단의 `UTF-8`표시 클릭하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;Reopen with Encoding&quot; &amp;rarr; &quot;UTF-8&quot; 선택,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 오른쪽 하단의 `UTF-8` 클릭 &amp;rarr; &quot;Save with Encoding&quot; &amp;rarr; &quot;UTF-8&quot;를 클릭한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;윈도우 메모장이나 일부 편집기는 UTF-8 with BOM을 기본으로 저장하다보니 `.env` 파일에 BOM(Byte Order Mark)이 숨겨져 있을 수 있기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 아까 안됐던 걸 실행하면 잘 실행된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1380&quot; data-origin-height=&quot;184&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vUjkk/dJMcahQgXlC/9DrXZ1siKmcgcxPDE1OChk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vUjkk/dJMcahQgXlC/9DrXZ1siKmcgcxPDE1OChk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vUjkk/dJMcahQgXlC/9DrXZ1siKmcgcxPDE1OChk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvUjkk%2FdJMcahQgXlC%2F9DrXZ1siKmcgcxPDE1OChk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;838&quot; height=&quot;112&quot; data-origin-width=&quot;1380&quot; data-origin-height=&quot;184&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #eeece9; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot;&gt;3️⃣ 프롬프트&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #eeece9; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot;&gt;`llm.invoke()`의 인자로 넣는 input에는 타입이 제한되어 있다.&lt;/span&gt;&lt;span style=&quot;color: #eeece9; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7; text-align: start; --darkreader-inline-color: var(--darkreader-text-eeece9, #e2dfda);&quot; data-darkreader-inline-color=&quot;&quot;&gt;Must be a &lt;u&gt;PromptValue&lt;/u&gt;, &lt;u&gt;str&lt;/u&gt;, or &lt;u&gt;list of BaseMessages&lt;/u&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. PromptValue&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #eeece9; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot;&gt;Langchain의 Prompt Template을 쓰면 PromptValue를 만들 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;949&quot; data-origin-height=&quot;438&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQxYMx/dJMcafkGxlV/LwPy1C14LSOYSrUqD57tU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQxYMx/dJMcafkGxlV/LwPy1C14LSOYSrUqD57tU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQxYMx/dJMcafkGxlV/LwPy1C14LSOYSrUqD57tU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQxYMx%2FdJMcafkGxlV%2FLwPy1C14LSOYSrUqD57tU1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;784&quot; height=&quot;438&quot; data-origin-width=&quot;949&quot; data-origin-height=&quot;438&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.ListofBaseMessages&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 이제 `BaseMessage`에 대해 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Langchain(Python 기준) `BaseMessage`를 상속받는 클래스는 대표적으로 4개가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▫️ `SystemMessage` : 시스템 프롬프트. 주로 여기에 LLM Application의 목적, 할일을 정의해 줌.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #cec9c2; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot;&gt;▫️&lt;span&gt; `HumanMessage` : 사용자(사람) 메시지&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #cec9c2; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot;&gt;▫️&lt;span&gt; `AIMessage` : LLM 메시지&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #cec9c2; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot;&gt;▫️&lt;span&gt; `ToolMessage` : 도구 실행 결과 메시&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #cec9c2; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;span&gt;Langchain으로 LLM Application을 만들면 이 4개를 많이 쓰게 된다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #cec9c2; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;span&gt;아까 말했듯이, 이것들의 List도 `llm.invoke()`에 인자로 들어갈 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;816&quot; data-origin-height=&quot;249&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PyBbn/dJMcahbJzkp/PDsk7qOCDPkr6rC7STPt3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PyBbn/dJMcahbJzkp/PDsk7qOCDPkr6rC7STPt3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PyBbn/dJMcahbJzkp/PDsk7qOCDPkr6rC7STPt3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPyBbn%2FdJMcahbJzkp%2FPDsk7qOCDPkr6rC7STPt3k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;767&quot; height=&quot;249&quot; data-origin-width=&quot;816&quot; data-origin-height=&quot;249&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;list of messages를 통해 few-shots를 활용할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;938&quot; data-origin-height=&quot;440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zNcQV/dJMcaioaYdb/ZW4hBlwCeT4pru2yLkzdf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zNcQV/dJMcaioaYdb/ZW4hBlwCeT4pru2yLkzdf1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zNcQV/dJMcaioaYdb/ZW4hBlwCeT4pru2yLkzdf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzNcQV%2FdJMcaioaYdb%2FZW4hBlwCeT4pru2yLkzdf1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;770&quot; height=&quot;361&quot; data-origin-width=&quot;938&quot; data-origin-height=&quot;440&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇지만 few-shots을 구성할 때 이렇게 list of messages로 주는 게 아니라&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`ChatPromptTemplate`을 활용하는 게 더 Langchain스럽다.(권장된다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐하면 `ChatPromptTemplate`은 LCEL(랭체인 구성하는 요소들을 `|`로 연결시키는 것)에 연동이 되는데 위에서 본 message list는 연동이 안되기 때문이다. LCEL을 사용하면 확장성 측면에서 유리하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.ChatPromptTemplate&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`ChatPromptTemplate`을 사용할 땐 이렇게 아까 만든 `message_list` (BaseMessage를 상속한 메시지 클래스들로 만든 리스트)를 주지 말고(아래처럼)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1246&quot; data-origin-height=&quot;579&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/t7B0n/dJMcahpgPrF/JQBMETk7DyWV8ekmNHlbDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/t7B0n/dJMcahpgPrF/JQBMETk7DyWV8ekmNHlbDK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/t7B0n/dJMcahpgPrF/JQBMETk7DyWV8ekmNHlbDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ft7B0n%2FdJMcahpgPrF%2FJQBMETk7DyWV8ekmNHlbDK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;806&quot; height=&quot;579&quot; data-origin-width=&quot;1246&quot; data-origin-height=&quot;579&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 아래처럼 튜플로 주는 것이 좋다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;990&quot; data-origin-height=&quot;687&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CuNPe/dJMcaacBQ0q/U2KOl3KylU05yuZADjoNI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CuNPe/dJMcaacBQ0q/U2KOl3KylU05yuZADjoNI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CuNPe/dJMcaacBQ0q/U2KOl3KylU05yuZADjoNI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCuNPe%2FdJMcaacBQ0q%2FU2KOl3KylU05yuZADjoNI1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;732&quot; height=&quot;508&quot; data-origin-width=&quot;990&quot; data-origin-height=&quot;687&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4️⃣ 답변 형식 컨트롤&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. OutputParser&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아웃풋파서를 활용해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1007&quot; data-origin-height=&quot;368&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7K33k/dJMcacBuOBk/rp1rLQCp8yGTeXxDyUBAkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7K33k/dJMcacBuOBk/rp1rLQCp8yGTeXxDyUBAkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7K33k/dJMcacBuOBk/rp1rLQCp8yGTeXxDyUBAkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7K33k%2FdJMcacBuOBk%2Frp1rLQCp8yGTeXxDyUBAkk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;781&quot; height=&quot;285&quot; data-origin-width=&quot;1007&quot; data-origin-height=&quot;368&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아웃풋파서를 사용하지 않았을 때와 사용했을 때의 산출물이 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( BaseMessage를 상속하는 AIMessage&amp;nbsp; &amp;nbsp; vs&amp;nbsp; &amp;nbsp; &amp;nbsp;스트링 )&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;970&quot; data-origin-height=&quot;330&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/I7qKg/dJMcaaXYXrN/kpn2atb67kpMLm0skr9WVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/I7qKg/dJMcaaXYXrN/kpn2atb67kpMLm0skr9WVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/I7qKg/dJMcaaXYXrN/kpn2atb67kpMLm0skr9WVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FI7qKg%2FdJMcaaXYXrN%2Fkpn2atb67kpMLm0skr9WVK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;766&quot; height=&quot;261&quot; data-origin-width=&quot;970&quot; data-origin-height=&quot;330&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;➕ 그리고 prompt에 Return the name of dog breed only.라고 추가해주면 개 품종 이름만 나오게 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. json 형식을 원할 때&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;llm 돌린 결과를 json 형식으로 답변 받아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #cec9c2; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot;&gt;cf. `StrOutputParser`같이 `JsonOutputParser`도 있다. 근데 산출하는 형식이 오락가락해서 쓸 수가 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #cec9c2; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot;&gt;pydantic으로 Base Model을 활용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #cec9c2; text-align: start;&quot; data-darkreader-inline-color=&quot;&quot;&gt;Base Model을 LLM과 연결시켜서 `with_structured_output()`으로 답변을 생성한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;996&quot; data-origin-height=&quot;793&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kSBkJ/dJMcafLKSxh/SQapgQm06bj8Qm39mlP9S0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kSBkJ/dJMcafLKSxh/SQapgQm06bj8Qm39mlP9S0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kSBkJ/dJMcafLKSxh/SQapgQm06bj8Qm39mlP9S0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkSBkJ%2FdJMcafLKSxh%2FSQapgQm06bj8Qm39mlP9S0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;768&quot; height=&quot;611&quot; data-origin-width=&quot;996&quot; data-origin-height=&quot;793&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 위에서 선언한 pydantic 모델이 나온다. capital, population 등에 접근도 가능하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;974&quot; data-origin-height=&quot;264&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEIPcy/dJMcaaDF4S6/rW2kybysdKt38GputK0trK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEIPcy/dJMcaaDF4S6/rW2kybysdKt38GputK0trK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEIPcy/dJMcaaDF4S6/rW2kybysdKt38GputK0trK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEIPcy%2FdJMcaaDF4S6%2FrW2kybysdKt38GputK0trK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;772&quot; height=&quot;209&quot; data-origin-width=&quot;974&quot; data-origin-height=&quot;264&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`model_dump()`를 활용하면 json 형식으로 나온다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;354&quot; data-origin-height=&quot;185&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c5z3nf/dJMcaaDF4Yl/rK6LB1YR5dBT2Io3lzEdok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c5z3nf/dJMcaaDF4Yl/rK6LB1YR5dBT2Io3lzEdok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c5z3nf/dJMcaaDF4Yl/rK6LB1YR5dBT2Io3lzEdok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc5z3nf%2FdJMcaaDF4Yl%2FrK6LB1YR5dBT2Io3lzEdok%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;297&quot; height=&quot;155&quot; data-origin-width=&quot;354&quot; data-origin-height=&quot;185&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dict이기 때문에 각각 접근도 가능하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;487&quot; data-origin-height=&quot;127&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJvIsy/dJMcagcPkq4/ebqb76tQHYASA8IypDI0i0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJvIsy/dJMcagcPkq4/ebqb76tQHYASA8IypDI0i0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJvIsy/dJMcagcPkq4/ebqb76tQHYASA8IypDI0i0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJvIsy%2FdJMcagcPkq4%2Febqb76tQHYASA8IypDI0i0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;383&quot; height=&quot;100&quot; data-origin-width=&quot;487&quot; data-origin-height=&quot;127&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5️⃣ LCEL 문법&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 파이프&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 게 다 Runnable을 상속 받고 있기 때문에 다들 Runnable 클래스의 메서드인 `invoke()`를 쓰고 있는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;971&quot; data-origin-height=&quot;347&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dy4YQW/dJMcagKFcuk/qYRGdMSZwdvd2ya9n6KYNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dy4YQW/dJMcagKFcuk/qYRGdMSZwdvd2ya9n6KYNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dy4YQW/dJMcagKFcuk/qYRGdMSZwdvd2ya9n6KYNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdy4YQW%2FdJMcagKFcuk%2FqYRGdMSZwdvd2ya9n6KYNk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;765&quot; height=&quot;347&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;971&quot; data-origin-height=&quot;347&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;chain도 Runnable이므로 chain끼리도 파이프로 연결할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 chain을 dog_chain이라고 하고, 나라 정보를 찾는 chain을 만들어서 연결시켜보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1022&quot; data-origin-height=&quot;831&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/89WH3/dJMcabvOUHj/86DWteadXL61tQIawKPiRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/89WH3/dJMcabvOUHj/86DWteadXL61tQIawKPiRK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/89WH3/dJMcabvOUHj/86DWteadXL61tQIawKPiRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F89WH3%2FdJMcabvOUHj%2F86DWteadXL61tQIawKPiRK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;805&quot; height=&quot;655&quot; data-origin-width=&quot;1022&quot; data-origin-height=&quot;831&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;랭체인의 이런 시스템(다 Runnable, 파이프로 이어서 체인 `invoke()` 할 수 있음.)은 여러 태스크를 처리할 때 강력한 도구가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;체인을 잘 활용하는 것이 매우 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.RunnablePassthrough&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`RunnablePassthrough`를 사용해보자.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;  RunnablePassthrough란?&lt;br /&gt;입력값을 아무 변화 없이 그대로 다음 단계로 통과(pass through)시키는 역할을 하는 Runnable.&lt;br /&gt;chain 등을 거치기 전에 원래의 입력값을 보존하기 위한 목적으로 자주 쓰인다.&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1105&quot; data-origin-height=&quot;548&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3doxr/dJMcag4XZq4/Fqq54j0C3q6Zy8yAyyhTrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3doxr/dJMcag4XZq4/Fqq54j0C3q6Zy8yAyyhTrk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3doxr/dJMcag4XZq4/Fqq54j0C3q6Zy8yAyyhTrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3doxr%2FdJMcag4XZq4%2FFqq54j0C3q6Zy8yAyyhTrk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;802&quot; height=&quot;398&quot; data-origin-width=&quot;1105&quot; data-origin-height=&quot;548&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;continent 도 넣어서 거기에도 `RunnablePassthrough`를 넣도록 해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1137&quot; data-origin-height=&quot;695&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/H4dIi/dJMcacavNEW/fqazackT6QoWiSIhfXrel0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/H4dIi/dJMcacavNEW/fqazackT6QoWiSIhfXrel0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/H4dIi/dJMcacavNEW/fqazackT6QoWiSIhfXrel0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FH4dIi%2FdJMcacavNEW%2FfqazackT6QoWiSIhfXrel0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;808&quot; height=&quot;494&quot; data-origin-width=&quot;1137&quot; data-origin-height=&quot;695&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⚠️ 위 코드대로 했을 때 에러 없이 결과가 잘 나왔지만, 원칙대로라면 `input_variables=[&quot;information&quot;, &quot;continent&quot;],`라고 템플릿에 등장하는 변수를 다 포함시켜야한다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 흐름&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;input(information,&amp;nbsp;continent) &lt;br /&gt;&amp;nbsp;&amp;nbsp;│ &lt;br /&gt;&amp;nbsp;&amp;nbsp;├── information 그대로 보관 (RunnablePassthrough) &lt;br /&gt;&amp;nbsp;&amp;nbsp;├── continent 그대로 보관 (RunnablePassthrough) &lt;br /&gt;&amp;nbsp;&amp;nbsp;└──&amp;nbsp;country_chain로&amp;nbsp;보내서&amp;nbsp;country&amp;nbsp;생성 &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;│ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;결과:&amp;nbsp;country &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; │ &lt;br /&gt;병합해서&amp;nbsp;다음&amp;nbsp;단계로&amp;nbsp;&amp;rarr;&amp;nbsp;dog_chain(country)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;➕ chain을 쪼개서 task를 분기하는 게 중요한 이유&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;prompt가 장황해지면 LLM이 잘 못알아들을 수 있으며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;~~하게 하지 마시오.&quot; 같은 것을 다른 것과 함께 넣으면(동시에 여러 일을 시키면) LLM이 잘 못한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▫️ 특히, LLM은 생성하는 애라서 ~~를 생성하지 마라. 같은 금지형 규칙은 잘 못 지킨다.&amp;nbsp; 그래서 그런 금지 규칙을 따로 빼서 핸들링 하는 게 좋다. 그리고 메인 로직은 gpt-4o같은 큰 모델 시켜도 &lt;span style=&quot;text-align: start;&quot;&gt;그런 금지 규칙은 간단하니까 mini 모델을 활용함으로써 비용도 아낄 수 있다. 즉, 금지 규칙이 있을 땐 분기형 체인 구조로 만들면 훨씬 안정적이고 성능이 좋다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6️⃣ Chain 활용 간단 복습&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;chain들을 파이프로 이어서 `invoke()` 해보겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 이어볼 것이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;  나라 &amp;rarr; native dog breed &amp;rarr; 귀 모양&lt;/blockquote&gt;
&lt;pre id=&quot;code_1763482257240&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import PromptTemplate

dog_prompt = PromptTemplate(
    template = 'What is one of the native dog breeds of {country}? return the name only',
    input_variables=['country']
)

dog_chain = dog_prompt | llm | StrOutputParser()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dog_chain 잘 되나 확인&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번엔 `ChatPromptTemplate` 활용&lt;/p&gt;
&lt;pre id=&quot;code_1763482274678&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain_core.prompts import ChatPromptTemplate

ear_prompt = ChatPromptTemplate.from_messages([
    ('system', 'Provide the ear shape style of the dog that user wants. return the ear shape style only.'),
    ('human', 'Can you give me the ear shape style of {dog}?')
])

ear_chain = ear_prompt | llm | StrOutputParser()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ear_chain 잘 되나 확인 후&amp;nbsp;두 체인을 이어 주고 입력값 넣어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한국 &amp;rarr; 진돗개 &amp;rarr; &lt;u&gt;Stand-up ears (최종 출력 결과)&lt;/u&gt; 나왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Data Science &amp;amp; AI  </category>
      <category>Langchain</category>
      <author>승실</author>
      <guid isPermaLink="true">https://nowallnow.tistory.com/30</guid>
      <comments>https://nowallnow.tistory.com/entry/LangChain-%EA%B8%B0%EB%B3%B8%EA%B8%B0-LLM-%EC%8B%A4%EC%8A%B5#entry30comment</comments>
      <pubDate>Sat, 8 Nov 2025 14:14:03 +0900</pubDate>
    </item>
    <item>
      <title>[Java] 문자 인코딩, 디코딩 실습</title>
      <link>https://nowallnow.tistory.com/entry/Java-%EB%AC%B8%EC%9E%90-%EC%9D%B8%EC%BD%94%EB%94%A9-%EB%94%94%EC%BD%94%EB%94%A9-%EA%B8%B0%EC%B4%88-%EC%8B%A4%EC%8A%B5</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;자바&amp;nbsp;고급&amp;nbsp;2편&amp;nbsp;섹션&amp;nbsp;2.&amp;nbsp;문자&amp;nbsp;인코딩 &lt;br /&gt;&lt;br /&gt; &amp;nbsp;학습&amp;nbsp;목표&amp;nbsp;:&amp;nbsp;입출력을&amp;nbsp;다루기&amp;nbsp;전&amp;nbsp;다음과&amp;nbsp;같은&amp;nbsp;기본&amp;nbsp;이론을&amp;nbsp;확실히&amp;nbsp;이해하고&amp;nbsp;넘어&amp;nbsp;가자. &lt;br /&gt;&lt;br /&gt;▫️&amp;nbsp;컴퓨터가&amp;nbsp;데이터를&amp;nbsp;저장하는&amp;nbsp;원리 &lt;br /&gt;▫️&amp;nbsp;텍스트&amp;nbsp;데이터와&amp;nbsp;문자&amp;nbsp;인코딩의&amp;nbsp;원리 &lt;br /&gt;▫️&amp;nbsp;실무에&amp;nbsp;꼭&amp;nbsp;필요한&amp;nbsp;문자&amp;nbsp;인코딩 &lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발을 하다가 문자가 깨질 때 해결하기 위해서는&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1️⃣ 문자 인코딩&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Charset (문자 집합)을 사용해서 기본적인 문자 인코딩을 해보았습니다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;package charset;
import java.util.Arrays;
import java.nio.charset.Charset;

import static java.nio.charset.StandardCharsets.*;

public class EncodingMain1 {
    private static final Charset EUC_KR = Charset.forName(&quot;EUC-KR&quot;);
    private static final Charset MS_949 = Charset.forName(&quot;MS949&quot;);

    public static void main(String[] args) {
        System.out.println(&quot;== ASCII 영문 처리 ==&quot;);
        encoding(&quot;A&quot;, US_ASCII);
        encoding(&quot;A&quot;, ISO_8859_1);
        encoding(&quot;A&quot;, EUC_KR);
        encoding(&quot;A&quot;, MS_949);
        encoding(&quot;A&quot;, UTF_8);
        encoding(&quot;A&quot;, UTF_16BE);

        System.out.println(&quot;==한글 지원==&quot;);
        encoding(&quot;가&quot;, EUC_KR);
        encoding(&quot;가&quot;, MS_949);
        encoding(&quot;가&quot;, UTF_8);
        encoding(&quot;가&quot;, UTF_16BE);

        String str = &quot;A&quot;;
        byte[] bytes = str.getBytes();
        System.out.println(&quot;bytes = &quot; + Arrays.toString(bytes));
    }

    private static void encoding(String text, Charset charset) {
        byte[] bytes = text.getBytes(charset);
        System.out.printf(&quot;%s -&amp;gt; [%s] 인코딩 -&amp;gt; %s %sbyte\n&quot;,
        	text, charset, Arrays.toString(bytes), bytes.length);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;541&quot; data-origin-height=&quot;432&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKm4v1/btsQnGkhHA1/Px9QcFMA3WZEuZJ2MUR5VK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKm4v1/btsQnGkhHA1/Px9QcFMA3WZEuZJ2MUR5VK/img.png&quot; data-alt=&quot;Program output&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKm4v1/btsQnGkhHA1/Px9QcFMA3WZEuZJ2MUR5VK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKm4v1%2FbtsQnGkhHA1%2FPx9QcFMA3WZEuZJ2MUR5VK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;394&quot; height=&quot;432&quot; data-origin-width=&quot;541&quot; data-origin-height=&quot;432&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Program output&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  &lt;code&gt;getBytes()&lt;/code&gt; 메서드의 역할&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;String&lt;/code&gt; 클래스의 인스턴스 메서드이고,&lt;br /&gt;&lt;span style=&quot;color: #f89009;&quot; data-darkreader-inline-color=&quot;&quot;&gt;문자열(&lt;code&gt;String&lt;/code&gt;)&lt;/span&gt;&lt;span style=&quot;--darkreader-inline-color: var(--darkreader-text-f89009, #ffa127);&quot;&gt;을&lt;/span&gt;&lt;span style=&quot;color: #f89009;&quot; data-darkreader-inline-color=&quot;&quot;&gt; 지정한 문자셋(&lt;code&gt;Charset&lt;/code&gt;)&lt;/span&gt;&lt;span style=&quot;--darkreader-inline-color: var(--darkreader-text-f89009, #ffa127);&quot;&gt;을&lt;/span&gt;&lt;span style=&quot;color: #f89009;&quot; data-darkreader-inline-color=&quot;&quot;&gt; 이용해서 바이트 배열(&lt;code&gt;byte[]&lt;/code&gt;)로 변환&lt;/span&gt;&lt;span style=&quot;--darkreader-inline-color: var(--darkreader-text-f89009, #ffa127);&quot;&gt;하는 역할&lt;/span&gt;을 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 이것은 &lt;span style=&quot;color: #006dd7;&quot; data-darkreader-inline-color=&quot;&quot;&gt;사람이 읽는 문자(charater)를 컴퓨터가 처리할 수 있는 byte sequence로 바꾸는 과정&lt;/span&gt;입니다.&lt;br /&gt;이때 어떤 방식으로 문자를 byte로 바꿀지 정해주는 게 바로 &lt;code&gt;Charset&lt;/code&gt;입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;642&quot; data-origin-height=&quot;228&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GPtvA/btsQnZqrISC/9ANv1vg6R3khd7fWDnrjB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GPtvA/btsQnZqrISC/9ANv1vg6R3khd7fWDnrjB0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GPtvA/btsQnZqrISC/9ANv1vg6R3khd7fWDnrjB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGPtvA%2FbtsQnZqrISC%2F9ANv1vg6R3khd7fWDnrjB0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;642&quot; height=&quot;228&quot; data-origin-width=&quot;642&quot; data-origin-height=&quot;228&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;667&quot; data-origin-height=&quot;357&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dIWf5k/btsQq2Tdfs3/lqsFEVrWZ5ZF2tWZK8mWt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dIWf5k/btsQq2Tdfs3/lqsFEVrWZ5ZF2tWZK8mWt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dIWf5k/btsQq2Tdfs3/lqsFEVrWZ5ZF2tWZK8mWt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdIWf5k%2FbtsQq2Tdfs3%2FlqsFEVrWZ5ZF2tWZK8mWt1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;667&quot; height=&quot;357&quot; data-origin-width=&quot;667&quot; data-origin-height=&quot;357&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java &amp;amp; Spring  </category>
      <author>승실</author>
      <guid isPermaLink="true">https://nowallnow.tistory.com/23</guid>
      <comments>https://nowallnow.tistory.com/entry/Java-%EB%AC%B8%EC%9E%90-%EC%9D%B8%EC%BD%94%EB%94%A9-%EB%94%94%EC%BD%94%EB%94%A9-%EA%B8%B0%EC%B4%88-%EC%8B%A4%EC%8A%B5#entry23comment</comments>
      <pubDate>Mon, 8 Sep 2025 15:51:33 +0900</pubDate>
    </item>
    <item>
      <title>2024년 1회 정보처리기사 합격 후기</title>
      <link>https://nowallnow.tistory.com/entry/2024%EB%85%84-1%ED%9A%8C-%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC-%ED%95%A9%EA%B2%A9-%ED%9B%84%EA%B8%B0</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;916&quot; data-origin-height=&quot;249&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bE5Z7T/btsH9hFhn0D/hEBVkrcr934CwwyGBRBSIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bE5Z7T/btsH9hFhn0D/hEBVkrcr934CwwyGBRBSIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bE5Z7T/btsH9hFhn0D/hEBVkrcr934CwwyGBRBSIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbE5Z7T%2FbtsH9hFhn0D%2FhEBVkrcr934CwwyGBRBSIk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;834&quot; height=&quot;249&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;916&quot; data-origin-height=&quot;249&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignLeft&quot; data-emoticon-type=&quot;friends1&quot; data-emoticon-name=&quot;019&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/019.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/019.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;시험 준비 과정&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅&amp;nbsp; 교재 - 중요한 부분을 우선으로&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 필기, 실기 모두 시나공에서 나온 교재로 공부했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목차에 단원별 중요도가 A, B, C, D로 적혀있기 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(&lt;a href=&quot;https://www.yes24.com/Product/Viewer/Preview/123036227&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.yes24.com/Product/Viewer/Preview/123036227&lt;/a&gt;&amp;nbsp; 필기 책 미리보기 참고, 실기 책도 마찬가지)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필기 시험 준비할 때 A, B 단원을 최우선으로 읽었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필기도 그렇지만 실기는 특히 시험 범위가 넓기 때문에 단원별 출제 비중 파악이 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;677&quot; data-origin-height=&quot;792&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xcCyN/btsH8kXi08h/D7ubiLRLhYCMj3KZFvkRl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xcCyN/btsH8kXi08h/D7ubiLRLhYCMj3KZFvkRl1/img.png&quot; data-alt=&quot;출처 : https://blog.naver.com/iwebmania/223166603288 권우석의 컴퓨터 자격증&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xcCyN/btsH8kXi08h/D7ubiLRLhYCMj3KZFvkRl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxcCyN%2FbtsH8kXi08h%2FD7ubiLRLhYCMj3KZFvkRl1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;497&quot; height=&quot;581&quot; data-origin-width=&quot;677&quot; data-origin-height=&quot;792&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : https://blog.naver.com/iwebmania/223166603288 권우석의 컴퓨터 자격증&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot; data-darkreader-inline-color=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot; data-darkreader-inline-color=&quot;&quot;&gt;✅&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;기출 - 매우 중요&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실기는 주관식이니까 문제에서 어떤 식으로 물어보는지, 개념을 어느 범위까지 알아야 하는지에 대한 감을 잡는 것도 중요하다. 그러니 아직 거의 다 모르는 문제이더라도 &lt;span style=&quot;text-align: start;&quot;&gt;냅다&lt;/span&gt; 기출을 뽑아서 공부하는 것도 좋다!&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; &amp;nbsp; '기사퍼스트 권우석'이라는 유튜브 채널에서 기출문제 해설강의를 보면서 공부했다. 설명이 좋아서 추천한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( &lt;a href=&quot;https://youtu.be/L7-_T6IliK8&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://youtu.be/L7-_T6IliK8&lt;/a&gt;&lt;a href=&quot;https://youtu.be/L7-_T6IliK8&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;&amp;nbsp;&lt;/a&gt;)&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=L7-_T6IliK8&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/ij1Xo/hyWoICibPp/ksz8gCZfslKkkuyVbFgEXk/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-title=&quot;[정보처리기사 실기] 2023년 3회 기출문제 풀이&quot; data-original-url=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/L7-_T6IliK8&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot; data-darkreader-inline-color=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot; data-darkreader-inline-color=&quot;&quot;&gt;✅&amp;nbsp;&lt;span&gt; 자투리 시간 활용&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;짬나는 시간이나 이동 시간에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유튜브 영상을 봐도 되고 다른 분들이 정리해 둔 글을 봐도 되니까 조금씩이라도 해두는 게 도움이 많이 된다고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;벼락치기는 너무 힘들다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://thisisyoon.tistory.com/category/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://thisisyoon.tistory.com/category/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1719157861061&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;'정보처리기사' 카테고리의 글 목록&quot; data-og-description=&quot;어깨피고 허리피자&quot; data-og-host=&quot;thisisyoon.tistory.com&quot; data-og-source-url=&quot;https://thisisyoon.tistory.com/category/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC&quot; data-og-url=&quot;https://thisisyoon.tistory.com/category/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/iQpmy/hyWoHwCnEQ/46NEFscXobWKbX9Lwh1IUK/img.jpg?width=400&amp;amp;height=398&amp;amp;face=0_0_400_398,https://scrap.kakaocdn.net/dn/Vt1E2/hyWoGEt5q2/7mzB02RV9DIW5KtzOuK1BK/img.jpg?width=400&amp;amp;height=398&amp;amp;face=0_0_400_398,https://scrap.kakaocdn.net/dn/oVSdC/hyWrVfF08G/ccKXVWDeTl0TRkmJMk6oYK/img.png?width=264&amp;amp;height=200&amp;amp;face=0_0_264_200&quot;&gt;&lt;a href=&quot;https://thisisyoon.tistory.com/category/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://thisisyoon.tistory.com/category/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/iQpmy/hyWoHwCnEQ/46NEFscXobWKbX9Lwh1IUK/img.jpg?width=400&amp;amp;height=398&amp;amp;face=0_0_400_398,https://scrap.kakaocdn.net/dn/Vt1E2/hyWoGEt5q2/7mzB02RV9DIW5KtzOuK1BK/img.jpg?width=400&amp;amp;height=398&amp;amp;face=0_0_400_398,https://scrap.kakaocdn.net/dn/oVSdC/hyWrVfF08G/ccKXVWDeTl0TRkmJMk6oYK/img.png?width=264&amp;amp;height=200&amp;amp;face=0_0_264_200');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;'정보처리기사' 카테고리의 글 목록&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;어깨피고 허리피자&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;thisisyoon.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; &amp;nbsp; 시험에 많이 나오는 개념 위주로 잘 정리되어 있다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;282&quot; data-origin-height=&quot;225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9c8Xa/btsH8x93sTs/HMv2BMFJRwhx4ThGkSNgtk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9c8Xa/btsH8x93sTs/HMv2BMFJRwhx4ThGkSNgtk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9c8Xa/btsH8x93sTs/HMv2BMFJRwhx4ThGkSNgtk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9c8Xa%2FbtsH8x93sTs%2FHMv2BMFJRwhx4ThGkSNgtk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;282&quot; height=&quot;225&quot; data-origin-width=&quot;282&quot; data-origin-height=&quot;225&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Achievements  </category>
      <author>승실</author>
      <guid isPermaLink="true">https://nowallnow.tistory.com/10</guid>
      <comments>https://nowallnow.tistory.com/entry/2024%EB%85%84-1%ED%9A%8C-%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC-%ED%95%A9%EA%B2%A9-%ED%9B%84%EA%B8%B0#entry10comment</comments>
      <pubDate>Sun, 23 Jun 2024 23:55:02 +0900</pubDate>
    </item>
    <item>
      <title>파이썬의 and / or는 True / False를 반환하지 않는다 (기본값 처리 패턴)</title>
      <link>https://nowallnow.tistory.com/entry/python-and-or-return</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1️⃣&amp;nbsp;&lt;code&gt;return A and B or C&lt;/code&gt; 의 반환 &lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: 값을 선택적으로 반환하는 '삼항 연산자' 대체 구문이다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;def solution(n):
    return n == int(n**.5)**2 and int(n**.5+1)**2 or -1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;code&gt;n**.5&lt;/code&gt; : &lt;code&gt;n**0.5&lt;/code&gt; (n의 제곱근)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  만약 n이 완전제곱수라면 &lt;code&gt;n == int(n**.5)**2&lt;/code&gt; 여야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  return 부분을 A and B or C라고 했을 때,   A가 &lt;code&gt;True&lt;/code&gt;이면 B를 반환하고, A가 &lt;code&gt;False&lt;/code&gt;이면 C를 반환한다. 그 이유는 후술할 and, or의 동작 방식 때문이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ Python의 논리 연산자 and, or 동작 방식&lt;br /&gt;1. and 연산자:&lt;br /&gt;▪ A and B 표현식에서 A가 False로 평가되면 B를 평가하지 않고 A를 반환한다.&lt;br /&gt;▪ A가 True로 평가되면 B를 평가한 후 B의 값을 반환한다.&lt;br /&gt;2. or 연산자:&lt;br /&gt;▪ A or B 표현식에서 A가 True로 평가되면 B를 평가하지 않고 A를 반환한다.&lt;br /&gt;▪ A가 False로 평가되면 B를 평가한 후 B의 값을 반환한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  맨 위 코드에서 &lt;code&gt;n == int(n**.5)**2&lt;/code&gt; 가 &lt;code&gt;True&lt;/code&gt;이면 &lt;code&gt;int(n**.5+1)**2&lt;/code&gt;를 평가한다. &lt;code&gt;int(n**.5+1)**2&lt;/code&gt; 이 &lt;code&gt;True&lt;/code&gt;이면 -1은 평가할 것도 없이 `int(n**&lt;b&gt;.5+1)**&lt;/b&gt;2` 값을 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;code&gt;n == int(n**.5)**2&lt;/code&gt; 가 &lt;code&gt;False&lt;/code&gt;이면 &lt;code&gt;int(n**.5+1)**2&lt;/code&gt;는 평가할 것도 없이 -1을 평가하고 반환한다.&lt;br /&gt;참고로 -1도 &lt;code&gt;True&lt;/code&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드가 &lt;code&gt;True&lt;/code&gt;나 &lt;code&gt;False&lt;/code&gt; 대신 정수를 반환하는 이유는 파이썬의 논리 연산자(and, or)가 불리언이 아닌 실제 피연산자의 값을 반환하기 때문이다. 불리언 반환이 목적이라면 ==, is, &amp;lt;, &amp;gt; 등 비교 연산자로 끝내는 형태로 쓰면 된다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2️⃣ 삼항 조건 표현식&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;: 조건에 따라 다른 값을 반환하는 기능을 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 더 명확하고 직관적인 것 같다.&lt;/p&gt;
&lt;pre class=&quot;lua&quot;&gt;&lt;code&gt;import math
def solution(n):
    return -1 if not math.sqrt(n).is_integer() else (math.sqrt(n)+1)**2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ 삼항 조건 표현식&lt;br /&gt;&lt;code&gt;if not math.sqrt(n).is_integer()&lt;/code&gt; 조건이 참이면 -1을 반환, 거짓이면 &lt;code&gt;(math.sqrt(n) + 1) ** 2&lt;/code&gt; 값을 반환.&lt;/p&gt;
&lt;div style=&quot;background-color: #1f1f1f; color: #cccccc;&quot; data-darkreader-inline-bgcolor=&quot;&quot; data-darkreader-inline-color=&quot;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3️⃣ 다른 언어에서도?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 언어에서도 `and`가 첫 falsy 값을 그대로 반환하고 `or`가 첫 truthy 값을 그대로 반환하는가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론부터 말하자면, JavaScript도 그렇다. Ruby의 `||`도 첫 truthy 객체를 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 대부분의 정적&amp;nbsp; 타입 언어(C/Java/C#/Go 등)는 boolean만 반환한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;정적 타입 언어 (Static Typed Language)&lt;br /&gt;: 변수의 타입이 컴파일 시점에 미리 결정되는 언어. (변수를 만들 때 타입을 명확히 선언해야 함.)&lt;br /&gt;e.g. 위에 말한 예시, Kotlin, TypeScript&lt;br /&gt;&lt;br /&gt;동적 타입 언어 (Dynamic Typed Language)&lt;br /&gt;: 변수의 타입이 runtime에 결정됨.&lt;br /&gt;let a = 10;&lt;br /&gt;a = &quot;hello&quot;;&lt;br /&gt;a = true;&lt;br /&gt;이처럼 변수의 타입이 바뀔 수도 있음.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, JS, Python, Ruby의 경우에는 or / and가 논리 판단 + 값 선택까지 해주고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java, C#, Go 같은 정적 타입 언어의 경우에는 or / and가 논리 판단만 한다. 결과는 boolean이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Languages  </category>
      <category>python</category>
      <author>승실</author>
      <guid isPermaLink="true">https://nowallnow.tistory.com/9</guid>
      <comments>https://nowallnow.tistory.com/entry/python-and-or-return#entry9comment</comments>
      <pubDate>Sat, 22 Jun 2024 20:45:39 +0900</pubDate>
    </item>
  </channel>
</rss>