<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>hopedevelopment</title>
    <link>https://hopedevelopment.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Mon, 17 Aug 2026 11:15:57 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>jmhope</managingEditor>
    <image>
      <title>hopedevelopment</title>
      <url>https://tistory1.daumcdn.net/tistory/3306163/attach/ba49286a5d50471d93a60a32f84d02b3</url>
      <link>https://hopedevelopment.tistory.com</link>
    </image>
    <item>
      <title>NestJS with Prisma</title>
      <link>https://hopedevelopment.tistory.com/99</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;NestJS와 Prisma를 사용하여 백엔드 개발은 처음이라 아닌 내용도 있을 수 있습니다.&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;NestJS에서 다양한 ORM이 존재하며 이전 회사에서는 대부분의 서비스에서 Sequelize를 사용했었으며 내가 이전에 새롭게 프로젝트를 시작하면서는 TypeORM을 사용했었다. (현재 회사는 go와 로우쿼리로...)&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;이번에 새롭게 프로젝트 할 일이 생겨 오랜만에 NestJS를 다시 하게 되었고 이번에는 Prisma로 선택하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금도 그러는지 모르겠지만 TypeORM이 런타임에서 타입안정성이 좋지 않다는 이야기가 있었고 Sequelize는 너무 오래되고 Typescript보다는 Javascript에 더 적합하다고 생각이 들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 ORM들보다 요즘에는 Prisma가 커뮤니티가 활성화 되어있는 거 같기도 하고 래퍼런스 찾기 쉬울 거라 생각했다.&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;좀 여유롭게 Prisma에 대한 동작을 공부하고 시작하고 싶었는데 못 했다.. (개발기간이 일주일 좀 넘게 있을 줄 알았는데 다른 거 하느라 2~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;h3 data-ke-size=&quot;size23&quot;&gt;설치방법&lt;/h3&gt;
&lt;pre id=&quot;code_1758084027542&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pnpm add prisma @prisma/client&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 package manager로 pnpm을 사용하였기에 이런식으로 하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;vscode를 쓴다면 prisma extension을 사용하는 것을 추천한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 처음부터 썼고 있다고 해서 나쁘지 않으니 그리고 가장 추천하는 설정은 저장할 때마다 format해주는 설정이다. 이거는 강추다. 진짜 go는 vscode go 서버에서 default로 설정되어 있지만 다른 거는 아니다..&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;설정&lt;/h3&gt;
&lt;pre id=&quot;code_1758111527622&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npx prisma init&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;위의 명령어를 쓰면 `prisma/schema.prisma` 파일이 생기며 아래와 같이 코드가 생성되어 있을 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1758111707360&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init

generator client {
  provider = &quot;prisma-client-js&quot;
  output   = &quot;../generated/prisma&quot;
}

datasource db {
  provider = &quot;postgresql&quot;
  url      = env(&quot;DATABASE_URL&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;분명 prisma의 공식 문서에 나와 있어 이거를 그래로 써야 하는 줄 알았지만.. 이 파일에 output이 있는 데 이것 때문에 좀 고생을 했다. output을 지워주면 굉장히 훌륭한 상태가 된다. (남겨두면 빌드할 때 힘들다..)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 나는 cloud run을 사용했는데 &lt;a href=&quot;http://prisma.io/docs/orm/prisma-client/deployment/serverless#guides-for-serverless-function-providers&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;공식문서&lt;/a&gt;에는 Azure도 있고 AWS도 있고 다른 것들은 있었으나 GCP만... 못 찾았다.. (난 GCP가 좋은데.. 왜 싫어하지..)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 os때문에 다른 provider를 추가해야했다. 이거는 다음에 이슈해결부분에서 다시 작성하겠다. (GCP에서 나온 이슈들과 함께 하겠다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1758432665893&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;model Auth {
  id         String    @id @default(uuid()) @db.Uuid
  sequence   Int       @default(autoincrement())
  externalId String    @map(&quot;external_id&quot;) @db.VarChar(255)
  createdAt  DateTime  @default(now()) @map(&quot;created_at&quot;)
  updatedAt  DateTime  @updatedAt @map(&quot;updated_at&quot;)
  deletedAt  DateTime? @map(&quot;deleted_at&quot;) @db.Timestamptz()

  recommendations Recommendation[]
  consumption     Consumption[]
  Stat            Stat[]

  @@map(&quot;auth&quot;)
}

model Recommendation {
  id            String    @id @default(uuid()) @db.Uuid
  sequence      Int       @default(autoincrement())
  stockName     String    @map(&quot;stock_name&quot;) @db.VarChar(255)
  userId        String    @map(&quot;user_id&quot;) @db.Uuid
  recommendedAt DateTime? @map(&quot;recommended_at&quot;) @db.Timestamptz()
  score         Float?    @db.DoublePrecision
  createdAt     DateTime  @default(now()) @map(&quot;created_at&quot;)
  updatedAt     DateTime  @updatedAt @map(&quot;updated_at&quot;)

  user Auth @relation(fields: [userId], references: [id])

  @@map(&quot;recommendations&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;일단 프로젝트에서 prisma의 일부를 발췌해왔다. 일단 기본적으로 schema.prisma파일에 설정 밑에 위와 같은 형식으로 스키마를 정의하고 아래와 같이 하면 `prisma/migrations`에 migration 파일이 생성 된다&lt;/p&gt;
&lt;pre id=&quot;code_1758434850685&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npx prisma migrate dev --name migration_name&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;이후에는 db연결이 된다면 아래와 같이 명령어를 쓰면 된다. dev와 deploy의 차이는 아직 확실히 모르겠지만 일단은 명령어는 나눠져 있다. (이 부분은 나중에 찾아보고 추가할 예정이다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 필자는 local에서 docker compose로 하여 테스트할때는 dev로 하였고 cloud sql에서는 deploy를 사용하였다.&lt;/p&gt;
&lt;pre id=&quot;code_1758434975779&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# development
npx prisma migrate dev

# production
npx prisma migrate deploy&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>NestJS</category>
      <category>nestJS</category>
      <category>prisma</category>
      <author>jmhope</author>
      <guid isPermaLink="true">https://hopedevelopment.tistory.com/99</guid>
      <comments>https://hopedevelopment.tistory.com/99#entry99comment</comments>
      <pubDate>Sun, 21 Sep 2025 15:11:29 +0900</pubDate>
    </item>
    <item>
      <title>[Go] 이진수 더하기</title>
      <link>https://hopedevelopment.tistory.com/98</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;level : 0&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/120885&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이진수&amp;nbsp;더하기&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1722665046148&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;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/120885&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bPqtwB/hyWGWUMN9L/Hp7fsisIWli5IicDTEBsFK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/cAWSRS/hyWG1htZK8/DpYuQOB9bT2rH5wUoA2gWk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/120885&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/120885&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bPqtwB/hyWGWUMN9L/Hp7fsisIWli5IicDTEBsFK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/cAWSRS/hyWG1htZK8/DpYuQOB9bT2rH5wUoA2gWk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&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;programmers.co.kr&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;&lt;span style=&quot;color: #0593d3; text-align: start;&quot;&gt;My Solution&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1722665194564&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import &quot;fmt&quot;

func convert(str string) int {
    result := 0
    for i := 0; i &amp;lt; len(str); i++{
        result *= 2
        if str[i] == 49 {
            result += 1
        }
    }
    
    return result
}

func solution(bin1 string, bin2 string) string {
    answer := convert(bin1) + convert(bin2)
    return fmt.Sprintf(&quot;%b&quot;, answer)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0593d3; text-align: start;&quot;&gt;풀이방법&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;먼저 convert라는 함수를 사용하여 2진수의 값을 나타내는 string을 10진수 int로 변환해주었다. 그리하여 bin1과 bint2을 더한 값을 Sprintf을 통하여 2진수 string으로 변환해서 return 하였다.&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;string &quot;0&quot;은 ASCII 코드로 48이고 string &quot;1&quot;은 &lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;ASCII 코드로&lt;/span&gt; 49이기에 49일 때만 1을 더해주면 된다.&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;방금 생각한 거지만 수식을 한 줄로 쓸 수 있었다. 다만 유의할 점은 string이 바뀌면 int가 아닌 다른 uint8나 int32와 같이 다른 타입으로 바뀌기 때문에 앞에 int로 붙여야한다.&lt;/p&gt;
&lt;pre id=&quot;code_1722669581252&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;result = 2 * result + int(str[i]) - 48&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2진수를 표현한 string이기에 result를 0으로 시작하고 string의 앞 부분 읽으며 result에 2를 곱하고 1이면 1 더해주는 식을 사용하면 2진수를 표현한 string을 int로 쉽게 변환할 수 있다&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0593d3; text-align: start;&quot;&gt;느낀점&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt; VScode에서는 알아서 formatting해주니까 더 깔끔하고 일관성이 있어 보기 편하지만 코딩테스트 환경은 아니어서 아쉬웠다.&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;go를 익히기 위해서는 코딩테스트로 연습하는 것이 정말 도움이 많이 된다. 물론 한계는 있지만 os나 외부 시스템을 연동하는 부분들을 제외한다면 기본 문법이나 라이브러리와 같은 부분은 정말 빨리 익숙해진다. 물론 혼자 프로젝트를 하는 것도 많은 부분에서 도움이 된다.&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;둘 다 같이 한다면 더 효율이 좋을 것이다.&lt;/p&gt;</description>
      <category>Algorithm/프로그래머스</category>
      <category>go</category>
      <category>Golang</category>
      <category>programmers</category>
      <category>이진수 더하기</category>
      <author>jmhope</author>
      <guid isPermaLink="true">https://hopedevelopment.tistory.com/98</guid>
      <comments>https://hopedevelopment.tistory.com/98#entry98comment</comments>
      <pubDate>Sat, 3 Aug 2024 16:20:10 +0900</pubDate>
    </item>
    <item>
      <title>[Go] qr code</title>
      <link>https://hopedevelopment.tistory.com/97</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;level : 0&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/181903&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;qr code&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1722523844530&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;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/181903&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bVEG5X/hyWGQz6kAs/gGpK9Kph2uVvRM5gPBrJ9K/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/cp3Qqe/hyWKwmoVrF/1sGV5bBjtKGqgSk4OlxnLK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/181903&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/181903&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bVEG5X/hyWGQz6kAs/gGpK9Kph2uVvRM5gPBrJ9K/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/cp3Qqe/hyWKwmoVrF/1sGV5bBjtKGqgSk4OlxnLK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&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;programmers.co.kr&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;&lt;span style=&quot;color: #0593d3; text-align: start;&quot;&gt;My Solution&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1722523859734&quot; class=&quot;go&quot; style=&quot;background-color: #000000; color: #000000; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;go&quot;&gt;&lt;code&gt;func solution(q int, r int, code string) string {
    var answer []byte
    for i := r; i &amp;lt; len(code); i += q {
        answer = append(answer, code[i])
    }
    return string(answer)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0593d3; text-align: start;&quot;&gt;풀이방법&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;나머지가 r이여애 하기에 r부터 시작하여 q씩 증가하여 byte를 추가해 주면 된다.&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이후 마지막으로 byte slice를 string으로 형 변횐 해주면 된다.&lt;/p&gt;</description>
      <category>Algorithm/프로그래머스</category>
      <category>go</category>
      <category>programmers</category>
      <category>QR Code</category>
      <author>jmhope</author>
      <guid isPermaLink="true">https://hopedevelopment.tistory.com/97</guid>
      <comments>https://hopedevelopment.tistory.com/97#entry97comment</comments>
      <pubDate>Thu, 1 Aug 2024 23:53:15 +0900</pubDate>
    </item>
    <item>
      <title>[TypeORM] CLI 환경에서 Migration 하기 (with NestJS)</title>
      <link>https://hopedevelopment.tistory.com/95</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;NestJS와 TypeORM을 사용하며 database에 대한 Migration을 파일로 따로 관리하였다. &lt;a href=&quot;https://hopedevelopment.tistory.com/93&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://hopedevelopment.tistory.com/93&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1718463293693&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;이슈 해결 - [TypeORM] DB migration file generate&quot; data-og-description=&quot;TypeORM을 이용하던 도중 migration을 위한 명령어를 통하여 migration file을 생성하려고 했다. migration file을 생성하기 위한 명령어는 create와 generate가 있다. typeorm migration:create ./path-to-migrations-dir/PostRefac&quot; data-og-host=&quot;hopedevelopment.tistory.com&quot; data-og-source-url=&quot;https://hopedevelopment.tistory.com/93&quot; data-og-url=&quot;https://hopedevelopment.tistory.com/93&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b18lXf/hyWoIm1N7P/15UEK6HSK2txuCKUoyU3t0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/Lae2l/hyWoELHk4Z/YTWXqw2vEtbb4xr9kDlLa1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800&quot;&gt;&lt;a href=&quot;https://hopedevelopment.tistory.com/93&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://hopedevelopment.tistory.com/93&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b18lXf/hyWoIm1N7P/15UEK6HSK2txuCKUoyU3t0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/Lae2l/hyWoELHk4Z/YTWXqw2vEtbb4xr9kDlLa1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800');&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;이슈 해결 - [TypeORM] DB migration file generate&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;TypeORM을 이용하던 도중 migration을 위한 명령어를 통하여 migration file을 생성하려고 했다. migration file을 생성하기 위한 명령어는 create와 generate가 있다. typeorm migration:create ./path-to-migrations-dir/PostRefac&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;hopedevelopment.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;Migration파일을 TypeScript로 저장하였기에 개발하며 사용하기 편하도록 ts-node로 migration 명령어를 실행시켰다.&lt;/p&gt;
&lt;pre id=&quot;code_1718463529804&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/// package.json
/// scripts 부분
&quot;migrate:run&quot;: &quot;ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js migration:run --dataSource src/config/data-source.config.ts&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;Docker와 NestJS를 같이 사용하는 경우 위와 같은 명령어로 migration하면 문제가 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 대부분의 NestJS를 Docker를 이용하여 이미지를 build하는 경우 용량을 줄이기 위하여 development와 production 2가지 Multi Stage로 작성한다. (현재 필자는 npm을 사용합니다. 따라서 이 글은 npm 기준으로 설명합니다.)&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;production stage에서 docker는 아래와 같은 명령어를 수행하게 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1718509037182&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;RUN npm install --only=production&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;그러면 devDependencies가 아닌 dependencies에 있는 패키지만 설치된다. 그렇다면 typescript와 ts-node가 설치되지 않아 결국 container를 실행하면 다른 방법을 사용해야 한다.&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;기존 migration:run script 명령어를 보면 알 수 있듯이 typeorm에는 cli.js라는 javascript 파일이 존재하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 cli.js파일을 통한다면 typeorm관련 cli를 할 수 있다는 이야기다.&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;이를 통하여 다음과 같이 script 명령어를 수행할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1718512316054&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/// package.json
/// scripts 부분
&quot;migration:run&quot;: &quot;node node_modules/typeorm/cli.js migration:run -d dist/src/config/data-source.config.js&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;p data-ke-size=&quot;size16&quot;&gt;현재는 src가 아닌 rootDirectory에 database라는 디렉토리에 data-source.config.ts과 migrations라는 디렉토리를 만들어 모든 migration 파일들이 생성 및 실행될 수 있게 하였으며 Docker파일은 아래와 같이 2가지 stage로 구성하였습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1718512782010&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM node:18-alpine as development

WORKDIR /app

COPY . .

RUN npm install
RUN npm run build

FROM node:18-alpine as production

ARG NODE_ENV=production
ENV NODE_ENV=${NODE_ENV}

WORKDIR /app

COPY --from=development /app/dist /app/dist
COPY --from=development /app/package.json .
COPY --from=development /app/package-lock.json .
COPY --from=development /app/.env .

RUN npm install --only=production

EXPOSE 3000

CMD [&quot;node&quot;, &quot;dist/src/main.js&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;실제 container에서 해보면 잘 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-06-16 오후 2.50.22.png&quot; data-origin-width=&quot;2138&quot; data-origin-height=&quot;680&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dVOwGU/btsH0WOAbLK/U0GpaQrrM8awHrY4KLEHvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dVOwGU/btsH0WOAbLK/U0GpaQrrM8awHrY4KLEHvk/img.png&quot; data-alt=&quot;container 시작&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dVOwGU/btsH0WOAbLK/U0GpaQrrM8awHrY4KLEHvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdVOwGU%2FbtsH0WOAbLK%2FU0GpaQrrM8awHrY4KLEHvk%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;2138&quot; height=&quot;680&quot; data-filename=&quot;스크린샷 2024-06-16 오후 2.50.22.png&quot; data-origin-width=&quot;2138&quot; data-origin-height=&quot;680&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;container 시작&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-06-16 오후 2.50.47.png&quot; data-origin-width=&quot;1970&quot; data-origin-height=&quot;306&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dq7xmq/btsH0XUhmSG/TryHtimGDPE6PqaEtn6JD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dq7xmq/btsH0XUhmSG/TryHtimGDPE6PqaEtn6JD0/img.png&quot; data-alt=&quot;돌아가는 container&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dq7xmq/btsH0XUhmSG/TryHtimGDPE6PqaEtn6JD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdq7xmq%2FbtsH0XUhmSG%2FTryHtimGDPE6PqaEtn6JD0%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;1970&quot; height=&quot;306&quot; data-filename=&quot;스크린샷 2024-06-16 오후 2.50.47.png&quot; data-origin-width=&quot;1970&quot; data-origin-height=&quot;306&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;돌아가는 container&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-06-16 오후 2.52.33.png&quot; data-origin-width=&quot;2210&quot; data-origin-height=&quot;1210&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dvSwwQ/btsH03mu8Pz/0FP6YyQzkRkRBNAKyP3kDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dvSwwQ/btsH03mu8Pz/0FP6YyQzkRkRBNAKyP3kDK/img.png&quot; data-alt=&quot;container에서 cli로 migration:run 실행하기&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dvSwwQ/btsH03mu8Pz/0FP6YyQzkRkRBNAKyP3kDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdvSwwQ%2FbtsH03mu8Pz%2F0FP6YyQzkRkRBNAKyP3kDK%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;2210&quot; height=&quot;1210&quot; data-filename=&quot;스크린샷 2024-06-16 오후 2.52.33.png&quot; data-origin-width=&quot;2210&quot; data-origin-height=&quot;1210&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;container에서 cli로 migration:run 실행하기&lt;/figcaption&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;</description>
      <category>NestJS</category>
      <category>CLI</category>
      <category>docker</category>
      <category>Migration</category>
      <category>nestJS</category>
      <category>TypeORM</category>
      <author>jmhope</author>
      <guid isPermaLink="true">https://hopedevelopment.tistory.com/95</guid>
      <comments>https://hopedevelopment.tistory.com/95#entry95comment</comments>
      <pubDate>Sun, 16 Jun 2024 14:55:11 +0900</pubDate>
    </item>
    <item>
      <title>[NestJS] TypeORM 설정</title>
      <link>https://hopedevelopment.tistory.com/94</link>
      <description>&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;NestJS를 사용하며 TypeORM을 사용하는 경우 설정할 때 이전에 했던 방식과 더 나은 방식을 기술할 예정입니다.&lt;br&gt;&amp;nbsp;&lt;br&gt;일단 TypeORM 설정을 파일로 따로 관리하여 AppModule에 Module decorator에 길게 관리하는 것을 싫어했습니다. 이에 아래와 같이 따로 파일로 관리하였습니다.&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;/// src/app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ConfigModule } from '@nestjs/config';
import { typeORMConfig } from 'src/config/typeorm.config';
import { QuestionModule } from 'src/question/question.module';
import { AnswerModule } from 'src/answer/answer.module';

@Module({
&amp;nbsp;&amp;nbsp;imports: [
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ConfigModule.forRoot({
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;isGlobal: true,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;TypeOrmModule.forRoot(typeORMConfig),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;QuestionModule,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AnswerModule,
&amp;nbsp;&amp;nbsp;],
&amp;nbsp;&amp;nbsp;controllers: [],
&amp;nbsp;&amp;nbsp;providers: [],
})
export class AppModule {}


/// src/config/typeorm.config.ts
import { ConfigService } from '@nestjs/config';
import 'dotenv/config';
import { TypeOrmModuleOptions } from &quot;@nestjs/typeorm&quot;;
import { Answer } from 'src/entities/answer.entity';
import { Question } from 'src/entities/question.entity';

const config : ConfigService = new ConfigService();

export const typeORMConfig : TypeOrmModuleOptions = {
&amp;nbsp;&amp;nbsp;type: 'postgres',
&amp;nbsp;&amp;nbsp;host: config.get&amp;lt;string&amp;gt;('DATABASE_HOST'),
&amp;nbsp;&amp;nbsp;port: config.get&amp;lt;number&amp;gt;('DATABASE_PORT'),
&amp;nbsp;&amp;nbsp;username: config.get&amp;lt;string&amp;gt;('DATABASE_USERNAME'),
&amp;nbsp;&amp;nbsp;password: config.get&amp;lt;string&amp;gt;('DATABASE_PASSWORD'),
&amp;nbsp;&amp;nbsp;database: config.get&amp;lt;string&amp;gt;('DATABASE_DATABASE'),
&amp;nbsp;&amp;nbsp;entities: [Question, Answer],
&amp;nbsp;&amp;nbsp;synchronize : false,
&amp;nbsp;&amp;nbsp;keepConnectionAlive: true,
}

export const testTypeORMConfig : TypeOrmModuleOptions = {
&amp;nbsp;&amp;nbsp;type: 'postgres',
&amp;nbsp;&amp;nbsp;host: config.get&amp;lt;string&amp;gt;('TEST_DATABASE_HOST'),
&amp;nbsp;&amp;nbsp;port: config.get&amp;lt;number&amp;gt;('TEST_DATABASE_PORT'),
&amp;nbsp;&amp;nbsp;username: config.get&amp;lt;string&amp;gt;('TEST_DATABASE_USERNAME'),
&amp;nbsp;&amp;nbsp;password: config.get&amp;lt;string&amp;gt;('TEST_DATABASE_PASSWORD'),
&amp;nbsp;&amp;nbsp;database: config.get&amp;lt;string&amp;gt;('TEST_DATABASE_DATABASE'),
&amp;nbsp;&amp;nbsp;entities: [Question, Answer],
&amp;nbsp;&amp;nbsp;logging: true,
&amp;nbsp;&amp;nbsp;synchronize : true
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;NestJS는 내부적으로 IoC container를 이용하여 DI(의존성 주입)을 관리합니다. 위와 같은 방식을 사용한다면 외부에서 ConfigService를 생성하고 dotenv/config도 이용하기에 여러 번 환경변수가 load되는 것이 매우 불편하였습니다.&lt;br&gt;이러한 방식이 매우 불편하였기에 좀더 NestJS사용에 맞게 사용하고자 하였습니다.&lt;br&gt;TypeOrmModule.forRoot 대신 TypeOrmModule.forRootAsync로 교체하였으며 AppModule의 ConfigModule에서 config를 load하고 이후에 ConfigService를 주입하는 방식을 채택하였습니다.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;/// src/app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { typeORMConfig } from 'src/config/typeorm.config';
import { QuestionModule } from 'src/question/question.module';
import { AnswerModule } from 'src/answer/answer.module';

@Module({
&amp;nbsp;&amp;nbsp;imports: [
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ConfigModule.forRoot({
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;isGlobal: true,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;TypeOrmModule.forRootAsync({
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;inject: [ConfigService],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;useFactory: async (config: ConfigService) =&amp;gt; await typeORMConfig(config)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;QuestionModule,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AnswerModule,
&amp;nbsp;&amp;nbsp;],
&amp;nbsp;&amp;nbsp;controllers: [],
&amp;nbsp;&amp;nbsp;providers: [],
})
export class AppModule {}


/// src/config/typeorm.config.ts
import { ConfigService } from '@nestjs/config';
import { TypeOrmModuleOptions } from &quot;@nestjs/typeorm&quot;;
import { Answer } from 'src/entities/answer.entity';
import { Question } from 'src/entities/question.entity';

export const typeORMConfig = async (config: ConfigService): Promise&amp;lt;TypeOrmModuleOptions&amp;gt; =&amp;gt; {
&amp;nbsp;&amp;nbsp;return {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;type: 'postgres',
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;host: config.get&amp;lt;string&amp;gt;('DATABASE_HOST'),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;port: config.get&amp;lt;number&amp;gt;('DATABASE_PORT'),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;username: config.get&amp;lt;string&amp;gt;('DATABASE_USERNAME'),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;password: config.get&amp;lt;string&amp;gt;('DATABASE_PASSWORD'),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;database: config.get&amp;lt;string&amp;gt;('DATABASE_DATABASE'),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;entities: [Question, Answer],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;synchronize : false,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;keepConnectionAlive: true,
&amp;nbsp;&amp;nbsp;}
};

export const testTypeORMConfig = async (config: ConfigService): Promise&amp;lt;TypeOrmModuleOptions&amp;gt; =&amp;gt; {
&amp;nbsp;&amp;nbsp;return {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;type: 'postgres',
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;host: config.get&amp;lt;string&amp;gt;('TEST_DATABASE_HOST'),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;port: config.get&amp;lt;number&amp;gt;('TEST_DATABASE_PORT'),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;username: config.get&amp;lt;string&amp;gt;('TEST_DATABASE_USERNAME'),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;password: config.get&amp;lt;string&amp;gt;('TEST_DATABASE_PASSWORD'),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;database: config.get&amp;lt;string&amp;gt;('TEST_DATABASE_DATABASE'),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;entities: [Question, Answer],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;logging: true,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;synchronize : true
&amp;nbsp;&amp;nbsp;}
};&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;하지만 아직 불편한 점은 Entity를 정의할 때마다 TypeOrmModuleOptions 중 entities에 매번 추가 해줘야 한다는 것이 불편하여 그냥 알아서 해주길 바라기 때문에 경로를 통하여 entities를 사용할 수 있게 설정하였습니다. 경로는 build후의 경로에 js를 로드하는 방식으로 하였습니다. (만약 ts 경로를 하는 경우 코드상에 있는 경로들을 외부 경로로 인식하여 import하지 못하는 에러가 발생하는 이슈가 있었습니다... build후 실행되기에 생각해보면 당연한 이슈..)&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;Unknown&quot; data-ke-language=&quot;Unknown&quot;&gt;&lt;code&gt;/// src/config/typeorm.config.ts
import { ConfigService } from '@nestjs/config';
import { TypeOrmModuleOptions } from &quot;@nestjs/typeorm&quot;;

export const typeORMConfig = async (config: ConfigService): Promise&amp;lt;TypeOrmModuleOptions&amp;gt; =&amp;gt; {
&amp;nbsp;&amp;nbsp;return {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;type: 'postgres',
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;host: config.get&amp;lt;string&amp;gt;('DATABASE_HOST'),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;port: config.get&amp;lt;number&amp;gt;('DATABASE_PORT'),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;username: config.get&amp;lt;string&amp;gt;('DATABASE_USERNAME'),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;password: config.get&amp;lt;string&amp;gt;('DATABASE_PASSWORD'),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;database: config.get&amp;lt;string&amp;gt;('DATABASE_DATABASE'),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;entities: ['dist/entities/*.js'],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;synchronize : false,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;keepConnectionAlive: true,
&amp;nbsp;&amp;nbsp;}
};

export const testTypeORMConfig = async (config: ConfigService): Promise&amp;lt;TypeOrmModuleOptions&amp;gt; =&amp;gt; {
&amp;nbsp;&amp;nbsp;return {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;type: 'postgres',
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;host: config.get&amp;lt;string&amp;gt;('TEST_DATABASE_HOST'),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;port: config.get&amp;lt;number&amp;gt;('TEST_DATABASE_PORT'),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;username: config.get&amp;lt;string&amp;gt;('TEST_DATABASE_USERNAME'),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;password: config.get&amp;lt;string&amp;gt;('TEST_DATABASE_PASSWORD'),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;database: config.get&amp;lt;string&amp;gt;('TEST_DATABASE_DATABASE'),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;entities: ['dist/entities/*.js'],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;logging: true,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;synchronize : true
&amp;nbsp;&amp;nbsp;}
};&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;옵션들을 좀더 NestJS과 TypeORM에게 할 일들을 맡기는 구조로 바뀌어 NestJS과 TypeORM을 동시 사용에 좀더 적합(?)하다는 견해입니다.&lt;br&gt;&amp;nbsp;&lt;br&gt;틀린 부분이 있을 수 있으니 알려주시면 감사하겠습니다 :)&lt;/p&gt;</description>
      <category>NestJS</category>
      <category>config</category>
      <category>forRootAsync</category>
      <category>nestJS</category>
      <category>Option</category>
      <category>TypeORM</category>
      <author>jmhope</author>
      <guid isPermaLink="true">https://hopedevelopment.tistory.com/94</guid>
      <comments>https://hopedevelopment.tistory.com/94#entry94comment</comments>
      <pubDate>Sun, 21 Apr 2024 13:47:33 +0900</pubDate>
    </item>
    <item>
      <title>이슈 해결 - [TypeORM] DB migration file generate</title>
      <link>https://hopedevelopment.tistory.com/93</link>
      <description>&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;TypeORM을 이용하던 도중 migration을 위한 명령어를 통하여 migration file을 생성하려고 했다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;migration file을 생성하기 위한 명령어는 &lt;a title=&quot;create&quot; href=&quot;https://orkhan.gitbook.io/typeorm/docs/migrations#creating-a-new-migration&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;create&lt;/a&gt;와 &lt;a title=&quot;generate&quot; href=&quot;https://orkhan.gitbook.io/typeorm/docs/migrations#generating-migrations&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;generate&lt;/a&gt;가 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1713670511482&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;typeorm migration:create ./path-to-migrations-dir/PostRefactoring
// or
typeorm migration:generate -d &amp;lt;path/to/datasource&amp;gt; path/to/migrations/&amp;lt;migration-name&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;create로 migration file을 생성하면 class 안에 up과 down 메서드를 제외하고 아무것도 있지 않지만 generate로 migration file을 생성하면 안에 코드가 들어있다. 이번에는 차이를 설명하는 것이 아닌 이슈 해결에 중점을 두어 쓰는 글이기에 둘의 차이는 &lt;a title=&quot;멍개님의 블로그&quot; href=&quot;https://blog.naver.com/pjt3591oo/223061702435&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;멍개님의 블로그&lt;/a&gt;를 보면 좋을 듯 합니다 :)&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;TypeORM의 버전이 0.2에서 0.3으로 올라가며&lt;span&gt; create로 생성하는 경우 default 경로를 지정하여 이름만 작성하여 default경로에 migration file에 작성되지 않는 이슈가 있었다. 다른 사람들이 이미 먼저 이슈를 오픈했으나 아직 TypeORM에서는 기능을 새로 넣어주지 않은 모양이다.. &lt;a href=&quot;https://github.com/typeorm/typeorm/issues/8814&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/typeorm/typeorm/issues/8814&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1713671250663&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;Typeorm CLI not works perfectly after 0.3.0 &amp;middot; Issue #8814 &amp;middot; typeorm/typeorm&quot; data-og-description=&quot;Issue Description After version 0.3.0 cli does not work perfectly. when I try to create an entity or migration using cli is create entity or migration in the root directory. However, in the old ver...&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/typeorm/typeorm/issues/8814&quot; data-og-url=&quot;https://github.com/typeorm/typeorm/issues/8814&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/6vTlj/hyVSWUAPF4/BBZq9vby0bQdharbUnKlb1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/typeorm/typeorm/issues/8814&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/typeorm/typeorm/issues/8814&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/6vTlj/hyVSWUAPF4/BBZq9vby0bQdharbUnKlb1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&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;Typeorm CLI not works perfectly after 0.3.0 &amp;middot; Issue #8814 &amp;middot; typeorm/typeorm&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Issue Description After version 0.3.0 cli does not work perfectly. when I try to create an entity or migration using cli is create entity or migration in the root directory. However, in the old ver...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.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;하지만 어거지로 매번 경로를 앞에 붙여서 생성하기 귀찮았던 나는 이슈를 읽어보며 &lt;a title=&quot;해결방법&quot; href=&quot;https://github.com/typeorm/typeorm/issues/8814#issuecomment-1147880721&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;해결방법&lt;/a&gt;을 찾았다!!&lt;/p&gt;
&lt;pre id=&quot;code_1713671442001&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&quot;typeorm&quot;: &quot;node --require ts-node/register ./node_modules/typeorm/cli.js&quot;,
&quot;migration:create&quot;: &quot;npm run typeorm migration:create ./migrations/$npm_config_name&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;package.json에 script 부분에 위와 같이 수정한 다음 아래의 명령어를 사용하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1713671318477&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm run migration:create --name=&amp;lt;마이그레이션 이름&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;아쉬운 점은 yarn은 사용되지 않고 npm만 사용 가능하다... (분명 개인프로젝트에서는 되었는데 회사에서 사용하니 안 되는 것을 보고 이슈를 찾아보니...)&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>NestJS</category>
      <category>create</category>
      <category>Database</category>
      <category>DB</category>
      <category>generate</category>
      <category>Migration</category>
      <category>TypeORM</category>
      <author>jmhope</author>
      <guid isPermaLink="true">https://hopedevelopment.tistory.com/93</guid>
      <comments>https://hopedevelopment.tistory.com/93#entry93comment</comments>
      <pubDate>Sun, 21 Apr 2024 13:04:38 +0900</pubDate>
    </item>
    <item>
      <title>Node.js - 프로젝트 초기 환경 설정 팁</title>
      <link>https://hopedevelopment.tistory.com/92</link>
      <description>&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;1. NVM(Node Version Manager)사용&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;일반적으로 Node 버전을 업데이트와 업그레이드하기 굉장히 귀찮기도 하고 한 번 잘못 꼬이면 해결하기 힘들기 때문이다. 많은 언어들에서도 version manager가 있다. java에서는 &lt;a title=&quot;jabba&quot; href=&quot;https://github.com/shyiko/jabba&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;jabba&lt;/a&gt;, golang에서는 &lt;a title=&quot;gvm&quot; href=&quot;https://github.com/moovweb/gvm&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;gvm&lt;/a&gt;등이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영체제마다 설치 방법이 다르다. 아래의 설명들은 Intel Mac에서 &lt;a title=&quot;homebrew&quot; href=&quot;https://brew.sh/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;homebrew&lt;/a&gt;가 설치가 되어있으며 zsh를 사용한다는 전제로 하는 설명이다.&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;(운영체제와 쉘 종류에 따라 설치 방법이 다르니 주의 바랍니다.)&lt;/b&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;먼저, brew로 nvm을 install한다.&lt;/p&gt;
&lt;pre id=&quot;code_1697967871477&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;brew install nvm&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;환경변수 설정 및 script를 실행한다.&lt;/p&gt;
&lt;pre id=&quot;code_1697965138678&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export NVM_DIR=~/.nvm
source $(brew --prefix nvm)/nvm.sh&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;a title=&quot;링크&quot; href=&quot;https://github.com/nvm-sh/nvm#troubleshooting-on-macos&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;링크&lt;/a&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 id=&quot;code_1701096201755&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;nvm -v # nvm의 버전을 확인합니다.

nvm list available # 사용가능한 Node 버전들이 조회된다.

nvm install node # node 최신 버전으로 설치됩니다.

nvm install {원하는 버전(e.g. 20.10)} # 원하는 버전의 node가 설치됩니다.

nvm use node # 사용하고자 하는 node 버전으로 변경합니다.

nvm list # 사용가능한 node 버전들을 조회합니다. (nvm ls도 동일)&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;2. husky로 git hook을 이용한 commit convention 적용&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;협업을 위해서는 commit convention의 존재가 필요하다. 이를 강제하기 위해서는 git hook을 이용하면 편리하게 적용할 수 있다. 특히 기존 명령어 git commit을 이용하면 굉장히 편하다.&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;node가 설치되었고 git도 걸치된 상태를 전제로 하는 설명이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 기본적으로 npm을 기반으로 설명할 예정이다. yarn을 사용한다면 약간 다를 수 있다.&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;버전에 따라 설정이 달라져 다시 작성한다. 현재는 install과 add 모두 deprecated되었다. version 9이전과 이후 사용법이 달라졌기에 버전 별로 사용밥법이 다르다. &lt;a title=&quot;changelog&quot; href=&quot;https://github.com/typicode/husky/releases/tag/v9.0.1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/typicode/husky/releases/tag/v9.0.1&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1714872192712&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;Release v9.0.1 &amp;middot; typicode/husky&quot; data-og-description=&quot;Kicking off the year with an exciting update! Note: install using husky@latest to get the bug fixes that were released after. Introducing husky init v8 npm pkg set scripts.prepare=&amp;quot;husky instal...&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/typicode/husky/releases/tag/v9.0.1&quot; data-og-url=&quot;https://github.com/typicode/husky/releases/tag/v9.0.1&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bXXzDa/hyVZtSA8vE/W1c5zKv585PkObIvV0jZb0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/DPcKY/hyVZk2sf8i/9exUadTZkIdyX2gdhjItzK/img.png?width=1024&amp;amp;height=1024&amp;amp;face=0_0_1024_1024&quot;&gt;&lt;a href=&quot;https://github.com/typicode/husky/releases/tag/v9.0.1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/typicode/husky/releases/tag/v9.0.1&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bXXzDa/hyVZtSA8vE/W1c5zKv585PkObIvV0jZb0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/DPcKY/hyVZk2sf8i/9exUadTZkIdyX2gdhjItzK/img.png?width=1024&amp;amp;height=1024&amp;amp;face=0_0_1024_1024');&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;Release v9.0.1 &amp;middot; typicode/husky&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Kicking off the year with an exciting update! Note: install using husky@latest to get the bug fixes that were released after. Introducing husky init v8 npm pkg set scripts.prepare=&quot;husky instal...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;pre id=&quot;code_1701097552798&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# npm 초기화
npm init

# husky 및 commitizen 설치
npm i husky commitizen --save-dev

# .husky 디렉토리 설정
## version 9부터
npx husky init
## version 9이전까지. 최신 버전에서 install command는 deprecated 되었다.
npx husky install

# git commit 명령어 만으로 convention 적용
## version 9부터
echo &quot;exec &amp;lt; /dev/tty &amp;amp;&amp;amp; node_modules/.bin/cz --hook || true&quot; &amp;gt; ./.husky/pre-commit 
## version 9이전까지. 최신 버전에서 add command는 deprecated 되었다.
npx husky add .husky/prepare-commit-msg 'exec &amp;lt; /dev/tty &amp;amp;&amp;amp; node_modules/.bin/cz --hook || true'&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;위의 명령어를 작성한 뒤 package.json 파일에 아래와 같이 추가해 준다.&lt;/p&gt;
&lt;pre id=&quot;code_1701097701969&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  &quot;config&quot;: {
    &quot;commitizen&quot;: {
      &quot;path&quot;: &quot;./node_modules/cz-conventional-changelog&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;그러면 git commit 명령어로 commit convention을 적용시킬 수 있다.&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;만약 commit 전에 prettier 와 ESLint 설정을 적용할 수 있다. 이는 링크를 참조하자. (&lt;a href=&quot;https://velog.io/@jiynn_12/%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A1%9C-%ED%98%91%EC%97%85%ED%95%98%EA%B8%B0-husky&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;링크&lt;/a&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;※ husky의 버전이 9이상부터 'exec &amp;lt; /dev/tty &amp;amp;&amp;amp; node_modules/.bin/cz --hook || true' 명령어를 추가하더라도 convention 관련 cli가 나오지만 커밋 메시지가 빈 메시지로 변경된다. 이 이슈에 대하여 방법을 찾아볼 예정이지만 현재는 버전 8이하의 버전으로 진행하는 것이 나아보인다.&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;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직 다 정리한 것은 아니지만 기본적으로 필수적인 것만 정리한 것이다. 시간이 된다면 틈틈이 정리 예정이다.&lt;/p&gt;</description>
      <category>Node.js</category>
      <category>commit convention</category>
      <category>git hook</category>
      <category>husky</category>
      <category>nvm</category>
      <author>jmhope</author>
      <guid isPermaLink="true">https://hopedevelopment.tistory.com/92</guid>
      <comments>https://hopedevelopment.tistory.com/92#entry92comment</comments>
      <pubDate>Tue, 28 Nov 2023 00:17:29 +0900</pubDate>
    </item>
    <item>
      <title>[JavaScript] 백준 14852 : 타일 채우기 3</title>
      <link>https://hopedevelopment.tistory.com/91</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;level : gold 4&lt;br&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/14852&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;타일 채우기 3&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;figure data-ke-type=&quot;opengraph&quot; data-og-title=&quot;14852번: 타일 채우기 3&quot; data-ke-align=&quot;alignCenter&quot; data-og-description=&quot;첫째 줄에 경우의 수를 1,000,000,007로 나눈 나머지를 출력한다.&quot; data-og-host=&quot;www.acmicpc.net&quot; data-og-source-url=&quot;https://www.acmicpc.net/problem/14852&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/57dIT/hyS5EBJuQ3/yDEYfIN99eliWqKJ7ZaCT1/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480&quot; data-og-url=&quot;https://www.acmicpc.net/problem/14852&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/14852&quot; target=&quot;_blank&quot; data-source-url=&quot;https://www.acmicpc.net/problem/14852&quot;&gt;&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/57dIT/hyS5EBJuQ3/yDEYfIN99eliWqKJ7ZaCT1/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480')&quot;&gt; &lt;/div&gt;&lt;div class=&quot;og-text&quot;&gt;&lt;p class=&quot;og-title&quot;&gt;14852번: 타일 채우기 3&lt;/p&gt;&lt;p class=&quot;og-desc&quot;&gt;첫째 줄에 경우의 수를 1,000,000,007로 나눈 나머지를 출력한다.&lt;/p&gt;&lt;p class=&quot;og-host&quot;&gt;www.acmicpc.net&lt;/p&gt;&lt;/div&gt;&lt;/a&gt;&lt;/figure&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;My Solution&lt;/span&gt;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const input = require(&quot;fs&quot;).readFileSync(&quot;/dev/stdin&quot;).toString().trim();
const N = Number(input);

/**
 * 
 * @param {number} n
 * @returns {number}
 */
function solution(n){
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(n === 1)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return 2;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else if(n === 2)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return 7;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;let dp = new Array(n+1).fill(0n);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const max = 1000000007n;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dp[1] = 2n;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dp[2] = 7n;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dp[3] = 22n;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for(let i = 4; i &amp;lt;= n; i++) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dp[i] = ((max + 3n * dp[i - 1]) - dp[i - 3] + dp[i - 2])%max;
	}
	return Number(dp[n]%max);
}

console.log(solution(N));&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;풀이방법&lt;/span&gt;&lt;br&gt;&amp;nbsp;&lt;br&gt;위 문제는 DP문제이며 점화식으로 접근해야합니다. &lt;br&gt;문제의 예제로 1,2,3째 항을 알려주었습니다.&lt;br&gt;먼저 n이 1인 경우는 2개이며 n이 2인 경우는 7개, n이 3인 경우는 22개 입니다.&lt;br&gt;n이 1이나 2인 경우는 찾기가 매우 쉬울 것이나 3이상은 다른 모양이 생깁니다. 따라서 수를 보고 처음에는 규칙성이 잘 안 보입니다.(보인다면 당신은 천재 혹은 그 이상... 저는 안보였습니다.) 그래서 점화식을 세우기가 어려웠습니다.&lt;br&gt;그리하여 차근차근 그림을 그리며 점화식을 세웠습니다.(설명은 좀 어려운데 그림 보세요. &lt;a href=&quot;https://dlog0518.tistory.com/41&quot; target=&quot;_self&quot;&gt;&lt;span&gt;&lt;span style=&quot;background-color: #e6f5ff;&quot;&gt;&lt;span style=&quot;color: #0070d1;&quot;&gt;블로그&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;)&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2659&quot; data-origin-height=&quot;738&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ocWZd/btskZs3lvq8/pWtgBUMRiI4qNv3I21s01k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ocWZd/btskZs3lvq8/pWtgBUMRiI4qNv3I21s01k/img.jpg&quot; data-alt=&quot;점화식&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ocWZd/btskZs3lvq8/pWtgBUMRiI4qNv3I21s01k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FocWZd%2FbtskZs3lvq8%2FpWtgBUMRiI4qNv3I21s01k%2Fimg.jpg&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;2659&quot; height=&quot;738&quot; data-origin-width=&quot;2659&quot; data-origin-height=&quot;738&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;점화식&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시그마가 나오길래 코드짜기가 어렵겠다고 생각을 하였습니다. 그리하여 시그마를 없애고 싶다는 생각이 들었고 이를 점화식 전개하였습니다.&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3325&quot; data-origin-height=&quot;1774&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnXrno/btskSqeYrSE/3ooLQTRi7qmuv60dZpvO30/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnXrno/btskSqeYrSE/3ooLQTRi7qmuv60dZpvO30/img.jpg&quot; data-alt=&quot;점화식 전개&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnXrno/btskSqeYrSE/3ooLQTRi7qmuv60dZpvO30/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnXrno%2FbtskSqeYrSE%2F3ooLQTRi7qmuv60dZpvO30%2Fimg.jpg&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;3325&quot; height=&quot;1774&quot; data-origin-width=&quot;3325&quot; data-origin-height=&quot;1774&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;점화식 전개&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리하여 코드로 짜기 쉬운 점화식을 만들었습니다. 일반항을 만들면 좋았겠지만 저의 한계로 잘은...ㅎ&lt;br&gt;마지막 줄에 있는 0을 굳이 1로 안 두고 n을 4부터 주어도 성립합니다!&amp;nbsp;&lt;br&gt;그리하여 dp를 이용하여 풀면 편하게 풀 수 있습니다. 하지만 여기서 허점은 계속 1000000007로 나눈 나머지을 저장하다 보니 dp에 음수가 발생할 수 있습니다. 그리하여 점화식 계산할 때, 1000000007를 더해주고 계산후에 1000000007로 나눈 나머지를 dp에 저장하면 됩니다.&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;느낀점&lt;/span&gt;&lt;br&gt;처음 문제를 접한 곳은 &lt;a href=&quot;https://blog.naver.com/ndb796/221233586932&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;나동빈님의 Dynamic Programming&lt;/span&gt;&lt;/a&gt;설명에서였습니다.&lt;br&gt;처음에는 어렵다는 느낌만 받았고 2차원 배열로 푸는 풀이에 대하여 의문이 들며 어떠한 점화식이 나와야 했을까라는 생각을 했습니다. 결국 2차원 배열에 쓰인 점화식을 이해하지 못하여 다른 방법으로 풀었습니다.&lt;br&gt;또한 n보다 큰 index를 참조하는 경우가 생겨 99%에서 계속 TypeError가 발생하여 고생을 했습니다.&lt;/p&gt;</description>
      <category>Algorithm/백준</category>
      <category>14852</category>
      <category>BOJ</category>
      <category>DP</category>
      <category>JavaScript</category>
      <category>js</category>
      <category>백준</category>
      <category>타일 채우기 3</category>
      <author>jmhope</author>
      <guid isPermaLink="true">https://hopedevelopment.tistory.com/91</guid>
      <comments>https://hopedevelopment.tistory.com/91#entry91comment</comments>
      <pubDate>Thu, 22 Jun 2023 16:06:43 +0900</pubDate>
    </item>
    <item>
      <title>[JavaScript] 혼자 놀기의 달인</title>
      <link>https://hopedevelopment.tistory.com/90</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;level : 2&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/131130&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;혼자 놀기의 달인&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1682135968812&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;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/131130&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/JDlJz/hySlGPw9JH/gsGfPZ43Cj4xryFdKkwmTK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bJpKma/hySmSOm2FK/11mv1xsSE5QDpBSQt1ddY0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/131130&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/131130&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/JDlJz/hySlGPw9JH/gsGfPZ43Cj4xryFdKkwmTK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bJpKma/hySmSOm2FK/11mv1xsSE5QDpBSQt1ddY0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&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;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0593d3; text-align: start;&quot;&gt;My Solution&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1682135995233&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function solution(cards) {
    const len = cards.length;
    let visited = new Array(len).fill(false);
    let result = [];

    while(visited.filter(v=&amp;gt;v).length &amp;lt; len){
        let temp = [];
        /// 첫번째 숫자 뽑기
        for(let i = 0; i &amp;lt; len; i++){
            if(!visited[i]){
                temp.push(i);
                visited[i] = true;
                break;
            }
        }
        const start = temp[0];

        while(cards[temp[temp.length - 1]] - 1 !== start){
            visited[cards[temp[temp.length - 1]] - 1] = true;
            temp.push(cards[temp[temp.length - 1]] - 1);
        }
        result.push(temp);
    }
    result.sort((a,b)=&amp;gt;b.length - a.length);
    return result.length &amp;gt; 1 ? result[0].length * result[1].length : 0;
}&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;span style=&quot;color: #0593d3; text-align: start;&quot;&gt;풀이방법&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 문제에서 주어지는 cards에 index가 주어진다. 이때 index는 1부터 시작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cards에서 순환하는 배열을 찾아 가장 긴 배열 두 개의 길이의 곱이 범희가 게임에서 최고점을 얻을 수 있다.&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;가장 먼저 뽑은 상자의 숫자는 start로 뽑은 상자의 index에 해당하는 visited를 true를 변환하고 뽑은 상자의 수보다 1작은 index에 해당하는 cards의 상자를 뽑는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 최근에 뽑은 상자의 index에 해당하는 visited를 true를 변환하고 다시 가장 최근에 뽑은 숫자에 해당하는 index - 1의 cards의 상자를 start로 돌아오기 전까지 계속 뽑으며 위와 같은 과정을 반복한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뽑을 때마다 index를 배열에 넣어 temp라는 배열을 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;temp라는 배열을 전체 배열 result에 push한다.&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;result의 원소는 순환하는 배열의 index를 가지는 배열로 이루어져 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러므로 result를 원소의 길이를 기준으로 내림차순으로 정렬한다.&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;만약 result에 2개 이상의 배열이 있다면 가장 앞의 2개의 배열의 길이를 반환하고 아닐 경우 0을 반환한다.&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: #0593d3; text-align: start;&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;지금 내 설명이 좋지 못하더라도 적어 놓고 틈틈히 다시 보며 더욱 이해가 쉽도록 명확하게 적어야겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithm/프로그래머스</category>
      <category>JavaScript</category>
      <category>js</category>
      <category>programmers</category>
      <category>프로그래머스</category>
      <category>혼자 놀기의 달인</category>
      <author>jmhope</author>
      <guid isPermaLink="true">https://hopedevelopment.tistory.com/90</guid>
      <comments>https://hopedevelopment.tistory.com/90#entry90comment</comments>
      <pubDate>Sat, 22 Apr 2023 13:17:18 +0900</pubDate>
    </item>
    <item>
      <title>플로이드 와샬(Floyd Warshall) 알고리즘</title>
      <link>https://hopedevelopment.tistory.com/88</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;플로이드 와샬 알고리즘은 모든 각각의 노드를 출발점으로해서 모든 정점까지의 최단경로를 구하는 알고리즘입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다익스트라 알고리즘은 가장 적은 비용을 하나씩 선택해야 했다면 플로이드 와샬 알고리즘은 기본적으로 &lt;b&gt;'거쳐가는&amp;nbsp;정점'&lt;/b&gt;을&amp;nbsp;기준으로&amp;nbsp;알고리즘을&amp;nbsp;수행한다는&amp;nbsp;점에서&amp;nbsp;그&amp;nbsp;특징이&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;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/72413&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;프로그래머스의 합승 택시 요금 문제&lt;/a&gt;가 플로이드 와샬을 활용할 수 있는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제의 풀이 코드로는 아래와 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1680244136465&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function solution(n, s, a, b, fares) {
    let dp = new Array(n).fill().map((_,i)=&amp;gt;new Array(n).fill().map((_,j)=&amp;gt;i===j ? 0 : Infinity));
    
    fares.forEach(([n1,n2,cost])=&amp;gt;{
        dp[n1 - 1][n2 - 1] = cost;
        dp[n2 - 1][n1 - 1] = cost;
    });
    
    /// 플로이드-와샬 알고리즘
    for(let k = 0; k &amp;lt; n; k++)
        for(let i = 0; i &amp;lt; n; i++)
            for(let j = 0; j &amp;lt; n; j++)
                if(dp[i][j] &amp;gt; dp[i][k] + dp[k][j])
                    dp[i][j] = dp[i][k] + dp[k][j];
    
    let answer = dp[s-1][a-1] + dp[s-1][b-1];

    for(let i = 0; i &amp;lt; n; i++) {
        const shortest = dp[s-1][i] + dp[i][a-1] + dp[i][b-1];
        answer = Math.min(answer, shortest);
    }

    return answer;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 모든 노드들을 거쳐 최단경로를 탐색하기 때문에 시간 복잡도는 O(N^3)이며 이차원 배열을 사용하기에 공간복잡도는 O(N^2)이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Computer Science/Algorithm</category>
      <category>Floyd warshall</category>
      <category>JavaScript</category>
      <category>js</category>
      <category>그래프</category>
      <category>플로이드 와샬</category>
      <category>합승 택시 요금</category>
      <author>jmhope</author>
      <guid isPermaLink="true">https://hopedevelopment.tistory.com/88</guid>
      <comments>https://hopedevelopment.tistory.com/88#entry88comment</comments>
      <pubDate>Fri, 31 Mar 2023 15:29:55 +0900</pubDate>
    </item>
  </channel>
</rss>