<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>hansol</title>
    <link>https://godsolnote.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Tue, 16 Jun 2026 01:04:56 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>yhansol</managingEditor>
    <image>
      <title>hansol</title>
      <url>https://tistory1.daumcdn.net/tistory/4428268/attach/13469439ec5c4a1ebac5c7e44309e523</url>
      <link>https://godsolnote.tistory.com</link>
    </image>
    <item>
      <title>Agent</title>
      <link>https://godsolnote.tistory.com/33</link>
      <description>&lt;h1&gt;AI Agent 개발 정의서&lt;/h1&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;p&gt;백엔드 개발자를 위한 AI Agent 개념 정리&lt;/p&gt;
&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;hr&gt;
&lt;h2&gt;1. AI Agent란?&lt;/h2&gt;
&lt;h3&gt;정의&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;&amp;quot;LLM을 두뇌로 사용하는 자율 실행 프로세스&amp;quot;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;단순히 질문에 답하는 LLM과 달리, Agent는 &lt;strong&gt;목표(Goal)&lt;/strong&gt; 를 주면 스스로 계획을 세우고, 필요한 도구를 선택해 실행하며, 결과를 보고 다음 행동을 결정하는 루프를 반복해 목표를 달성한다.&lt;/p&gt;
&lt;h3&gt;기존 LLM과의 차이&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;구분&lt;/th&gt;
&lt;th&gt;기존 LLM (ChatGPT 등)&lt;/th&gt;
&lt;th&gt;AI Agent&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;동작 방식&lt;/td&gt;
&lt;td&gt;질문 → 답변 (단발성)&lt;/td&gt;
&lt;td&gt;목표 → 계획 → 반복 실행 → 완료&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;상태&lt;/td&gt;
&lt;td&gt;Stateless&lt;/td&gt;
&lt;td&gt;Stateful (메모리, 컨텍스트 유지)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;외부 연동&lt;/td&gt;
&lt;td&gt;없음&lt;/td&gt;
&lt;td&gt;Tool 호출 (API, DB, 파일 시스템 등)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;루프&lt;/td&gt;
&lt;td&gt;없음&lt;/td&gt;
&lt;td&gt;결과를 보고 다음 행동 결정 (ReAct Loop)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;자율성&lt;/td&gt;
&lt;td&gt;없음&lt;/td&gt;
&lt;td&gt;목표 달성까지 스스로 판단 및 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;hr&gt;
&lt;h2&gt;2. 백엔드 관점으로 이해하기&lt;/h2&gt;
&lt;p&gt;백엔드의 일반적인 요청 처리 흐름:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Request → Controller → Service → Repository → External API → Response&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Agent의 실행 흐름:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Goal → LLM (판단) → Tool 선택 → Tool 실행 → 결과 관찰 → LLM (재판단) → ... → 완료&lt;/code&gt;&lt;/pre&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;백엔드 개념&lt;/th&gt;
&lt;th&gt;Agent 개념&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Service Layer (비즈니스 로직)&lt;/td&gt;
&lt;td&gt;LLM (자연어로 로직을 판단하는 레이어)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repository / External API 호출&lt;/td&gt;
&lt;td&gt;Tool (실제 실행 단위)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Workflow / Saga Pattern&lt;/td&gt;
&lt;td&gt;Planning (태스크 오케스트레이션)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Session / Cache&lt;/td&gt;
&lt;td&gt;Memory (상태 유지)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Event Loop&lt;/td&gt;
&lt;td&gt;ReAct Loop (Think → Act → Observe 반복)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;핵심은 기존에 &lt;strong&gt;개발자가 if/else로 하드코딩했던 로직&lt;/strong&gt;을, &lt;strong&gt;LLM이 런타임에 동적으로 판단&lt;/strong&gt;한다는 것이다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;3. 핵심 구성요소&lt;/h2&gt;
&lt;h3&gt;3-1. Tool&lt;/h3&gt;
&lt;p&gt;LLM이 호출할 수 있는 함수 단위. Agent의 &amp;quot;손발&amp;quot; 역할.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// Tool 정의 예시 (백엔드 함수와 동일한 구조)
const tools = [
  {
    name: &amp;quot;search_stock_price&amp;quot;,
    description: &amp;quot;특정 종목의 현재 주가를 조회한다&amp;quot;,
    parameters: {
      ticker: { type: &amp;quot;string&amp;quot;, description: &amp;quot;종목 코드 (e.g. AAPL)&amp;quot; }
    },
    execute: async ({ ticker }) =&amp;gt; stockApiClient.getPrice(ticker)
  },
  {
    name: &amp;quot;run_sql&amp;quot;,
    description: &amp;quot;데이터베이스에서 데이터를 조회한다&amp;quot;,
    parameters: {
      query: { type: &amp;quot;string&amp;quot;, description: &amp;quot;실행할 SQL 쿼리&amp;quot; }
    },
    execute: async ({ query }) =&amp;gt; db.query(query)
  },
  {
    name: &amp;quot;send_slack&amp;quot;,
    description: &amp;quot;슬랙 채널에 메시지를 발송한다&amp;quot;,
    parameters: {
      channel: { type: &amp;quot;string&amp;quot; },
      message: { type: &amp;quot;string&amp;quot; }
    },
    execute: async ({ channel, message }) =&amp;gt; slackClient.send(channel, message)
  }
];&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;LLM은 Tool의 &lt;code&gt;name&lt;/code&gt;과 &lt;code&gt;description&lt;/code&gt;을 보고 어떤 Tool을 언제 쓸지 판단한다. 즉, &lt;strong&gt;Tool 설명을 잘 쓰는 것 = Agent 품질에 직결&lt;/strong&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;3-2. Memory&lt;/h3&gt;
&lt;p&gt;Agent가 상태를 유지하는 방식. 크게 두 가지로 나뉜다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;유형&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;th&gt;백엔드 비유&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Short-term Memory&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;현재 대화/작업의 컨텍스트&lt;/td&gt;
&lt;td&gt;Request-scoped 변수, 세션&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Long-term Memory&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;과거 경험, 사용자 정보 등 영구 저장&lt;/td&gt;
&lt;td&gt;Vector DB, Redis, RDB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Long-term Memory는 보통 &lt;strong&gt;Vector DB&lt;/strong&gt;(Pinecone, pgvector 등)를 사용해 의미 기반 검색으로 필요한 과거 정보를 꺼내온다.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;3-3. Planning&lt;/h3&gt;
&lt;p&gt;복잡한 목표를 서브태스크로 분해하고 실행 순서를 결정하는 단계.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Goal: &amp;quot;이번 달 실적 부진 종목 분석 후 리포트 발송&amp;quot;

Plan:
  1. DB에서 이번 달 종목별 수익률 조회
  2. 하위 10% 종목 필터링
  3. 각 종목의 최근 뉴스 수집
  4. 분석 리포트 작성
  5. 슬랙 발송&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Saga Pattern이나 Workflow Orchestration과 개념이 유사하지만, &lt;strong&gt;실행 계획 자체를 LLM이 동적으로 생성&lt;/strong&gt;한다는 점이 다르다.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;3-4. ReAct Loop&lt;/h3&gt;
&lt;p&gt;Agent의 실행 사이클. &lt;strong&gt;Reasoning + Acting&lt;/strong&gt;의 합성어.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Thought]   목표를 달성하려면 먼저 DB에서 데이터를 조회해야 한다.
[Action]    run_sql(&amp;quot;SELECT * FROM stocks WHERE month = &amp;#39;2026-03&amp;#39;&amp;quot;)
[Observe]   결과: [{ticker: &amp;#39;AAPL&amp;#39;, return: -12%}, ...]
[Thought]   AAPL이 부진하다. 관련 뉴스를 찾아봐야 한다.
[Action]    search_news(&amp;quot;AAPL 2026년 3월&amp;quot;)
[Observe]   결과: &amp;quot;실적 발표 미스로 주가 하락...&amp;quot;
[Thought]   분석이 충분하다. 리포트를 작성하고 발송한다.
[Action]    send_slack(&amp;quot;#trading&amp;quot;, &amp;quot;3월 부진 종목 분석: ...&amp;quot;)
[Observe]   발송 완료
[Done]&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;h2&gt;4. Agent 아키텍처 패턴&lt;/h2&gt;
&lt;h3&gt;Single Agent&lt;/h3&gt;
&lt;p&gt;하나의 LLM이 모든 Tool을 직접 사용해 목표를 달성.&lt;br&gt;단순한 태스크에 적합.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;User → Agent (LLM) → [Tool A, Tool B, Tool C]&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Multi-Agent&lt;/h3&gt;
&lt;p&gt;복잡한 태스크를 여러 Agent가 역할 분담해 처리. 마이크로서비스 아키텍처와 유사.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;User → Orchestrator Agent
          ├── Research Agent   → [Web Search Tool, News Tool]
          ├── Analysis Agent   → [SQL Tool, Code Execution Tool]
          └── Reporter Agent   → [Slack Tool, Email Tool]&lt;/code&gt;&lt;/pre&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;패턴&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;th&gt;적합한 상황&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Single Agent&lt;/td&gt;
&lt;td&gt;LLM 1개 + 여러 Tool&lt;/td&gt;
&lt;td&gt;간단한 자동화, 빠른 프로토타이핑&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-Agent&lt;/td&gt;
&lt;td&gt;역할별 LLM 분리&lt;/td&gt;
&lt;td&gt;복잡한 워크플로우, 병렬 처리 필요 시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Human-in-the-loop&lt;/td&gt;
&lt;td&gt;중간에 사람 승인&lt;/td&gt;
&lt;td&gt;고위험 작업 (결제, 배포 등)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;hr&gt;
&lt;h2&gt;5. &amp;quot;Agent 개발&amp;quot;이 실제로 의미하는 것&lt;/h2&gt;
&lt;p&gt;요즘 언급되는 &amp;quot;AI Agent 개발&amp;quot;은 크게 두 가지 맥락이 있다.&lt;/p&gt;
&lt;h3&gt;(1) Agent 플랫폼/런타임 개발&lt;/h3&gt;
&lt;p&gt;Anthropic, OpenAI, Google 등이 하는 일. LLM 자체 + Tool 실행 엔진 + Memory 시스템을 직접 구축.&lt;/p&gt;
&lt;h3&gt;(2) Agent 기반 애플리케이션 개발 ← 대부분의 개발자&lt;/h3&gt;
&lt;p&gt;기존 LLM API + Agent 프레임워크를 활용해 서비스를 만드는 것.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;백엔드 개발자 입장에서의 실제 작업:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tool 설계 및 구현 (기존 서비스 API를 Tool로 래핑)&lt;/li&gt;
&lt;li&gt;Memory 저장소 설계 (Vector DB 도입, 스키마 설계)&lt;/li&gt;
&lt;li&gt;시스템 프롬프트 작성 (Agent의 역할, 제약 조건 정의)&lt;/li&gt;
&lt;li&gt;에러 처리 및 fallback 로직&lt;/li&gt;
&lt;li&gt;비용 최적화 (LLM API 호출 횟수, 토큰 관리)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;주요 프레임워크&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;프레임워크&lt;/th&gt;
&lt;th&gt;언어&lt;/th&gt;
&lt;th&gt;특징&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;LangChain&lt;/td&gt;
&lt;td&gt;Python / JS&lt;/td&gt;
&lt;td&gt;가장 범용적, 생태계 풍부&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LangGraph&lt;/td&gt;
&lt;td&gt;Python / JS&lt;/td&gt;
&lt;td&gt;그래프 기반 복잡한 워크플로우&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CrewAI&lt;/td&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;td&gt;Multi-Agent 특화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Agent SDK&lt;/td&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;td&gt;Anthropic 공식, 이 도구가 사용하는 것&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vercel AI SDK&lt;/td&gt;
&lt;td&gt;TypeScript&lt;/td&gt;
&lt;td&gt;Next.js 친화적&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;hr&gt;
&lt;h2&gt;6. 패러다임 전환 요약&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;기존 백엔드
  개발자가 모든 분기를 코드로 정의
  → if (condition) doA() else doB()

AI Agent
  LLM이 런타임에 분기를 판단
  → &amp;quot;이 상황에선 A가 맞겠다&amp;quot; (자연어 추론)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;결론:&lt;/strong&gt;&lt;br&gt;Agent 개발은 새로운 언어나 프레임워크를 배우는 것이 아니라,&lt;br&gt;&lt;strong&gt;&amp;quot;코드로 제어하던 로직의 일부를 LLM의 판단에 위임하는 설계 방식&amp;quot;&lt;/strong&gt; 을 익히는 것이다.&lt;br&gt;백엔드 개발자가 API 설계하듯, Agent 개발자는 &lt;strong&gt;Tool 설계와 프롬프트 설계&lt;/strong&gt;를 한다.&lt;/p&gt;</description>
      <category>ai</category>
      <category>Agent</category>
      <category>AI</category>
      <category>GPT</category>
      <category>llm</category>
      <author>yhansol</author>
      <guid isPermaLink="true">https://godsolnote.tistory.com/33</guid>
      <comments>https://godsolnote.tistory.com/33#entry33comment</comments>
      <pubDate>Sat, 14 Mar 2026 18:38:54 +0900</pubDate>
    </item>
    <item>
      <title>[aws] 파라미터 스토어 (AWS Systems Manager Parameter Store)</title>
      <link>https://godsolnote.tistory.com/32</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;파라미터 스토어란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS Systems Manager Parameter Store는 Amazon Web Services(AWS)에서 제공하는 서비스로, 애플리케이션의 구성 데이터 및 비밀을 안전하게 저장하고 관리하는 데 도움 이 된다. 이 정보를 중앙에서 관리하고 액세스할 수 있으므로 애플리케이션 구성을 보다 쉽게 ​​유지 관리하고 업데이트할 수 있다.&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;Parameter Store를 사용하면 키-값 쌍을 매개변수로 저장할 수 있는데, 여기서 값은 단순한 문자열이거나 암호화된 암호와 같은 보다 복잡한 데이터 유형일 수 있다. 이러한 매개변수는 경로와 같은 구조로 계층적으로 구성할 수 있으므로 대규모 매개변수 세트를 구성하고 관리하는 것이 편리.&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;Parameter Store는 안전한 저장 및 액세스 제어를 위한 기능도 제공한다. AWS Key Management Service(KMS)를 사용하여 민감한 파라미터를 암호화하고 세분화된 액세스 정책을 정의하여 파라미터를 검색하거나 수정할 수 있는 사람을 제어가 가능하다.&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;span&gt; &lt;/span&gt;1.&lt;span&gt; &lt;/span&gt;&lt;b&gt;계층적 데이터 저장&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;Parameter Store는 계층적 구조를 지원하여 데이터를 체계적으로 관리할 수 있도록 돕는다. 예를 들어, &lt;span&gt;/prod/database/username&lt;/span&gt; 또는 &lt;span&gt;/dev/api/key&lt;/span&gt;와 같은 경로를 사용해 환경별로 데이터를 분리하고 관리할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;2.&lt;span&gt; &lt;/span&gt;&lt;b&gt;보안 관리&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;민감한 데이터(예: API 키, 데이터베이스 비밀번호)는 AWS Key Management Service(KMS)를 사용해 암호화할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;세분화된 IAM 정책을 통해 누가 어떤 파라미터에 접근할 수 있는지를 제어할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;3.&lt;span&gt; &lt;/span&gt;&lt;b&gt;다양한 데이터 형식 지원&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;Parameter Store는 단순 문자열, SecureString(암호화된 문자열), StringList(쉼표로 구분된 문자열 목록)와 같은 다양한 데이터 유형을 지원한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;애플리케이션의 요구 사항에 따라 적합한 데이터 유형을 선택할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;4.&lt;span&gt; &lt;/span&gt;&lt;b&gt;통합 및 자동화&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;AWS Lambda, EC2, ECS와 같은 서비스와 통합하여 애플리케이션에서 파라미터를 동적으로 가져올 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;AWS Systems Manager Run Command나 State Manager와 통합해 파라미터를 자동으로 배포하거나 관리할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;5.&lt;span&gt; &lt;/span&gt;&lt;b&gt;버전 관리&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;Parameter Store는 각 파라미터에 대해 버전 관리를 제공한다. 이전 버전으로 쉽게 롤백하거나 변경 내역을 추적할 수 있다.&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;span&gt; &lt;/span&gt;1.&lt;span&gt; &lt;/span&gt;&lt;b&gt;파라미터 생성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;AWS Management Console, AWS CLI, 또는 SDK를 사용해 새로운 파라미터를 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;KMS 키를 사용하여 데이터를 암호화하려면 &lt;span&gt;SecureString&lt;/span&gt; 유형을 선택한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;2.&lt;span&gt; &lt;/span&gt;&lt;b&gt;파라미터 검색&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;애플리케이션에서 AWS SDK 또는 CLI를 사용하여 필요한 파라미터를 검색한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;예: &lt;/span&gt;aws ssm get-parameter --name &quot;/prod/database/username&quot; --with-decryption&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;3.&lt;span&gt; &lt;/span&gt;&lt;b&gt;IAM 정책 설정&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;파라미터에 접근할 수 있는 사용자를 제한하는 IAM 정책을 설정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;예: 특정 사용자나 서비스에만 특정 경로의 파라미터 접근 권한을 부여한다.&lt;/p&gt;</description>
      <category>aws</category>
      <author>yhansol</author>
      <guid isPermaLink="true">https://godsolnote.tistory.com/32</guid>
      <comments>https://godsolnote.tistory.com/32#entry32comment</comments>
      <pubDate>Mon, 4 Nov 2024 18:49:38 +0900</pubDate>
    </item>
    <item>
      <title>UserInputError</title>
      <link>https://godsolnote.tistory.com/31</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;UserInputError는 GraphQL 쿼리나 뮤테이션 요청 시 유저가 잘못된 입력을 제공했을 때 발생시키는 에러로, 주로 입력 검증 실패나 요청 값이 유효하지 않을 때 사용한다. 이 에러는 apollo-server-errors 모듈에서 제공하는 기본 에러 클래스 중 하나이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;UserInputError 사용 방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UserInputError는 apollo-server-express 패키지에서 직접 가져오는 것이 아니라, apollo-server-errors에서 가져와야 한다. 이 에러를 사용하면 클라이언트에게 에러 메시지를 전달할 수 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;주요 포인트&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;에러 메시지&lt;/b&gt;: UserInputError의 첫 번째 인자로 에러 메시지를 설정한다. 이 메시지는 클라이언트에게 그대로 전달된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;invalidArgs&lt;/b&gt;: 두 번째 인자로 에러와 관련된 추가 정보를 제공할 수 있다. 여기서는 invalidArgs를 통해 어떤 입력이 잘못되었는지 알려줄 수 있다.&lt;/li&gt;
&lt;/ul&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;</description>
      <category>node.js</category>
      <author>yhansol</author>
      <guid isPermaLink="true">https://godsolnote.tistory.com/31</guid>
      <comments>https://godsolnote.tistory.com/31#entry31comment</comments>
      <pubDate>Wed, 28 Aug 2024 17:33:04 +0900</pubDate>
    </item>
    <item>
      <title>[GraphQL] GraphQL이란?</title>
      <link>https://godsolnote.tistory.com/30</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;GraphQL&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GraphQL은 API를 위한 쿼리언어이며 타입 시스템을 사용하여 쿼리를 실행하는 서버사이드 런타임이다. GraphQL은 특정 데이터베이스나 특정 스토리지 엔진과 관계되어 있지 않으며 기존코드와 데이터에 의해 대체된다.&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;쿼리언어(Query Language)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿼리언어는 정보를 얻기 위해 보내는 질의문을 만들기 위해 사용되는 컴퓨터 언어이다. 데이터베이스 시스템에 저장된 데이터를 가져오기 위해 사용하는 SQL&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;GraphQL(Graph Query Language)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SQL이 데이터베이스에서 데이터를 가져오는 목적을 가진다면 GraphQL은 클라이언트가 데이터를 서버로부터 가져오는 것을 목적으로 한다.&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;GraphQL vs REST&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GraphQL은 RESTful API가 이미 존재하고 널리 쓰이던 2012년에 만들어졌다. GraphQL은 어떤 이유에서 만들어졌고 RESTful과는 어떤차이가 있을까&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;GraphQL이 REST와 비교해서 가지는 차이점은 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;1. GraphQL은 보통 하나의 엔드포인트를 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;2. GraphQL은 요청할때 사용하는 쿼리에 따라 다른 응답을 받을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;3. GraphQL은 원하는 데이터만 받을 수 있다.(response)&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;엔드포인트&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;REST API는 보통 여러 엔드포인트를 가지며 각각의 엔드포인트가 동일한 응답을 반환한다. GraphQL은 보통 하나의 엔드포인트만을 사용하며 요청하는 쿼리에 따라 다른 응답을 반환하는 방식이다.&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;REST API로 응답값을 받으면 필요한 데이터 이외의도 많은 정보를 함께 받아야 한다. 하지만 GraphQL을 사용하면 원하는 데이터만 받을 수 있다. 예시로 이름, 키, 몸무게 데이터만 필요하다고 할때 GraphQL을 사용하면 다음과 같이 요청할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1697760223264&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// GraphQL request

query {
	person(personId: 1) {
    	name
        height
        mass
    }
}


// GraphQL response

{
	&quot;data&quot; : {
    	&quot;person&quot; : {
        	&quot;name&quot; : &quot;hansol&quot;,
            &quot;height&quot; : 170,
            &quot;mass&quot; : 62
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GraphQL은 클라이언트에서 필요한대로 쿼리를 작성해 원하는 데이터만 가져올 수 있다.&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;GraphQL 장단점&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;장점&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;1. HTTP 요청 횟수를 줄일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;RESTful의 경우 필요한 리소스 별로 요청해야 하고 필요한 데이터들이 부분적으로 나눠서 개발되어있다면 그만큼 요청횟수가 늘어난다. 하지만 GraphQL은 원하는 정보를 하나의 쿼리에 모두 담아 요청할 수 있다.&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;2. HTTP 응답 사이즈를 줄일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; RESTful의 경우 응답 형태가 정해져있기 때문에 필요한 정보만 부분적으로 요청하는것이 어렵다. 이로인해 데이터의 사이즈가 크고 불필요한 데이터까지 함께 받아온다. GraphQL을 사용함으로써 응답데이터 사이즈를 최소화할 수 있다.&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;3. 개발자의 부담을 덜 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; RESTful API를 사용한다면 개발자는 API의 요청/응답 형식에 의존하게 된다. 따라서 새로운 엔드포인트를 효율적으로 개발하기 위해 커뮤니케이션이 강제되는 경우가 있는데 GraphQL은 요청/응답 의존도가 떨어지기 때문에 API개발 부담을 덜 수 있다.&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;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;1. 고정된 요청과 응답만 필요할때에는 query로 인해 요청의 크기가 RESTful보다 커질 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;2. 캐싱이 REST보다 복잡하다.&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;&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://graphql-kr.github.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://graphql-kr.github.io/&lt;/a&gt;&lt;/p&gt;</description>
      <category>database</category>
      <category>graphQL</category>
      <category>query</category>
      <category>REST</category>
      <category>RESTful</category>
      <category>SQL</category>
      <author>yhansol</author>
      <guid isPermaLink="true">https://godsolnote.tistory.com/30</guid>
      <comments>https://godsolnote.tistory.com/30#entry30comment</comments>
      <pubDate>Fri, 20 Oct 2023 09:07:44 +0900</pubDate>
    </item>
    <item>
      <title>[Bun] Bun??</title>
      <link>https://godsolnote.tistory.com/29</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;Bun 이란??&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트 런타임 : 자바스크립트 코드를 실행할 수 있는 환경&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;노드보다 빠른 속도&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Bun 공식 웹사이트를 통해 알 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bun.sh/&quot;&gt;https://bun.sh/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Bun은 빠른 올인원 자바스크립트 런타임이라고 소개하고 있다. 그렇다면 얼마나 빠를까??&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;399&quot; data-origin-height=&quot;343&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dJRSlT/btsyLmW0hn5/7tVtwgUp2dTXhkKCfioNpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dJRSlT/btsyLmW0hn5/7tVtwgUp2dTXhkKCfioNpK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dJRSlT/btsyLmW0hn5/7tVtwgUp2dTXhkKCfioNpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdJRSlT%2FbtsyLmW0hn5%2F7tVtwgUp2dTXhkKCfioNpK%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;380&quot; height=&quot;343&quot; data-origin-width=&quot;399&quot; data-origin-height=&quot;343&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-10-19 오후 1.43.00.png&quot; data-origin-width=&quot;405&quot; data-origin-height=&quot;341&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/z8jcS/btsyOXBHYSK/v9iVknKgKvlioU7TPIL7xK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/z8jcS/btsyOXBHYSK/v9iVknKgKvlioU7TPIL7xK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/z8jcS/btsyOXBHYSK/v9iVknKgKvlioU7TPIL7xK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fz8jcS%2FbtsyOXBHYSK%2Fv9iVknKgKvlioU7TPIL7xK%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;373&quot; height=&quot;341&quot; data-filename=&quot;스크린샷 2023-10-19 오후 1.43.00.png&quot; data-origin-width=&quot;405&quot; data-origin-height=&quot;341&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>node.js</category>
      <category>bun</category>
      <category>JavaScript</category>
      <category>Node</category>
      <author>yhansol</author>
      <guid isPermaLink="true">https://godsolnote.tistory.com/29</guid>
      <comments>https://godsolnote.tistory.com/29#entry29comment</comments>
      <pubDate>Fri, 20 Oct 2023 08:52:53 +0900</pubDate>
    </item>
    <item>
      <title>[python] smtp 메일 보내기</title>
      <link>https://godsolnote.tistory.com/28</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬 'smtplib' 를 통해 메일을 보낼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cron을 통해 특정주기마다 반복적으로 메일을 보내는 방법을 소개한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1697254050217&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import smtplib
import re
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication

html_content = &quot;&quot;&quot;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
	&amp;lt;p&amp;gt;
    	파이썬 코드로 메일 보내기
    &amp;lt;/p&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&quot;&quot;&quot;

def send_mail(addr):
    reg = &quot;^[a-zA-Z0-9.+_-]+@[a-zA-Z0-9]+\.[a-zA-Z]{2,3}$&quot;  # 유효성 검사
    if re.match(reg, addr):
        smtp.sendmail(my_account, to_mail, msg.as_string())
        print(&quot;정상적으로 메일이 발송되었습니다.&quot;)
    else:
        print(&quot;받으실 메일 주소를 정확히 입력하십시오.&quot;)

# smpt 연결
gmail_smtp = &quot;smtp.gmail.com&quot;
gmail_port = 465
smtp = smtplib.SMTP_SSL(gmail_smtp, gmail_port)

# login
my_account = &quot;보낼메일 주소&quot;
my_password = &quot;패스워드&quot;
smtp.login(my_account, my_password)

# to
to_mail = &quot;받을메일 주소&quot;

# info
msg = MIMEMultipart()
msg[&quot;Subject&quot;] = &quot;메일 제목&quot;
msg[&quot;From&quot;] = my_account
msg[&quot;To&quot;] = to_mail

# content
content_part = MIMEText(html_content, &quot;html&quot;)
msg.attach(content_part)

# attach
file = &quot;파일경로&quot; # 절대경로 혹은 상대경로
with open(file, 'rb') as attachment:
        part = MIMEApplication(attachment.read(), Name = &quot;첨부파일 이름&quot;)
        part['Content-Disposition'] = 'attachment; filename = &quot;첨부파일 이름&quot;
        msg.attach(part)

send_mail(to_mail)

smtp.quit()&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;첨부파일을 사용하기 위해 'from eamil.mime.application import MIMEApplication' 을 임포트 하고 작성한다.&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;span&gt;&lt;/span&gt;&lt;a href=&quot;https://myaccount.google.com/security&quot;&gt;https://myaccount.google.com/security&lt;/a&gt; 링크 접속 &amp;gt; 2단계인증 &amp;gt; 하단에 앱 비밀번호 설정 &amp;gt; 앱 비밀번호 생성 &amp;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;</description>
      <category>python</category>
      <author>yhansol</author>
      <guid isPermaLink="true">https://godsolnote.tistory.com/28</guid>
      <comments>https://godsolnote.tistory.com/28#entry28comment</comments>
      <pubDate>Sat, 14 Oct 2023 12:40:20 +0900</pubDate>
    </item>
    <item>
      <title>Dead Lock(교착상태)</title>
      <link>https://godsolnote.tistory.com/27</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;DeadLock&lt;/b&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Transaction&lt;/b&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Locking(교착상태 예방)&lt;/h4&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;h4 data-ke-size=&quot;size20&quot;&gt;Wait-Die(교착상태 회피)&lt;/h4&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;h4 data-ke-size=&quot;size20&quot;&gt;Wound-Wait(교착상태 회피)&lt;/h4&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;h4 data-ke-size=&quot;size20&quot;&gt;Time Stamp&lt;/h4&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;h4 data-ke-size=&quot;size20&quot;&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;&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;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트랜잭션을 자주 커밋한다.&lt;/li&gt;
&lt;li&gt;정해진 순서대로 테이블에 접근한다.&lt;/li&gt;
&lt;li&gt;읽기 잠금 획득(SELECT ~ FOR UPDATE)의 사용을 피한다.&lt;/li&gt;
&lt;li&gt;한테이블의 복수 행을 복수로 연결하여 순서없이 갱신하면 교착상태가 발생하기 쉽다. 테이블 단위의 잠금을 획득해 갱신을 직렬화하면 동시성이 떨어지지만 교착상태를 피할 수 있다.&lt;/li&gt;
&lt;/ul&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;a href=&quot;https://velog.io/@yrkim/Database-%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98-deadlock&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://velog.io/@yrkim/Database-%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98-deadlock&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://kkh0977.tistory.com/3516&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://kkh0977.tistory.com/3516&lt;/a&gt;&lt;/p&gt;</description>
      <category>database</category>
      <category>Database</category>
      <category>Deadlock</category>
      <category>transaction</category>
      <author>yhansol</author>
      <guid isPermaLink="true">https://godsolnote.tistory.com/27</guid>
      <comments>https://godsolnote.tistory.com/27#entry27comment</comments>
      <pubDate>Thu, 23 Feb 2023 14:21:00 +0900</pubDate>
    </item>
    <item>
      <title>[node] Base64</title>
      <link>https://godsolnote.tistory.com/26</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;노드에서 Base64 인코딩, 디코딩 방법을 알아보자&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;Encoding &amp;amp; Decoding&lt;/h3&gt;
&lt;pre id=&quot;code_1675146397192&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var message = &quot;This is message&quot;;
console.log(message);

// Encoding
base64EncodedText = Buffer.from(message, &quot;utf8&quot;).toString('base64');

// Decoding
base64DecodedText = Buffer.from(base64EncodedText, &quot;base64&quot;).toString('utf8');&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;Buffer.from(문자열, &quot;utf8&quot;).toString('base64')&amp;nbsp; -&amp;gt; Base64 Encoding&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Buffer.from(문자열, &quot;base64&quot;).toString('utf8')&amp;nbsp; -&amp;gt; Base64 Decoding&lt;/p&gt;</description>
      <category>node.js</category>
      <category>BASE64</category>
      <category>decoding</category>
      <category>encoding</category>
      <category>Node</category>
      <author>yhansol</author>
      <guid isPermaLink="true">https://godsolnote.tistory.com/26</guid>
      <comments>https://godsolnote.tistory.com/26#entry26comment</comments>
      <pubDate>Tue, 31 Jan 2023 15:29:32 +0900</pubDate>
    </item>
    <item>
      <title>[v8] V8엔진(Chrome V8)</title>
      <link>https://godsolnote.tistory.com/25</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;V8엔진(Chrome V8)&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;1200&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kAOvJ/btrW2tyR001/W9uewm5x7YT6oP2sNg8Es0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kAOvJ/btrW2tyR001/W9uewm5x7YT6oP2sNg8Es0/img.png&quot; data-alt=&quot;V8&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kAOvJ/btrW2tyR001/W9uewm5x7YT6oP2sNg8Es0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkAOvJ%2FbtrW2tyR001%2FW9uewm5x7YT6oP2sNg8Es0%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;289&quot; height=&quot;289&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;1200&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;V8&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 브라우저를 만드는데 기반을 제공하는 오픈소스 자바스크립트 엔진&lt;br /&gt;ECMAScrpit 규격의 C++로 작성되었으며 자바스크립트를 바이트코드로 컴파일하고 실행하는 방식 사용(JIT)&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;* JIT&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Just-In-Time&lt;/li&gt;
&lt;li&gt;Java, C# 등에서 제공하는 실시간 컴파일 방식&lt;/li&gt;
&lt;/ul&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;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트 코드를 실행하는 프로그램 혹은 인터프리터를 말한다. 자바스크립트 엔진은 표준적인 인터프리터로 구현될 수도 있고 혹은 자바스크립트 코드를 바이트코드로 컴파일하는 JIT컴파일로 구현할 수도 있다.&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;V8엔진 등장배경&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹브라우저 내부에서 JS의 속도 개선을 위해 고안된 V8엔진. 자바스크립트 엔진은 웹 특성상 유저와 상호작용을 위해 즉시성이 있는 인터프리터 방식을 사용하는데 코드가 많아질수록 속도저하의 문제가 생겨서 외부 api를 이용한 기능개발 구현이 어려웠다.(구글맵과같은) 따라서 V8엔진은 속도향상을 위해 자바스크립트 코드를 효율적인 머신 코드로 번역하게 된다.&lt;/p&gt;</description>
      <category>javascript</category>
      <category>Chrome</category>
      <category>JavaScript</category>
      <category>V8</category>
      <author>yhansol</author>
      <guid isPermaLink="true">https://godsolnote.tistory.com/25</guid>
      <comments>https://godsolnote.tistory.com/25#entry25comment</comments>
      <pubDate>Wed, 25 Jan 2023 15:36:28 +0900</pubDate>
    </item>
    <item>
      <title>[typeScript] 타입스크립트를 왜 쓸까?</title>
      <link>https://godsolnote.tistory.com/24</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;타입스크립트를 왜 쓸까&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;타입스크립트도 결국 자바스크립트이다.&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입스크립트도 자바스크립트와 크게 다르지 않다. 따지고 보면 JS의 확장 느낌&lt;br /&gt;자바스크립트에 타입에 대한 내용을 확장시킨것이 타입스크립트이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입스크립트는 컴파일 후에 자바스크립트 파일을 떨군다.(tsc -w) 결과적으로 JS파일을 생성한다는 점에서 왜 굳이 타입스크립트를 쓰는지에 대한 의문이 생기는데 그 의문을 해결해보자.&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 id=&quot;code_1674001191523&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function sum(x, y) {{
	return x + y;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sum 함수가 파라미터로 어떤타입의 인자를 받는지, 어떤타입으로 리턴해주는지 명확하지가 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트는 dynamic typing을 지원하고 있다. 예를 들어 해당 함수에 x =3 , y = '5' 값을 인자로 넘겨줬을때 자바스크립트는 친절하게도 에러를 띄우지 않을 것이다.&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;154&quot; data-origin-height=&quot;51&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFYz27/btrWxq9w5NT/rd5fMsikY581pKqAumGdwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFYz27/btrWxq9w5NT/rd5fMsikY581pKqAumGdwK/img.png&quot; data-alt=&quot;결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFYz27/btrWxq9w5NT/rd5fMsikY581pKqAumGdwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFYz27%2FbtrWxq9w5NT%2Frd5fMsikY581pKqAumGdwK%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;154&quot; height=&quot;51&quot; data-origin-width=&quot;154&quot; data-origin-height=&quot;51&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 결과로 출력된 35는 어떤타입일까?? 명확하지가 않다.&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 id=&quot;code_1674001433503&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function sum(x: number, y:number) {
	return x + y;
}&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;TypeScript&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Type&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입스크립트는 닉값처럼 타입을 직접 지정해주고 컴파일 시점에서 에러를 잡을 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1674001619875&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const name : string = 'hansol'
const age : string | number = &quot;30&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수에 string 값이 아닌 다른 타입을 지정하면 에러가 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;' | ' or 조건으로 타입을 여러개 가질수도 있다.&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;2. bug&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;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;Javascript&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;Typescript&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;동적&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;정적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;인터프리터 언어&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;컴파일 언어&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;독립적으로 사용가능&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;자바스크립트에 의존적(자바스크립트로 컴파일)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;유연성(타입에 제한 없음)&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;더 나은 구조와 간결함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;.js&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;.ts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;간단한 프로젝트에 적합&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;대형 프로젝트에 적합&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;</description>
      <category>javascript</category>
      <category>JavaScript</category>
      <category>TypeScript</category>
      <author>yhansol</author>
      <guid isPermaLink="true">https://godsolnote.tistory.com/24</guid>
      <comments>https://godsolnote.tistory.com/24#entry24comment</comments>
      <pubDate>Wed, 18 Jan 2023 09:33:31 +0900</pubDate>
    </item>
  </channel>
</rss>