ESC

25년 회고 - 태풍이 휘몰아치는

잡담

25년 회고 - 태풍이 휘몰아치는

너무나도 힘들었던 2025년에 대해 돌아볼 시간이 왔습니다. 이번연도 회고는 넘어갈까 생각하다가도 생성형 AI를 사용하지 않는 제 블로그에 이번연도에 작성한 글이 얼마 없었기 때문에 회고라도 작성하려고 열심히 써보고 있습니다. # 고등학교 졸업 --- 현재는 이전과 다른 학교생활을 즐기고 있습니다. 고등학교 졸업식에 갈 때, 브로콜리너마저의 <졸업>을 들으면서 졸업 분위기에 기분을 맞춰보고 싶었지만, 쉽지 않았습니다. ![Graduate](/Review-2025-Graduate.jpg) 하여튼 12년 동안의 학교생활에 마침표를 찍고 현재는 사회와 마주할 준비를 하는 중입니다. # 운전면허 취득 --- 고등학교 졸업 후, 시간이 많이 남았었습니다. 이 시간 동안 너무나 힘들고 혼란스러운 시간을 보내고 있었지만, 그렇다고 시간을 허무하게 날려버릴 수는 없었기 때문에 무언가라도 하자는 마음으로 운전면허 학원에 등록하여 운전면허를 취득했습니다. ![Driver's License](/Review-2025-Driver-License.jpg) 운전면허 학원에 가보니 '붙는다'라는 표현보다는 '붙여준다'라는 표현이 맞는 거 같다고 생각했었는데요. 운전면허 학원에 가서도 운전면허를 취득하지 못하는 것은 정말 쉽지 않은 일인 것 같았습니다. # 또 `Pixel` --- `Pixel 6 Pro`를 보낸 다음 다시 `Pixel` 시리즈를 구매할 줄은 저도 몰랐습니다. `Pixel 6 Pro` 다음으로 `갤럭시` 시리즈를 사용하고 있었거든요. 좋은 매물이 좋은 가격에 떴길래 저도 모르게 집어 왔는데, 그래도 후회 안 하고 만족스럽게 사용하고 있습니다. 이전과 다르게 요즘은 패치를 통해서 통화도 문제없이 할 수 있고요. ![Pixel 8 Pro](/Review-2025-Pixel-8-Pro.jpg) 그리고 `Pixel 8 Pro`를 사용하다가 너무 만족스러워서 `Pixel Watch 3`를 충동구매 했습니다. ![Pixel Watch 3](/Review-2025-Pixel-Watch-3.jpg) `iPhone`을 사용하면서 `Apple Watch`도 같이 사용하고 있었기 때문에 거의 고민하지 않았던 기기입니다. 원형 돔 디스플레이가 너무 매력적으로 보여서 구매했습니다. 이것도 만족하면서 사용 중입니다. 최근에는 `Google Pay`도 풀어줬어요. # 말레이시아 여행 --- 여러 일들로 인해 너무 지치고 힘들어 어디론가 떠나고 싶었습니다. 마침, 친구가 말레이시아 여행을 제안하였고, 모든 이동 경로는 친구가 짜두어서 저는 따라다니기만 했습니다. ![Malaysia Travel](/Review-2025-Malaysia-Travel.jpg) 친구 따라다니면서 맛있는 것도 먹고, 저라면 절대 하지 않았을 스노클링 같은 것도 해보고 등산도 하고 원숭이, 악어 같은 동물들도 보고... 꽤 재밌었습니다. # 키보드 정착 --- 작년부터 키보드에 빠져서 많은 키보드를 구매했었습니다. `Neo65`, `Neo80`, `Luckey65v2`, `QK101` 등 여러 키보드를 구매해서 사용했습니다. 현재는 `Neo65`, `F1-8X V2`, `TIGER LITE`만 남기고 모두 떠나보냈습니다. 너무 많은 키보드를 목적 없이 구매했다는 생각이 들어서 정말 필요하다고 생각되는 키보드만 남기고 모두 지인들 나누어줬습니다. 그리고, 여태 써보았던 키보드 중 가장 마음에 들었던 것을 뽑아보자면 지온웍스의 `F1-8X V2`를 고르겠습니다. ![F1-8X V2](/Review-2025-F1-8X-V2.jpg) 지금도 열심히 사용하고 있는데, 만약 V3가 나온다면 나오자 마자 사지 않을까 싶어요. # SW인재페스티벌 참가 --- ![SW Festival](/Review-2025-SW-Festival.jpg) SW중심대학사업단에서 진행하는 SW인재페스티벌에 대학 선배들께서 좋은 기회를 주셔서 참가해 볼 수 있었습니다. 오픈소스 LLM 모델을 사용하는 프로젝트를 만들었었는데, 이걸 4일 정도 몰아서 한 번에 완성했었네요. 아쉽게도 수상은 하지 못했었지만, 프로젝트 개발하면서 많은 걸 배웠습니다. # 마무리 --- 하루하루 태풍이 휘몰아치는 곳에서 아무런 대비도 하지 못하고 많이 다쳤었던 한 해였습니다. 물론, 한 해 동안 있었던 모든 일들이 힘들었던 것은 아니었지만, 이곳에 말할 수 없는 힘든 일들을 많이 겪었습니다. 힘들었던 순간을 제외하면, 그렇게 바라던 기술적 성장을 해왔고, 멋진 사람들을 많이 만났고, 많은 도움을 받았습니다. 아직 더 배워야 하고, 할 일이 많지만, 이번 해에는 정말 애썼고 잘했다는 말을 저에게 하고 싶군요. 종종 과거를 많이 그리워했었기 때문에 회고를 작성할 때 과거를 떠올리지 않고 잘 살았다고 이야기했었습니다. 이번 연도에는 너무 바빴던 탓인가 그럴 기회조차 없었네요. 벌써 달력에 내년 일정들이 빼곡히 쌓였습니다. 지금도 사실 해야 할 일이 있는데, 회고를 작성하느려고 미뤄두었습니다. 다시 할 일을 하러 가야겠네요. 이 글을 읽으시는 여러분의 다음 해에는 태풍과 마주하지 않길, 태풍이 어떠한 상처도 주지 않기를 기원합니다.

내가 LCP를 개선한 방법

개발

내가 LCP를 개선한 방법

따로 글을 쓰지 않았지만, 최근 블로그를 개선하는 작업을 하고 있습니다. 이 블로그는 2023년 `Jekyll`를 이용하다, `Next.js`를 기반으로 `Contentlayer`라는 종속성에 의존하여 개발되었었습니다. 최근 제가 작성했던 코드들을 개선하고자 블로그를 최근 `@next/mdx`에 의존하도록 변경하고, 여러 문제점을 해결해나가는 중에 `LightHouse` 검사의 성능 점수가 낮게 나와 이를 분석하고 해결한 경험에 대해 이야기 해보려 합니다. # `LCP`가 뭔가요? --- `Largest Contentful Paint`를 줄여서 `LCP`라고 부르니 저도 이제부터 그렇게 부르겠습니다. `LCP`는 사용자가 페이지를 로딩 할 때를 기준으로 표시되는 가장 큰 이미지, 동영상 등의 렌더링 시간을 의미합니다. [Google](https://web.dev/articles/lcp)에서는 2.5초 이하면 좋다고 언급하였지만, 일단 검사 결과 개선 방안을 제안해줬으니 살펴보겠습니다. # 성능 점수가 왜이리 낮을까? --- `Lighthouse` 검사를 블로그 메인 화면에서 실행하면 성능 점수는 87점, `LCP`는 2.4초였습니다. ![Lighthouse result](/How-I-Improved-LCP-Lighthouse-Result.png) `Lighthouse`는 성능을 개선 할 수 있도록, 인사이트를 제공해줍니다. 인사이트의 내용은 다음과 같았습니다. ![Lighthouse Insights](/How-I-Improved-LCP-Lighthouse-Insights.png) 문제는 이미지가 렌더링 되는 크기에 비해 지나치게 큰 이미지를 로딩하는 것과 이미지 로딩 우선 순위가 정해지지 않았다는 것이였습니다. 두 내용 모두 이미지 최적화가 필요하다는 뜻 입니다. # 해결해보자! --- `Lighthouse`에서는 이러한 성능 문제를 해결 할 수 있도록 해결 방안도 제시해줍니다. 이미지 로딩 우선 순위가 정해지지 않은 문제의 경우 `fetchpriority` 속성을 사용해야하고, `lazy loading`이 적용되지 않았다는 언급이 되어 있습니다. ![Lighthouse Priority](/How-I-Improved-LCP-Lighthouse-Priority.png) 대부분의 PC의 경우 제 블로그 메인 페이지에 접속하였을 때, 4개의 이미지가 먼저 보입니다. 이 이미지들만 먼저 로딩하도록 최적화 하기로 했습니다. 제 블로그의 글 목록에 표시되는 이미지들은 `Next.js`에서 제공하는 `Image` 컴포넌트를 사용합니다. `Image` 컴포넌트에 상위 4개 이미지에만 `fetchPriority` 속성을 `high`, `loading` 속성을 `eager`로 설정했습니다. 나머지는 `fetchPriority` 속성을 `low`, `loading` 속성을 `lazy`로 설정하여 이미지 로딩 우선 순위를 명확히 하였습니다. 이미지가 표시되는 크기에 비해 제공되는 이미지가 너무 크다는 문제에 대해서는 어떠한 개선 방안을 언급해주지는 않았습니다. ![Lighthouse Image Size](/How-I-Improved-LCP-Lighthouse-Image-Size.png) 하지만, `Next.js`의 `Image` 컴포넌트에 대한 공식 문서 중, [`sizes`](https://nextjs.org/docs/app/api-reference/components/image#sizes)에 대한 내용을 보고 이를 이용하여 문제를 해결하면 될 것 같았습니다. 블로그의 메인 페이지는 너비 685px 이상의 기기에서 글 목록을 두 칸으로 나누고, 미만의 기기들에서는 글 목록을 한 칸으로 표시합니다. 이를 기준으로 너비 685px 이상의 기기에서는 이미지를 뷰 포트 절반의 너비로 제공하고, 미만의 기기들에서는 뷰 포트 전체의 너비로 제공합니다. # 해치웠나 --- 수정 사항을 적용한 결과를 `Vercel`를 통하여 배포해보고 다시 확인해보았습니다. 결과를 확인해보니, `Lighthouse` 성능 점수가 향상되었습니다. `Lighthouse` 검사를 블로그 메인 화면에서 실행하면 성능 점수는 100점, `LCP`는 0.4초였습니다. ![Lighthouse improve result](/How-I-Improved-LCP-Lighthouse-Improve-Result.png) 무선 인터넷 품질이 좋지 않은 곳에서 가끔씩 제 블로그에 접속 할 때, 일부 글 목록의 이미지가 렌더링 되지 않는 문제가 더 이상 발생하지 않는 부수적인 효과도 얻었습니다.

이제 Next.js에서 파라미터 쓰는 법

개발

이제 Next.js에서 파라미터 쓰는 법

`App Router`를 쓰는 `Next.js` 15부터 많은 동기 API가 비동기화 되었습니다. 그 중, `params`와 `searchParams`가 비동기 Promise화가 되었습니다. `Client Component`에서는 `use()` 훅을 통한 동기 접근이 가능해집니다. 이에 대한 변경점에 대해 알아봅니다. # `params`와 `searchParams`는 왜 `Promise`가 되었을까? --- `Next.js` 15부터는 각 `Segment` 단위로 비동기 렌더링이 가능해졌습니다. 이러한 변경점 덕분에 각 `Segment`별로 렌더링 후 준비된 부분만 먼저 렌더링 하는 `Streaming Rendering`이 가능해졌습니다. 이제 각 `Segment`를 독립적으로 렌더링 하는 것이 가능해졌기 때문에, 부모 `Segment`가 아직 렌더 중일 떄 자식 `Segment`의 파라미터 값을 바로 읽을 수 없는 상황이 발생하게 됩니다. 이러한 상황을 방지하기 위해 아직 렌더링 되지 않은 `Segment`의 파라미터 값을 가져오는 상황을 방지하기 위해 비동기가 된 것으로 보입니다. # `Layout`에서의 사용 --- `Next.js` 15 이전에는 아래와 같은 구조로 비동기 `Layout`에서 사용이 가능했었습니다. ```typescript type Params = { slug: string } export function generateMetadata({ params }: { params: Params }) { const { slug } = params } export default async function Layout({ children, params, }: { children: React.ReactNode params: Params }) { const { slug } = params } ``` `Next.js` 15 이후부터는 아래와 같이 `params`를 `Promise` 타입으로 변경하고, `generateMetadata`도 비동기 함수로 변경합니다. ```typescript type Params = Promise<{ slug: string }> export async function generateMetadata({ params }: { params: Params }) { const { slug } = await params; } export default async function Layout({ children, params }: { children: React.ReactNode; params: Params }) { const { slug } = await params; } ``` 동기 `Layout`의 경우 `React`의 `use()` 훅을 통하여 `Promise`를 동기적으로 해제합니다. ```typescript import { use } from 'react' type Params = Promise<{ slug: string }> export default function Layout(props: { children: React.ReactNode params: Params }) { const params = use(props.params) const slug = params.slug } ``` # `Page`에서의 사용 --- `Next.js` 15 이전에는 아래와 같은 구조로 비동기 `Page`에서 사용이 가능했었습니다. ```typescript type Params = { slug: string } type SearchParams = { [key: string]: string | string[] | undefined } export function generateMetadata({ params, searchParams, }: { params: Params searchParams: SearchParams }) { const { slug } = params const { query } = searchParams } export default async function Page({ params, searchParams, }: { params: Params searchParams: SearchParams }) { const { slug } = params const { query } = searchParams } ``` `Layout`과 비슷한 맥락으로 `Next.js` 15 이후부터는 아래와 같이 `params`와 `searchParams`를 `Promise` 타입으로 변경하고, `generateMetadata`도 비동기 함수로 변경합니다. ```typescript type Params = Promise<{ slug: string }> type SearchParams = Promise<{ [key: string]: string | string[] | undefined }> export async function generateMetadata(props: { params: Params searchParams: SearchParams }) { const params = await props.params const searchParams = await props.searchParams const slug = params.slug const query = searchParams.query } export default async function Page(props: { params: Params searchParams: SearchParams }) { const params = await props.params const searchParams = await props.searchParams const slug = params.slug const query = searchParams.query } ``` `Client Component`에서는 `React`의 `use()` 훅을 통하여 `Promise`를 동기적으로 해제합니다. ```typescript 'use client' import { use } from 'react' type Params = Promise<{ slug: string }> type SearchParams = Promise<{ [key: string]: string | string[] | undefined }> export default function Page(props: { params: Params searchParams: SearchParams }) { const params = use(props.params) const searchParams = use(props.searchParams) const slug = params.slug const query = searchParams.query } ``` # `Route Handler`에서의 사용 --- `Next.js` 15 이전에는 아래와 같은 구조로 `Route Handler`에서 사용이 가능했었습니다. ```typescript type Params = { slug: string } export async function GET(request: Request, segmentData: { params: Params }) { const params = segmentData.params const slug = params.slug } ``` 비슷한 맥락으로 `Next.js` 15 이후부터는 아래와 같이 `params`를 `Promise` 타입으로 변경합니다. ```typescript type Params = Promise<{ slug: string }> export async function GET(request: Request, segmentData: { params: Params }) { const params = await segmentData.params const slug = params.slug } ``` # 마무리 --- 이제 `Next.js`의 모든 `Component`는 `params`와 `searchParams`를 `Promise`로 다루어야 합니다. 서버에서는 `await`, 클라이언트에서는 `use()`로 접근하는 것이 올바른 패턴입니다. 이러한 변경점이 있는지 모르고 최신 `Next.js` 프로젝트에서 기존처럼 파라미터를 사용하려다가 오류가 발생한 경험이 있습니다. 이번 글에서는 왜 이러한 변화가 생겼는지, 이제 어떻게 사용하는 것이 올바른지에 대해서 알아보았습니다. [참고 문서](https://nextjs.org/docs/app/guides/upgrading/version-15#params--searchparams)

24년 회고 - 사랑하는 일, 증오하는 일

잡담

24년 회고 - 사랑하는 일, 증오하는 일

정말 최선을 다하면서 지낸 2024년이 또 몇 시간 남지 않았습니다. 계속 있는 일이지만, 해가 지나갈 때마다 느낌이 다르다는 게 꽤 신기하네요. 이 말은, 졸업이 얼마 남지 않았다는 이야기이기도 합니다. 이제 졸업도 몇 번 남지 않았지만, 졸업이 다가올 때의 느낌이 다른 것도 꽤 저에겐 신기해요. # `Apple Developer Program` 가입 --- 2024년에 가장 처음 있었던 일이기도 하면서 2024년에 제가 제일 의미 있는 소비를 했다고 생각하는 일입니다. `App Store`에 무언가를 배포하거나 Apple 플랫폼을 위한 무언가를 하려면 꼭 필요한 것이 `Apple Developer Program`입니다. ![Apple Developer Program Enroll Email](/Review-2024-Apple-Developer-Program-Enroll-Email.png) 가입 이후에 `Flutter`를 이용해서 개발한 프로젝트를 직접 배포해 보기도 하고, 저에겐 꽤 재미있는 경험이었습니다. 여전히 하고 싶은 것들이 많이 있어서 129,000원을 지불하고 연장도 했습니다. # 또 노트북 --- 작년에는 제가 노트북 패널을 해 먹었지만, 이번엔 아무것도 안 했는데 패널에 균일도 문제가 생겨서 수리했습니다. Apple 여의도에 갔었는데 수리도 빨랐고 좋은 경험이었습니다. 제가 아는 분들이 항상 Apple 제품이 고장 나면 항상 Apple 여의도에 방문하던데, 그 이유를 알겠더라고요. 제 과실이 아니어서 무상으로 수리했습니다. # 첫 `Pixel` --- 중고로 `Pixel 6 Pro`를 구매했었습니다. ![Pixel 6 Pro](/Review-2024-Pixel-6-Pro.jpg) 처음으로 사용해 보는 `Pixel` 제품군이였는데, 꽤나 재밌는 제품이었습니다. 제 불찰로 디스플레이가 파손되어서 오래 사용하지 못하긴 했었지만, 제가 잘 관리했다면 아직 사용하고 있지 않았을까 싶습니다. `Pixel 6 Pro`를 사용했을 때 경험이 너무 좋아서 다시 `Pixel` 제품군 구매를 고려 중인데, 한국에 정발한 제품이 아니다 보니 여러 문제점이 있어서 계속 고려 중이기만 합니다. # 첫 `HomePod` --- `Apple`의 `HomePod mini` 두 개를 최근부터 사용하게 되었는데, 꽤 좋은 기기라고 생각합니다. ![HomePod mini](/Review-2024-HomePod-Mini.jpg) `Apple TV 4K`도 함께 사용 중인데, 이 크기의 스피커 중에서는 독보적인 것 같다고 사용할 때마다 생각하고 있습니다. 하지만, 여전히 한국어 지원을 안 해주고 대한민국에 판매하지 않는 것이 별로라고 사용할 때마다 생각 중입니다. # 장비 구매 --- 2024년에 두 번째로 잘 한 소비는 장비를 구매한 것이라고 확신할 수 있습니다. ![My Desk](/Review-2024-My-Desk.jpg) 최근 손목 건강이 상당히 악화되었고, 계속 여러 불편함들이 있어왔어서 모니터 암, 27인치 4K 모니터, 키보드, 마우스를 구매했습니다. ![My Keyboards](/Review-2024-My-Keyboards.jpg) 현재까지 상당히 만족스럽고, 너무나 잘 사용 중입니다. 왜 진작 이렇게 구성하지 않았을지 많이 손해 본 것 같은 기분이지만, 지금 잘 쓰고 있으니 괜찮습니다. # `Apple Vision Pro` 체험 --- ![Apple Vision Pro](/Review-2024-Apple-Vision-Pro.jpg) `Apple Vision Pro` 단독으로 한번, `Mac`과 연결해서 한번 사용해 보았는데 상당히 별로였습니다. 모든 게 자글자글하게 보이고, 초록 색감이 많이 섞인 보정이 잘못된 세상을 사는 기분이었습니다. 이걸 제 돈 주고 샀다면 정말 땅을 치고 후회했겠지만, 돈 주고 안 샀으니, 여기까지 말하겠습니다. # `Backend` 도전 --- `Frontend` 관련 프레임워크만 사용해 오던 제가 어쩌다가 `Backend` 구축의 필요성을 느끼고 직접 구축했습니다. 그냥 간단하게 `Express.js`와 `TypeScript`를 이용하고, `Jenkins`와 `Docker`를 통해 배포하는 방식으로 아직 사용 중입니다. 제가 봤을 때 상당히 엉망으로 구성한 것 같은데, 아직 어찌저찌 돌아간다는 게 꽤 기적 같습니다. # `Jetpack Compose` 사용 --- `Android` 앱을 개발할 때 사용하는 프레임워크인 `Jetpack Compose`를 써봤습니다. ![Android Studio With My Project](/Review-2024-Android-Studio-With-My-Project.jpg) 아직 완성하지 못한 프로젝트여서 블로그에 언급한 적은 없었지만, 웹 개발만 하던 저에게는 꽤 어렵고 복잡하게 느껴지더라고요. 그래서 아직 완성을 못 하고 그냥 비틀대고 있습니다. 어찌저찌 거의 다 만들어가고 있는데, 올해 안에 완성하지 못했다는 아쉬움이 꽤 남습니다. 내년에는 꼭 완성해 보려고요. # 잔디 결산 --- ![My Github Contribution](/Review-2024-My-Github-Contribution.png) 2024년에만 1,659개의 기여를 했고, 221일 동안 끊기지 않고 열심히 달려왔습니다. 제가 사랑하는 일을 끊임없이 사랑해 오면서 해왔다는 것만으로도 저는 만족스럽습니다. `PS`도 열심히 하고, 다른 개발도 하고, 진짜 오픈 소스 프로젝트에 기여도 해보고, 2024년에 제 잔디를 보면 정말 잘 해왔다고 생각합니다. # 마무리 --- [23년도 회고](https://blog.d3h1.com/Review-2023)를 작성하면서 제가 이렇게 작성했더라고요. > 이번 해처럼 아니 이번 해보다 더 다음 해가 더 행복해 이번 해가 생각나지 않도록 행복하게 살아보겠습니다. 이 말을 저는 잘 지킨 것 같습니다. 행복했고 2023년이 생각나지 않도록 잘 살았어요. 가끔 노력한 것에 비해서 결과가 잘 안 나와서 실망했었던 일은 있었지만, 행복했습니다. 사랑하는 일을 더 사랑하고, 증오하는 일을 더 증오할 수 있었던 2024년은 저에게는 멋진 한 해였습니다. 그래서 제가 행복할 수 있었나 봅니다. 다음 해도 더 행복하게 살아보려고 합니다. 그러기 위해서는 더 노력해야겠죠. 이제 2025년이 얼마 남지 않았는데, 2024년의 마지막 몇 시간을 더 행복하게 보내려고 합니다. 이 글을 읽으시는 여러분들도 여전히 행복하시길 바랍니다.

나도 코딩 배울까?

잡담

나도 코딩 배울까?

저번에는 매년 있던 WWE라면, 이번에는 매달 있는 WWE에 대한 답입니다. > 나도 코딩 배울까? > 나도 코딩이나 배워볼까? 이 말을 저는 매달에 한 번씩 듣는 것 같습니다. 생각보다 이 질문에 대해서 제가 할 말이 많더라고요. 생각해 볼 것도 많아서, 한 번 정리해 보려고요. 이 글도 길기 때문에 대충 정리해 보겠습니다. - 코딩은 컴퓨터에 명령을 내리는 기술로, 모든 사람이 필수는 아니지만 개발자나 특정 프로젝트에 유용합니다. - 코딩을 배우는 다양한 방법으로는 온라인 강의, 부트캠프, 대학 강의, 자기 주도 학습 등이 있으며, 자신에게 맞는 방식을 선택하는 것이 중요합니다. - AI가 코딩을 도와주더라도 창의적인 문제 해결과 협업 능력은 여전히 인간 개발자의 중요한 역할을 유지합니다. # 코딩이 뭔가요? --- 코딩은 컴퓨터에 내리는 명령입니다. 컴퓨터는 명령을 받아들이고, 그에 따라 동작합니다. 말은 쉽게 하면, 컴퓨터에 남을 거치지 않고 내가 직접적으로 명령을 시키는 겁니다. 그러니까, 코딩을 배우면 컴퓨터에 명령을 내릴 수 있습니다. 예를 들어, 컴퓨터에 "안녕!"이라고 말하고 싶다면, "안녕!"이라는 명령을 컴퓨터에 내릴 수 있습니다. 근데, 이미 누가 나 대신에 내가 "안녕!"이라고 말하고 싶을 때 말해주는데, 굳이 내가 배울 필요가 있을까요? # 어떻게 배워요? --- 방법은 정말 다양합니다. 인강 강사 고를 때처럼 여러 방법을 겪어보길 저는 추천해 드립니다. 저는 유튜브 강의나 책을 통하여 배웠는데, 안 맞는 사람도 많았어요. 저처럼 유튜브, 책 같은 걸 통해서 독학하셔도 됩니다. 인터넷 강의도 다양한 플랫폼에 존재하니까 맛보기 강의 몇 개씩 들어보시고요. 이것도 별로면 국비 지원되는 학원도 저는 추천해 드립니다. 아니면 맨땅에 해딩한다고 생각하고 목표를 정한 후에 어떤 기술을 사용하겠다고 정하고, 문법 몇 개 익히고 막힐 때마다 계속 찾아서 학습하는 것도 저는 나쁘지 않다고 생각합니다. 블로그나 계산기, 메모장 같은거 만들어도 좋습니다. 근데, 구글이나 AI가 만들어준 코드 그대로 복사 붙여 넣기 하라는 이야기는 아니에요. # `C`부터 팔까요? --- 이 질문에 대한 제 대답은 '아니요.'입니다. 코딩을 시작하려는 분들께 듣는 질문 중 제가 가장 많이 들은 질문 같습니다. `C`는 매우 복잡하고 어렵습니다. 메모리 관리, 포인터, 직접적인 하드웨어 접근 등 복잡한 개념들을 다루어야 하므로 대부분의 초보자에게 절대로 추천하지 않습니다. 그래서, 만약 처음 시작하실 거라면 저는 `Python`이나 `Java`를 정말 추천합니다. 이것들에 익숙해지면 `C`를 배울 때에도 아마 큰 어려움을 겪지 않으실 겁니다. # AI가 다 하던데 굳이 필요해요? --- AI가 다 해준다기보다는, 도와준다고 하는 게 적절합니다. AI를 활용하면 더 효율적으로 코딩을 하는 것이지 모든 걸 AI가 대신 하지는 않습니다. 지금 AI가 어떤 문제를 완벽하게 풀고, 어떤 그림을 완벽하게 그리던 프로그래머는 사라지지 않을 겁니다. AI 모델 만든 프로그래머는 그 AI 모델이 자신의 직장이거든요. 그리고 아직도 AI가 해결하지 못한 숙제가 매우 많이 남았어요. 저도 당장 사용하는 프레임워크에 급격한 변화가 생겼을 때, AI가 해결해 주지 못해서 도움도 못 받고 직접 해결했습니다. # 마무리 --- 시간이 많아서 코딩 배우는 건 저도 좋다고 생각합니다. 저는 재밌어서 좋아해요. 근데, 관련 없는 업계에 종사하고 있거나, 관련 없는 과에 재학 중이라면 업으로 삼을 생각은 하지 않으시는 게 좋을 거예요. 당장 아무 대학교 컴퓨터공학과 들어가서 실력을 오름차순 정렬하면 최댓값과 최솟값의 실력 차이가 어마어마할 겁니다. 그리고 이거 생각보다 어려워요.

MacBook 좀 사지 마세요.

잡담

MacBook 좀 사지 마세요.

이 시기에 제가 많이 듣는 질문은 '`MacBook` 살까?'입니다. 이 질문에 대해서 몇몇 친구들을 빼고 저는 '아니 사지 마.'라고 똑같이 답변해 줬습니다. 이제 이 답변을 하는 것도 지쳐서 매년 있는 WWE를 제 손과 입이 해왔던 일을 이 글이 대신 하게 할 것입니다. 글이 상당히 길기 때문에, 세 줄 요약을 해보겠습니다. - 비슷한 사양을 가진 유명 제조사의 `Windows`가 포함된 노트북보다 `MacBook` 제품군이 약 1,000,000원 정도를 더 지불해야 합니다. - `MacBook` 제품군을 사용할 때, 대부분의 사용자는 응용 프로그램을 설치하고 삭제하는 과정이 익숙하지 않거나 `Microsoft Office` 제품군 사용에 불편함을 겪는 사용자들처럼 불편함을 겪게 됩니다. - `Apple Silicon`이 탑재된 `Mac` 컴퓨터와 `macOS`를 지원하는 게임 중, 대한민국 게이머들이 즐기는 게임은 거의 없다고 봐도 무방하기 때문에 PC 게이머는 `Windows`가 설치되는 게이밍 PC를 따로 마련해야 합니다. # 가격 --- 제 개인적으로 Apple의 가격 정책에 항상 불만을 느낍니다. 제가 현재 사용 중인 `MacBook Pro 16-inch (M2 Pro, 2023)`을 3,120,300원에 구입했습니다. ![My MacBook Purchase Price](/Stop-Buying-MacBook-My-MacBook-Purchase-Price.png) 당시, 같은 화면 크기, 같은 램 용량과 SSD 용량을 가진 유명 제조사의 노트북을 선택했다면, 제가 지불한 금액보다 약 1,000,000원 저렴하게 구매할 수 있었습니다. 지금 비교하더라도 가격 차이가 비슷합니다. ![Other Laptop Purchase Price](/Stop-Buying-MacBook-Other-Laptop-Purchase-Price.png) OS도 다르고, 성능, 배터리 지속 시간도 다른데 비교 대상이 되냐고 물으실 겁니다. 하지만, 대학 생활을 하며 많이 사용할 한컴오피스 사용이 매우 불편한 `macOS`가 왜 필요하세요? 왜 iOS 프로그래밍, 영상 편집 같은 고사양 작업을 하실 것도 아니면서 이러한 고사양 작업에 도움이 되는 `Apple Silicon`이 탑재된 `Mac` 컴퓨터가 필요하신가요? `macOS`와 `Apple Silicon`이 탑재된 `Mac` 컴퓨터를 여러분은 약 1,000,000원을 더 지불하고도 모든 것이 불편하다고 생각하게 되실겁니다. 이 이야기를 이어서 해보죠. # 사용성 --- 여러분들이 지금까지 사용해 왔던 `Windows PC`나 `iPad`에서의 경험과 `Mac`에서 경험은 **완전히 다릅니다.** 응용 프로그램을 설치하고 삭제하는 방법부터 문서를 작성하거나 확인하는 과정까지 모든 것에 차이가 존재합니다. `Mac`에서 응용 프로그램을 설치하는 방법은 세 가지로 나뉩니다. `iPhone`이나 `iPad`에서처럼 `App Store`를 이용하여 설치하거나, `Windows PC`에서처럼 `.pkg` 확장자의 설치 프로그램 프랫 패키지 파일을 이용하여 설치하거나, `.dmg` 확장자의 디스크 이미지에서 응용 프로그램을 끌어다 옮겨 설치합니다. 먼저, `App Store`를 이용하여 설치하는 방법에 대해 알아보겠습니다. `iPhone`이나 `iPad`에서처럼 `App Store`를 열고, 원하는 응용 프로그램을 설치하면 됩니다. ![Installing Application From App Store](/Stop-Buying-MacBook-Installing-Application-From-App-Store.png) `.pkg` 확장자의 설치 프로그램 프랫 패키지 파일을 이용해서 설치하는 방법에 대해 알아보겠습니다. 설치할 응용 프로그램을 제작한 회사에서 배포하는 `.pkg` 확장자의 설치 프로그램 프랫 패키지 파일을 내려받습니다. ![Installing Application From Pkg File](/Stop-Buying-MacBook-Installing-Application-From-Pkg-File.png) 이 파일을 열고, 설치 과정을 따르면 응용 프로그램 설치가 완료됩니다. ![Finishing Install Application From Pkg File](/Stop-Buying-MacBook-Finishing-Install-Application-From-Pkg-File.png) `.dmg` 확장자의 디스크 이미지에서 응용 프로그램을 끌어다 옮겨 설치하는 방법에 대해 알아보겠습니다. 설치할 응용 프로그램을 제작한 회사에서 배포하는 `.dmg` 확장자의 디스크 이미지를 내려받습니다. ![Installing Application From Dmg File](/Stop-Buying-MacBook-Installing-Application-From-Dmg-File.png) 이 파일을 열고, 응용 프로그램을 `Application` 폴더에 끌어다 옮깁니다. ![Finishing Install Application From Dmg File](/Stop-Buying-MacBook-Finishing-Install-Application-From-Dmg-File.png) `App Store`에서 설치한 응용 프로그램은 `Launchpad`에서 삭제할 수 있습니다. `iPhone`이나 `iPad`에서 응용 프로그램을 지우는 것처럼 응용 프로그램을 길게 클릭하고 있으면, 삭제가 가능합니다. ![Removing Application From Launchpad](/Stop-Buying-MacBook-Removing-Application-From-Launchpad.png) `App Store` 이외에서 설치한 응용 프로그램은 별도의 응용 프로그램을 통하여 삭제하거나, 삭제 방법을 검색하면 **완전히 삭제할 수 있습니다.** 응용 프로그램 설치부터 삭제만 해도 벌써 어렵지 않나요? 이것이 `Mac`의 사용성입니다. `Mac`을 사용하면서 느낄 불편함은 또 있습니다. 문서 작업하며 사용하는 응용 프로그램 중 가장 많이 사용되는 응용 프로그램은 `Microsoft Office` 제품군입니다. 검색해 보면, `Microsoft Office` 제품군을 `Mac`에서 사용할 때 계속 충돌이 일어나 사용이 어렵다는 이야기를 쉽게 찾아볼 수 있습니다. ![Report Issues With Using Microsoft Office On macOS](/Stop-Buying-MacBook-Report-Issues-With-Using-Microsoft-Office-On-macOS.png) # 게임 --- `Apple Silicon`이 탑재된 `Mac` 컴퓨터에서 대한민국 게이머들이 즐겨하는 게임 대부분을 플레이할 수 없다고 봐도 무방합니다. [PC방 게임전문 리서치 서비스 게임트릭스](https://www.gametrics.com/)의 2024년 12월 21일 기준 게임 순위입니다. ![gametrics Game Ranking](Stop-Buying-MacBook-gametrics-Game-Ranking.png) 순위에 있는 게임 중, `Apple Silicon`이 탑재된 `Mac` 컴퓨터를 위해 빌드된 게임은 `메이플스토리`와 `메이플스토리 월드` 단 두 가지뿐이며, 이마저도 현재 오픈베타 서비스 중입니다. `리그 오브 레전드`나 `스타크래프트`도 포함되는 게 아니냐고 물으시는 분들도 계실겁니다. 이 두 게임은 `Intel 프로세서`가 탑재된 `Mac` 컴퓨터 전용으로 빌드된 게임입니다. `Apple Silicon`이 탑재된 `Mac` 컴퓨터에서 실행할 수 있는 이유는 `Rosetta 2` 덕분입니다. `Rosetta 2`는 `Intel 프로세서`가 탑재된 `Mac` 컴퓨터 전용으로 빌드된 앱을 `Apple Silicon`이 탑재된 `Mac` 컴퓨터에서 실행할 수 있도록 돕는 번역 도구입니다. 기본적으로 `Mac`에 설치되어 있는 도구가 아니며, 사용자가 `Intel 프로세서`가 탑재된 `Mac` 컴퓨터 전용으로 빌드된 앱을 처음 실행하려고 할 때, `Mac`이 인터넷에 연결된 상태라면 `Rosetta 2` 설치 과정을 진행합니다. 이 이후에는 `Rosetta 2`가 자동으로 작동합니다. 아무리 `Rosetta 2`가 `Intel 프로세서`가 탑재된 `Mac` 컴퓨터 전용으로 빌드된 앱 실행을 돕는다고 해도 `Intel 프로세서`가 탑재된 `Mac` 컴퓨터에서 실행하는 것처럼 동작하지 않을 수도 있습니다. 한국어를 다른 언어로 번역할 때, 번역기를 사용한다고 해서 항상 매끄럽고 정확한 번역이 이루어지지 않는 것과 비슷합니다. # 마무리 --- 제가 매년 있는 WWE를 쉽게 넘어갈 수 있도록 제가 `MacBook`을 추천하지 않는 이유에 대해 모두 설명했습니다. 저도 여기까지 읽을 분들은 거의 없다는 것을 잘 알고 있습니다. 만약 여기까지 읽으셨다면 정말로 `MacBook`을 구매하셔도 좋습니다. 하지만, `MacBook`을 사용하면서 겪으실 질문과 불편함에 대한 책임은 저에게 1도 존재하지 않습니다. 그러니 여기까지 읽었어도 다시 한번 `MacBook` 제품군 구매를 고려해 보세요. **여러분이 `MacBook`을 구매했을 때 정말 효율적인 사용이 가능할지, 같은 비용으로 효율적인 대안이 존재하지 않는지 제발 다시 한번 생각하세요.**

AirTag vs 갤럭시 스마트태그2 - 스마트 트래커 뭐 사지?

잡담

AirTag vs 갤럭시 스마트태그2 - 스마트 트래커 뭐 사지?

모두 나온 지 조금 된 제품들이지만 시장에서 가장 인기 있는 스마트 트래커는 아무래도 이 두 제품 같습니다. 저는 트래커 달아 놓는 것을 매우 좋아합니다. 갤럭시 스마트태그의 1세대 제품도 사서 사용하고 있었지만, 스마트태그2를 최근에 써보면서 이제야 뭔가 AirTag와 경쟁할 수 있겠다는 생각이 들어 비교 글을 한번 작성해 보려 합니다. # 디자인 --- AirTag는 동그랗고 마치 바둑돌을 떠올리게 하는 디자인입니다. 저는 공식 홈페이지에서 구입하지 않아 무료 각인 서비스를 신청하지 못해서 더욱 그래 보일 수도 있고요. ![AirTag Back](/AirTag-Vs-Galaxy-SmartTag2-What-Smart-Tracker-To-Buy-AirTag-Back.jpg) 애플 로고가 각인된 스테인리스 스틸 배터리 커버는 정말 말도 안되게 흠집이 잘나서 놀랐습니다. 차라리 이럴 거면 무광으로 만들어 주는 것이 나았을 거 같다는 생각입니다. ![AirTag Front](/AirTag-Vs-Galaxy-SmartTag2-What-Smart-Tracker-To-Buy-AirTag-Front.jpg) 갤럭시 스마트태그2는 갤럭시 스마트태그, 갤럭시 스마트태그+에서 비판을 받았던 디자인을 버리고 작고 귀여운 형태가 되었습니다. AirTag처럼 어떤 사물이 연상되지도 않고 꽤 마음에 듭니다. ![Galaxy SmartTag2 Front](/AirTag-Vs-Galaxy-SmartTag2-What-Smart-Tracker-To-Buy-Galaxy-SmartTag2-Front.jpg) 다만 상단에 있는 큰 구멍은 어딘가에 달아두기 위해 존재하는 것 같은데, 갤럭시 스마트태그의 소재가 쭉 경도가 낮은 플라스틱이어서 무언가에 달아두게 된다면 갤럭시 스마트태그2에 흠집이 많이 나는 부분은 매우 아쉽습니다. 이것은 갤럭시 스마트태그, 갤럭시 스마트태그+에서도 동일한 단점이 존재했는데, 저 부분을 사용하지 않고도 어딘가 매달아 놓을 수 있는 정품 액세서리가 있으니 그냥 넘어가도록 하겠습니다. ![Insert Keyring Galaxy SmartTag2](/AirTag-Vs-Galaxy-SmartTag2-What-Smart-Tracker-To-Buy-Insert-Keyring-Galaxy-SmartTag2.jpg) 디자인은 개인적인 취향이지만 어떠한 액세서리도 착용하지 않은 AirTag가 갤럭시 스마트태그2보다 저에게는 더 나아보입니다. ![Design Compare AirTag Without Accessory](/AirTag-Vs-Galaxy-SmartTag2-What-Smart-Tracker-To-Buy-Design-Compare-AirTag-Without-Accessory.jpg) 하지만 AirTag에 정품 가죽 키링을 장착하니 제 개인적인 취향으로는 갤럭시 스마트태그2가 저에게 더 나아보입니다. ![Design Compare AirTag With Accessory](/AirTag-Vs-Galaxy-SmartTag2-What-Smart-Tracker-To-Buy-Design-Compare-AirTag-With-Accessory.jpg) AirTag는 갤럭시 스마트태그**들**과 다르게 **별도의 액세서리가 있어야만** 무언가에 달아서 활용할 수 있습니다. 어딘가에 달아두지 않고 넣어둘 생각이여도 무조건 액세서리가 있어야만 합니다. 그 이유는 이 뒤에서 계속 하도록 하겠습니다. # 배터리 --- 두 제품 모두 CR2032 배터리를 사용합니다. 교체가 가능하며 AirTag는 1년 이상 지속된다고 하고 갤럭시 스마트태그2는 약 500일간 사용이 가능하고 `절전 모드`를 통해 700일까지 사용할 수 있다고 합니다. ![AirTag Battery Life](/AirTag-Vs-Galaxy-SmartTag2-What-Smart-Tracker-To-Buy-AirTag-Battery-Life.png) ![Galaxy SmartTag2 Battery Life](/AirTag-Vs-Galaxy-SmartTag2-What-Smart-Tracker-To-Buy-Galaxy-SmartTag2-Battery-Life.png) 다만 배터리 수명 같은 경우에도 갤럭시 스마트태그를 써오면서 300일 간다고 했던 배터리가 버튼 기능을 하루에 한 번 이상 사용해 오다 보니 300일을 못 가고 230일 정도에서 배터리 교체를 해줬던 것을 생각하면 갤럭시 스마트태그2는 공식적으로 밝힌 배터리 수명보다는 좀 덜할 것이라고 예상합니다. 반면에 AirTag는 한국에서 `나의 찾기 네트워크`를 사용할 수 없고, 갤럭시 스마트태그2와 다르게 버튼 기능도 없으니, 공식적으로 밝힌 수명보다 한국에서는 조금 더 사용할 수 있을 것 같다고 예상합니다. 하지만, 갤럭시 스마트태그2는 AirTag에 비해 배터리 수명이 길기 때문에 아무리 버튼을 사용해도, 한국에서 `나의 찾기 네트워크`를 사용하지 못해 예상 수명보다 더 오래 지속된다고 해도 갤럭시 스마트태그2의 배터리 수명이 더 오래 갈 것이라고 예상합니다. AirTag도 후속작에서는 배터리 수명이 더 늘어났으면 더 좋겠다는 생각이 있습니다. `절전 모드`를 사용하면 이러한 스마트 트래커를 사용하는 이유가 아예 없는 것과 마찬가지라고 생각하지만, 아예 선택권을 주지 않는 AirTag보다는 `절전 모드`라는 선택권을 주는 갤럭시 스마트태그2 쪽이 저는 더 마음에 들었습니다. 배터리를 다 사용하면 교체를 해주어야 하는데 배터리 교체 방식은 별도의 도구 없이 교체가 가능한 AirTag 쪽이 마음에 들었습니다. 대신 배터리 교체 난이도는 갤럭시 스마트태그2 쪽이 더 나았습니다. 갤럭시 스마트태그2는 유심 분리핀이 필요하지만 유심 분리핀을 찔러주면 한번에 나오는데 AirTag는 안그래도 이 미끄러운 스테인리스를 손으로 힘을 적당히 줘서 돌려줘야하기 때문에 개인적으로는 교체가 꽤 힘들었습니다. 게다가 배터리 교체 할 때 조심하지 않으면 AirTag에 보기 싫은 엄청난 흠집이 날 것 같아서 매우 불안합니다. ![AirTag Battery Replace](/AirTag-Vs-Galaxy-SmartTag2-What-Smart-Tracker-To-Buy-AirTag-Battery-Replace.jpg) ![Galaxy SmartTag2 Battery Replace](/AirTag-Vs-Galaxy-SmartTag2-What-Smart-Tracker-To-Buy-Galaxy-SmartTag2-Battery-Replace.jpg) # 소리 --- AirTag와 갤럭시 스마트태그2 모두 소리를 통하여서 찾을 수 있습니다. 하지만 처음 AirTag를 개봉하고 바로 소리를 울렸을 때, 저는 매우 실망했습니다. 갤럭시 스마트태그2와 굳이 바로 옆에서 비교하지 않아도 소리가 작다는 느낌을 받았기 때문에 크게 실망했던 상태여서 바로 소리 측정을 해봤습니다. ![AirTag Without Leather Key Ring Sound Level](/AirTag-Vs-Galaxy-SmartTag2-What-Smart-Tracker-To-Buy-AirTag-Without-Leather-Key-Ring-Sound-Level.jpg) 진짜 AirTag의 소리가 갤럭시 스마트태그2에 비해 작았습니다. 갤럭시 스마트태그, 갤럭시 스마트태그+는 방수방진 등급이 공식적으로 스펙에 기재가 되어있지 않았었고 갤럭시 스마트태그2는 방수방진 등급이 추가되고 크기가 작아졌는데 갤럭시 스마트태그와 소리 크기의 차이가 없다는 부분에 대해 매우 만족했던 부분이었는데 AirTag는 갤럭시 스마트태그2와 방수방진 등급도 같은데 소리가 작은 부분이 매우 실망스러웠습니다. ![Galaxy SmartTag2 Sound Level](/AirTag-Vs-Galaxy-SmartTag2-What-Smart-Tracker-To-Buy-Galaxy-SmartTag2-Sound-Level.jpg) AirTag가 갤럭시 스마트태그2가 내는 소리에 비해서 고음이기 때문에 이게 설계 시 의도인 줄 알았지만, 소리로 찾기에는 갤럭시 스마트태그2가 유리했습니다. 액세서리를 착용하기 전에는 그랬습니다. AirTag 정품 가죽 키링을 착용하고 소리를 울려보니까 뭔가 소리가 더 커진 것 같은 느낌에 다시 측정을 해보니까 진짜 소리가 더 커졌고, AirTag가 내는 소리가 고음이라 그런지 더 찾기 쉬웠습니다. ![AirTag With Leather Key Ring Sound Level](/AirTag-Vs-Galaxy-SmartTag2-What-Smart-Tracker-To-Buy-AirTag-With-Leather-Key-Ring-Sound-Level.jpg) AirTag는 무언가를 찾는 때 제품이고, 애플은 AirTag를 소리로 찾는 기능을 제공하는데, 찾을 때 사용되는 소리의 크기가 물건을 찾을 때 영향이 충분히 있을 수 있는 부분인데 대체 왜 이런 차이가 나도록 설계했는지 이해할 수 없습니다. 액세서리 착용으로 성능이 달라진다면 애초에 기본 제공을 해줬어야한다고 생각하는데 에어태그 출고가와 현재 정가에 가까운 가격에 별도로 정품 액세서리를 판매한다는 게 정말로 이해할 수 없습니다. 애초에 정품 액세서리는 AirTag보다 더 비싸게 판매했으면서 몇몇 액세서리는 이제 구할 수도 없습니다. 게다가 더 이상 AirTag 가죽 키링 제품은 판매하지도 않고 AirTag 파인우븐 키링을 판매하는데 현재 AirTag 정가보다 비싸게 판매한다니 정말 이해할 수 없습니다. 물론 서드파티 액세서리도 있지만, 개인적으로 서드파티 액세서리들은 마음에 드는 제품들도 없었고 저는 좋은 기회에 AirTag 가죽 키링을 저렴한 가격에 구입해서 사용하고 있습니다. 액세서리를 사용하고 나서야 알게 된 점이지만 서드파티 액세서리를 사용한다고 해도 똑같은 효과를 줄 수 있는지 확신할 수 없기 때문에 정말 이해가 안 됩니다. ![AirTag And AirTag FineWoven Key Ring Price](/AirTag-Vs-Galaxy-SmartTag2-What-Smart-Tracker-To-Buy-AirTag-And-AirTag-FineWoven-Key-Ring-Price.png) 갤럭시 스마트태그2는 소리로 찾을 때 재생될 소리를 정할 수 있는데, 개인적으로 모든 소리가 AirTag에 비해 듣기 싫은 소리였습니다. 또한 AirTag는 고음을 내는 데에도 상당히 예쁘다고 느껴지는 소리를 내지만 갤럭시 스마트태그2는 어떻게 하나 같이 듣기 싫은 소리를 내는지 정말 이해할 수 없습니다. 차라리 사용자가 직접 만들어 사용하는 선택지를 줬으면 좋겠지만, 아마 제품 성능의 한계로 이건 안 될 것 같아 아쉽습니다. # 위치 찾기 --- 위치는 두 가지 방법을 통해서 찾을 수 있습니다. 하나는 주변 기기가 지나가면서 연결 되면 지도에 대략적인 위치를 알려주는 것이고 하나는 UWB를 통하여 정확한 위치를 찾는 방법입니다. 지도에 대략적인 위치를 알려주는 방법은 현재 AirTag는 지원되지 않습니다. 심지어 사용자가 AirTag를 소지하고 있다고 해도 아예 **지도에 표시되지 않습니다.** 또한 AirTag와 멀어졌을 때 사용자에게 알림을 주는 기능도 **한국에서는 지원되지 않습니다.** 갤럭시 스마트태그2는 사용자가 소지하고 있을 때뿐만 아니라, 주변 갤럭시 기기를 찾는 것을 도와주는 설정을 킨 갤럭시가 지나갔을 때 지도에 대략적인 위치를 알 수 있도록 해줍니다. 또한 AirTag는 Apple 기기가 있어야만 위치가 확인이 가능하지만, 갤럭시 스마트태그는 [smartthingsfind.samsung.com](http://smartthingsfind.samsung.com)을 통해서 기기가 삼성 계정에 등록만되어 있다면 가능합니다. [find.icloud.com](http://find.icloud.com)에 AirTag만 표시가 안되는 부분은 정말 의문입니다. ![Galaxy SmartTag2 Find To Web](/AirTag-Vs-Galaxy-SmartTag2-What-Smart-Tracker-To-Buy-Galaxy-SmartTag2-Find-To-Web.png) Apple 내부 정책으로 인해 한국에서는 지도를 통한 위치를 어떤 Apple 제품이라도 확인할 수 없습니다. 아무리 생각해도 이해가 안 되는데, 이 문제를 Apple이 해결해 주었으면 좋겠습니다. UWB를 통한 정확한 위치를 찾을때에는 소리도 같이 울릴 수 있습니다. AirTag와 갤럭시 스마트태그2를 같은 위치에 숨겼습니다. 숨긴 위치까지 벽 두 개를 지나야하는데 갤럭시 스마트태그2는 소리를 울릴 수 있는 반면에 AirTag는 소리를 울릴 수 없었습니다. ![Find AirTag And Galaxy SmartTag2 Using UWB](/Find-AirTag-And-Galaxy-SmartTag2-Using-UWB-1.jpg) 숨긴 트래커들에 가까이 다가가면서 갤럭시 스마트태그2는 여전히 소리도 울릴 수 있고 신호 감도도 뜨는데, AirTag는 아무것도 뜨지 않다가 갑자기 소리 울리기가 활성화됐습니다만 하지만 여전히 어디쯤 있는지는 알 수 없었습니다. ![Find AirTag And Galaxy SmartTag2 Using UWB](/Find-AirTag-And-Galaxy-SmartTag2-Using-UWB-2.jpg) 사진은 가까워진 상태로 찍었지만 4m 정도 남았을 때, 갑자기 AirTag가 어디 있는지 정확한 방향이 뜨기 시작했고 갤럭시 스마트태그는 거리 정도만 표시됐고 여전히 정확한 방향은 알 수 없었습니다. ![Find AirTag And Galaxy SmartTag2 Using UWB](/Find-AirTag-And-Galaxy-SmartTag2-Using-UWB-3.jpg) 폰을 하나씩만 들고 가서 테스트해보고 케이스도 벗겨보고 두 개 다 들고 다니면서 위치도 바꿔보고 했지만, 결과는 같았습니다. 제가 사용하는 환경에서는 UWB를 이용해 찾는 경험은 AirTag가 사용하기 좋았고, 블루투스 신호 감도를 보고 소리를 울리는 경험은 갤럭시 스마트태그2가 사용하기 좋았습니다. # 가격 --- 현재 공식 홈페이지에서 판매 중인 정가로 비교해보겠습니다. ![AirTag Price](/AirTag-Vs-Galaxy-SmartTag2-What-Smart-Tracker-To-Buy-AirTag-Price.png) ![Galaxy SmartTag2 Price](/AirTag-Vs-Galaxy-SmartTag2-What-Smart-Tracker-To-Buy-Galaxy-SmartTag2-Price.png) AirTag가 갤럭시 스마트태그2에 비해 훨씬 비쌉니다. AirTag를 오픈마켓에서는 더 싸게 구입할 수 있지만, 갤럭시 스마트태그2는 갤럭시 스마트폰의 사은품으로 주기도 했고 미개봉 신품을 매우 싼 값에 발견할 수 있는 반면에 AirTag가 중고가 자체도 갤럭시 스마트태그2 미개봉 신품에 비해 더 비쌉니다. 여기에 아까 말했던 제대로 쓰기 위한 액세서리들까지 구매한다면 비교할 수 없을 정도로 AirTag가 훨씬 비쌉니다. ![AirTag And AirTag FineWoven Key Ring Price](/AirTag-Vs-Galaxy-SmartTag2-What-Smart-Tracker-To-Buy-AirTag-And-AirTag-FineWoven-Key-Ring-Price.png) # 마무리 --- 최종 결론은 저는 두 개 다 사용하기로 했습니다. 각각의 장단점이 존재하고 하나만 사용해서는 뭔가 부족한 느낌이라서 같이 사용하며 각각의 부족함을 채우는 용도로 사용하면 딱이더라고요. 만약 둘 중 하나만을 구매하실 생각이라면 저는 현재 사용하시는 메인 스마트폰이 갤럭시가 아니더라도 중고 갤럭시를 하나 구매하셔서 갤럭시 스마트태그2 사용하시는 것을 추천해 드립니다. 국내에서 사용하기에 갤럭시 스마트태그2가 가장 낫고 사용해 보니 대충 어디있는지 빨리 찾을 수 있는 것은 갤럭시 스마트태그2 였습니다. 배터리 교체가 좀 불편해서 그렇지 동봉된 있는 유심 교체핀만 잘 가지고 있다면 크게 문제 없을 것 같고요. AirTag는 해외 출장이 잦으신 분들이나 해외여행을 자주 나가시는 분들이 쓰시면 좋은데, UWB 정밀 추적이 안 되는 국가가 꽤 있는 것으로 알고 있으니 참고하시면 좋을 것 같습니다.

화학 챌린지 앱 출시

잡담

화학 챌린지 앱 출시

화학 챌린지가 출시 되었습니다. `Flutter`를 통해서 제작되었고 `App Store`와 `Google Play 스토어`에서 모두 이용 가능해요. [![Download On The App Store](/I-Made-Chemistry-Challenge-Download-On-The-App-Store.png)](https://apps.apple.com/us/app/화학-챌린지/id6477348331/) [![Get It On Google Play](/I-Made-Chemistry-Challenge-Get-It-On-Google-Play.png)](https://play.google.com/store/apps/details?id=com.d3h1.chemistry_challenge) # 만들어진 이유 --- 이 앱은 처음부터 `화학 I` 시간 때 생기부를 위한 발표 자료로 사용하려고 간단한 원소 기호를 맞추는 앱으로 기획했었습니다. 하지만 학기 말이다 보니까 게을러지고 놀러 다녀서 점점 미뤄지게 됐는데, 또 제대로 만들려고 하다 보니까 욕심이 생겨서 막 테마 만들어서 집어넣고 중복되는 코드를 정리하려고 코드 구조를 몇십 번이나 헤집어 놓고 해서 1~2주 정도면했을 걸 `74 Commit`씩이나 하고 거의 한 달 반 동안 개발을 했어요. 사실 저 기간 동안 `Commit` 안한 날은 놀긴 했는데, 어쨌든 제 욕심을 꽉꽉 담아 처음으로 `네이티브 앱`이라는 걸 제대로 만들어봤습니다. # 구조 --- 많은 시간을 들인 것과 별개로 구조는 별거 없습니다. `challenge_page.dart`라는 파일은 `pages` 폴더에 있는 `dart` 파일들에서 `title`, `challengeData`, `questionItem`, `answerItem`들을 선언 받습니다. 그 후 `data` 폴더에 선언 되어 있는 `list`들에서 `questionItem`와 `answerItem`을 표시 후 사용자가 화면 하단에 표시되는 `Button` 4개 중 1개를 선택했을 때 `selectAnswer` 메서드를 호출해 정답인지 아닌지 확인 후 정답이면 점수를 업데이트합니다. 그 후 `nextChallenge`를 호출해 다음 문제로 넘어갑니다. 사용된 `Item`의 개수와, `data` 폴더에 저장되어 있는 `list`의 개수가 같다면 결과창을 보여줘 문제를 맞힌 개수와 틀린 개수를 사용자에게 표시합니다. # 멍청한 실수 --- 이 앱을 배포 한지 얼마 되지 않았는데, 벌써 업데이트가 네 번 있었습니다. 다신 이런 실수를 하지 않기 위해 이 문제 또한 기록해 두려 합니다. 첫 번째 실수입니다. ![Flutter Theme](/I-Made-Chemistry-Challenge-Flutter-Theme.png) 뭔가 이상한 부분이 보이시나요? 이 `Flutter` 프로젝트에서는 `Flutter`의 `API` 중 하나인 `ThemeExtension`을 사용해 만들어졌습니다. 지금 `static ThemeData get dark`이라고 작성되어 있는 줄을 자세히 보면 `color`는 `dark`에서 받아오지만, `ThemeData.light()`를 기반으로 `copyWith` 메서드를 사용해서 라이트 모드의 속성을 적용시키고 있었습니다. 이걸 모두 `style` 속성으로 지정 해놨으니 이상한 부분을 감지하지 못한 것입니다. 다 만들고 다른 프로젝트에 저 코드를 사용하다가 이상한 점을 발견하고 즉시 수정했습니다. 두 번째 실수입니다. ![Instagram Direct Message With Friend](/I-Made-Chemistry-Challenge-Instagram-Direct-Message-With-Friend.png) 배포 후 저는 `인스타그램 스토리`에 이 프로젝트의 다운로드 링크를 올렸는데요. 여러 친구들이 다운로드하고 사용해 보고 피드백을 남겨주었는데 그중 한 친구가 마지막 난이도가 어려움으로 표기되어 있는 두 챌린지에서만 결괏값을 보여주지 않는다고 하길래 확인해 보았습니다. 확인해 보니 진짜였습니다. 급하게 다시 노트북을 켜서 디버깅을 해보니 사용된 `item`의 개수와 `list`에 기재되어 있는 `item`의 개수가 끝났음에도 불구하고 1개 차이로 넘어가지 않았고, 같은 list를 사용하고 있는 두 챌린지에서만 문제가 발생했습니다. ![ChatGPT](/I-Made-Chemistry-Challenge-ChatGPT.png) `list`를 복사해 `ChatGPT`에게 질문해보니, 아래와 같은 답변을 남겨주어서 재빠르게 수정 후 다시 배포하였습니다. # 마무리 --- 사실 이렇게까지 오래 할 것이 아니었는데, 제 게으름과 이상한 성격 때문에 이렇게까지 오래 걸린 것에 대해서는 조금 아쉽지만 결과물 자체는 제 능력 안에서 최선을 다했고, `App Store`와 `Google Play Store`에 당당히 등록되어 있다는 사실마저 만족스럽습니다. 모두 저와 같은 실수는 하지 않고 문제없는 2024년 되시길 바랍니다.

23년 회고 - 하나, 둘,

잡담

23년 회고 - 하나, 둘,

많은 곳을 갔고 많은 일을 했고 많은 것을 본 2023년이 벌써 몇 시간 남지 않았습니다. Google I/O Extended 2023 Seoul에서 들었던 것처럼 프로젝트가 끝날 때나 분기에 한 번씩 쓸까 하다 고민하다가 성인이 되기 전이나 취업하기 전 어쨌든 시간이 널널하기 전까지는 이렇게 내가 1년 동안 뭘 했나 정리하고 기록하는 용도로 적어보려고 합니다. # 노트북 패널 해 먹기 --- 그냥 대충 웹 개발용으로 사용하던 ASUS 비보북이 있었습니다. 침대에 열어둔 채로 올려두고 데스크톱을 켜고 작업하다가 창문 열려고 침대에 올라갈 때 노트북을 보지 못하고 밟았는데 패널이 완전히 맛탱이가 갔습니다. ![Broken Laptop LCD](/Review-2023-Broken-Laptop-LCD.jpg) 이 노트북은 잔고장이 너무 많아서 정보다는 스트레스를 받던 참이었는데 이참에 새로 사자하고 그냥 방치했습니다. 뭐 결국엔 새로 샀어요. 이 당시에 그리 충격적이었다거나 망했다 이런 생각이 든 건 아닌데, 기억에 남는 일 중 하나여서 넣어봤습니다. # 미완성 프로젝트 --- 사실 이번 3월쯤 `React`로 만들고 싶은 게 있어 만들고 있었습니다. 크롬의 시작 화면처럼 검색 할 수 있고 바로 가고 싶은 사이트를 고정해 놓는 그런 것을 만들고 싶다는 생각이 들어서 만들려고 마음먹었어요. ![Chrome New Tab Page](/Review-2023-Chrome-New-Tab-Page.png) 만들 때는 멋진 분의 도움을 꽤나 많이 받았어요. 그때의 저는 대충 머리에 구상해 두고 만들기 시작했습니다. 하지만 실력 이슈로 하다가 막히는 부분이 있었고, 그로 인해 멋진 분의 많은 도움을 받았어요. 아니 사실 그분이 다 하셨다고 해도 할 말 없어요. 하다가 제 능력의 부족을 느끼고 중간에 그만두었지만 그분이 작성하신 코드를 보고 많이 배웠고 제 능력이 부족하다는 것을 깨달았기 때문에 더 공부해서 다음에는 좋은 결과를 내려고 노력했습니다. 가끔 그 repository에 들어가 보기도 하고 실제로 이 블로그를 만든 것처럼 좋은 결과를 내기도 했어요. # 민증 만들기 --- 이번 해는 제가 민증을 만들 수 있게 된 나이가 된 해입니다. 민증은 생일이 있는 달의 첫 평일부터 신청이 가능합니다. 예를 들어 생일이 3월 10일이라면 4월의 첫 번째 주의 첫 번째 평일부터 신청이 가능합니다. 저는 당연히 가장 빠르게 신청하러 갔습니다. 학교와 집의 거리가 조금 있는 편이라 학교 근처 행정복지센터에서 할지 집 근처 행정복지센터에서 할지 고민했었는데 집 가는 길에 행정복지센터가 있기 때문에 학교 근처에서 했습니다. 가니까 여러 서류를 작성하고 학생증을 확인하고 지문을 찍었습니다. ![Fingerprint Scanner](/Review-2023-Fingerprint-Scanner.jpg) 이런 게 신기하지 않을 때도 됐는데 여전히 재밌고 신기합니다. 이거로 인식이 잘 안되는 친구들은 직접 잉크로 찍었다던데 저는 일단 그러지 않았고 만들고 거의 2주 좀 넘어서 받아볼 수 있었습니다. # Jekyll로 블로그 만들기 --- React로 프로젝트를 진행하다가 쓰디쓴 능력 부족을 만나고 무언가를 다시 만들고 싶었습니다. 그래서 이번엔 블로그를 만들어 봐야겠다는 생각이 들었고 찾아보다 Jekyll로 만들기로 합니다. HTML 태그 도배는 무엇보다 자신 있는 작업이거든요. 완벽하진 않지만 대충 돌아가는 멋진 블로그를 3주 만에 만들어 내긴 합니다. 어쨌든 결과물이 제 성에 차지 않아 다 갈아엎었으니 그 이야기는 뒤에서 계속하겠습니다. ![Jekyll Blog Design](/Review-2023-Jekyll-Blog-Design.png) # iPad 구매 --- 저는 원래 갤럭시 탭 S8+을 사용하고 있었습니다. 하지만 필기 중 팜 리젝션이 풀려서 화면이 알아서 막 움직인다든지 기본적인 작업만 한다고 해도 뜨거워진다든가 하는 일이 많은 이후로 꽤나 많은 불편함을 느꼈는데요. 우연한 기회로 처분하고 iPad Pro 12.9"와 다른 악세서리를 구매했고 아직까지 잘 사용 중이긴 합니다. ![iPad Pro and Accessories](/Review-2023-iPad-Pro-And-Accessories.jpg) 이것도 쓰다 보면 좀 뜨거워지는 부분이 있긴 한데 최소 필기 중 팜 리젝션이 풀려서 화면이 다른 곳으로 도망간다든가 하는 현상은 없기에 아직은 만족하면서 사용 중입니다. # Next.JS로 블로그 전환 --- Jekyll로 블로그를 만들긴 했지만, CSS도 제대로 못 해서 반응형이 이상하거나 HTML로 대충 감으면 되는 거라 진짜 대충 감았더니 파일을 열어보기가 싫더라고요. 그래서 진짜 제대로 만들 생각을 했지만 좀 편하게 만들고 싶어 검색하니 Next-Contentlayer라는 모듈을 사용해서 만든 후기가 많이 나오더라고요. 아까 말했던 미완성 프로젝트의 코드들을 많이 참고하고 셀 수도 없이 레포를 들어갔다 나오며 많은 참고를 했습니다. 결과는 지금 보시는 것처럼 약간의 문제를 제외하면 아주 잘되고 있습니다. ![Next.JS Blog Design](/Review-2023-NextJS-Blog-Design.png) 다음에 시간이 날 때에는 DB와 에디터를 구축할 생각을 하고 있습니다. 아직도 다크모드를 사용할 때 FOUC 이슈가 있는 등 사소한 문제가 있는데, DB와 에디터 구축하기 전에 고처야 할 거 같긴 합니다. # 친구들과의 여행 --- 제가 했던 가장 미친 짓으로 말할 수 있을 거 같아요. 저를 포함한 중학교 친구 세 명과 만나기로 정하고 뭐 할까 정하기로 하였는데 바다를 보러 가자는 이야기가 나왔고 그 새벽에 그날 아침 KTX를 예매해 부모님께 말씀 안 드리고 묵호로 친구들과 바다를 보러 갔습니다. ![Mukho Station](/Review-2023-Mukho-Station.JPEG) 사실 묵호 가기로 한 거 아닌데 KTX 타고 있는데 갑자기 계획을 바꿔서 묵호에서 내려서 수산시장에서 바가지도 당했습니다. 그러고 바다가 보이는 멋진 카페에 들어갔는데, 뷰가 꽤 멋졌습니다. ![Mukho Cafe](/Review-2023-Mukho-Cafe.JPEG) 그리고 그렇게 보고 싶어 하던 바닷가에도 내려가서 놀았는데, 한 번 더 하라고 하면 할 수 있을 거 같기도 한데 돈을 엄청나게 쓰긴 해서 나중에 성인 되면 한 번 더 해볼 수 있을 때 해보겠습니다. ![Mukho Beach](/Review-2023-Mukho-Beach.jpg) # Google I/O Extended 2023 Seoul --- 저의 첫 번째 컨퍼런스였습니다. 배운 것도 많았고 재미도 챙긴 상당히 인상 깊었던 컨퍼런스입니다. ![Google I/O Extended 2023 Seoul](/Review-2023-Google-IO-Extended-2023-Seoul.jpg) 너무 좋았어서 한 번 더 갈 수만 있다면 더 가고 싶었던 그런 컨퍼런스였고 가서 많은 굿즈와 상품들을 받아와서 티켓값이 아깝지 않았던 기억이 있네요. 이 내용은 블로그에 포스팅했습니다. # `Flutter` 도전기 --- `Next.JS`로 블로그를 완성 시킨 저는 이것을 무언가 확장시키고 싶었습니다. 그러다가 `Flutter`를 알게 되었고 블로그를 앱으로 만들고 싶었습니다. 10일 만에 모든 개발을 끝내고 `Google Play Store`에만 일단은 등록을 해놨습니다. 지금 꺼내보니 꽤나 엉망이네요. 이것도 시간 날 때 한번 갈아 엎어야겠습니다. ![Google Play Store](/Review-2023-Google-Play-Store.jpg) 이것을 끝내고 학교에서 포트폴리오로 사용할 프로젝트를 `Flutter`를 이용해서 만들어 봤는데 선생님도 상당히 신기해 하시는 경험을 할 수 있었습니다. # Unreal Fest 2023 Seoul --- 이건 누가 같이 가자고 해서 따라갔습니다. 빨리 오면 키링 준다고 해서 행사 시작 한참 전부터 갔습니다. ![Unreal Fest 2023 Seoul](/Review-2023-Unreal-Fest-2023-Seoul.jpg) 그래서 8번째 순서로 제가 도착했고 키링 받았고 컨퍼런스 내용도 나쁘지 않았습니다. 대신 여기에는 개발자분들도 많이 오셨지만 영상 관련 직종 종사자 분들도 많이 오셔서 제가 이해하기에는 살짝 어려운 부분의 내용도 있었지만 대부분은 어느정도 이해 가능 한 수준이였습니다. 이 내용 또한 블로그에 포스팅 해놨습니다. # 새 노트북 구매 --- 노트북의 패널이 부셔지고 한참 지나서 노트북의 필요성을 다시 느껴 구매했습니다. `Flutter`를 좀 다루다 보니까 `iOS Simulator`가 꼭 있어야 겠다는 느낌이 들어서 이번 노트북은 MacBook Pro 16(2023년) 실버 색상의 모델로 구입했습니다. 아직까지 잘 쓰고 있고 화면 하단에 균일도가 떨어지는게 보여서 오늘 Apple 여의도에 갔다 왔는데, 수리 부품이 들어오면 무상 수리를 받기로 하고 지금 집에 왔습니다. ![Macbook Pro](/Review-2023-Macbook-Pro.jpg) # 마무리 --- 글을 쓰기 시작 했을 때에는 2023년이 꽤 많이 남아 있었는데, 다 쓰고 나니 정말 얼마 남지 않았네요. 이번 해는 돌아볼 수록 작년 해가 그립지 않은 매우 행복한 해였습니다. 많은 사람을 만나고 많은 곳을 가고 '작년이 나았지'라는 생각을 작년에는 하루도 빠짐 없이 했는데 이번 해에는 한번도 그런적이 없네요. 이번 해처럼 아니 이번 해보다 더 다음 해가 더 행복해 이번 해가 생각나지 않도록 행복하게 살아보겠습니다. 다음 해에는 저와 같은 나이의 많은 친구들이 집중을 해야 할 것이 있기에, 이번 해처럼 많은 곳을 돌아다닐 수는 없을것 같지만, 다음 해에 열심히 해 그 다음 해에 이번 해처럼 열심히 돌아다니고 열심히 블로그에 포스팅 해보겠습니다. 제 추억팔이를 여기까지 읽어주신 모든 분에게 감사하고 새해에는 모두 코드가 항상 컴파일되고 버그 없는 한 해가 되셨으면 좋겠습니다.

구글의 웹 기반 IDE 프로젝트 IDX 살펴보기

후기

구글의 웹 기반 IDE 프로젝트 IDX 살펴보기

`GitHub`의 `Codespace`에 이어서 `Google`도 `프로젝트 IDX`라는 브라우저 IDE를 출시했습니다. 아직까진 Waitlist 접수를 받고 허가된 사용자에게만 푸는 것 같아요. 사실 8월에 저는 이미 살짝 써봤는데 미루다가 블로그에 쓰기 좋은 주제 같아서 가지고 왔어요. 대충 `GitHub Copilot` 같은 `Codey`라는 AI Assistant를 넣은 게 특징이라고 하네요. 웹 개발 시 Preview를 제공하는 것은 물론, `Flutter` 개발을 할 때 `Android`와 `iOS`의 `Simulator`를 모두 제공한다고 해서 기대했습니다. # 첫 화면 --- 생각보다 평범하게 생겼습니다. `Code - OSS` 기반이라 우리가 기존에 보던 `Visual Studio Code`와 꽤 비슷하게 생겼습니다. ![Main Page](/Review-Project-IDX-Main-Page.png) 여기서 어떤 프로젝트를 생성 할지 정하고 옵션을 선택하면 프로젝트가 생성됩니다. # 웹 프로젝트 생성 --- 웹 프로젝트를 생성하기로 설정하면 아래와 같은 화면이 나옵니다. ![Make Web Project Page](/Review-Project-IDX-Make-Web-Project-Page.png) 그냥 `HTML`, `CSS`, `JS` 프로젝트로 생성 할 수 있고 `Angular`, `React`, `NextJS`로도 생성 할 수 있습니다. `Vue`나 `Svelte` 프로젝트도 생성 할 수 있다고 했었는데, More options를 누르니 확인 할 수 있었습니다. ![Select Web Project Framework](/Review-Project-IDX-Select-Web-Project-Framework.png) ![Select More Web Project Framework](/Review-Project-IDX-Select-More-Web-Project-Framework.png) 그거 말고도 `JavaScript`로 생성 할 것인지 `TypeScript`로 생성 할지도 설정 할 수 있네요. 재밌는 건 `React`를 제외한 모든 `Framework`의 기본 `Language`는 `TypeScript`로 되어 있네요. ![Select Web Project Language](/Review-Project-IDX-Select-Web-Project-Language.png) 또한 실험적 기능으로 `Nix`를 킨다는 옵션이 있어 찾아보니 패키지 매니저라고 하네요. 쓰지 않는 패키지를 삭제하는 기능도 있다고 하니 한번 써봐도 나쁘지 않을 거 같긴 한데 아직 한 번도 써본 적은 없습니다. ![Nix](/Review-Project-IDX-Nix.png) 그냥 대충 보려고 `NextJS` 프로젝트를 생셩해 보았습니다. 일단 웹 Preview는 잘 뜹니다. ![Web Preview](/Review-Project-IDX-Web-Preview.png) 근데 `iOS`라고 써져 있어서 뭔가 했더니 `iOS Simulator`가 제공이 됩니다? 많이 버벅이는데 `Mac` 제품군을 사야지만 사용할 수 있었던 `iOS Simulator`가 제공된다는 자체가 꽤 멋집니다. ![iOS Simulator Preview](/Review-Project-IDX-iOS-Simulator-Preview.png) `Android Simulator`를 꺼내려고 하니 오류를 뿜으며 뜨진 않습니다. 이걸 보니 `Flutter` 프로젝트를 당장 생성해 보고 싶어졌습니다. # `Flutter` 프로젝트 생성 --- `Flutter` 프로젝트 생성할 때에는 별다른 걸 물어보진 않습니다. `Nix`를 쓸 건지 안 쓸 건지 물어보고 웹 프로젝트를 생성할 때에는 항상 `Nix`가 기본값으로 설정되어 있었는데 `Flutter` 프로젝트를 생성할 때에는 꺼져있네요. ![Make Flutter Project Page](/Review-Project-IDX-Make-Flutter-Project-Page.png) 프로젝트를 만드니 `flutter doctor`의 결과값을 보여주고 `Android`와 `iOS`의 `Simulator`를 모두 제공하고 있네요. `flutter doctor`의 결과에는 `ubuntu` 위에서 실행되는 것처럼 모이는데 어떻게 `iOS Simulator`를 돌리는지 매우 궁금합니다. ![Flutter iOS Simulator Preview](/Review-Project-IDX-Flutter-iOS-Simulator-Preview.png) `Android Simulator`에서도 Preview 해보고 싶었는데 도저히 되질 않네요. 이것도 마찬가지로 엄청나게 버벅입니다. ![Flutter Android Simulator Preview](/Review-Project-IDX-Flutter-Android-Simulator-Preview.png) # 결론 --- `Android`와 `iOS`의 `Simulator`를 모두 제공하는 부분이 매우 마음에 들지만, 너무 버벅이고 불안정한 게 흠입니다. 장점이라고 자랑하는 AI Assistant는 `Palm2` 기반이여서 꽤 별로입니다. 아직은 Beta여서 어느 정도 용서되는 부분이 있는 것은 사실이지만 정식 출시 후에도 버벅이고 AI Assistant는 별로인데 유료화한다면 얘도 `Killed by Google`에 올라가지 않을까? 라는 생각이 듭니다.

파이브가이즈 갔다 왔습니다.

후기

파이브가이즈 갔다 왔습니다.

미국 3대 버거라고 불리는 파이브가이즈, 인앤아웃, 쉑쉑버거 중 파이브가이즈가 강남에 상륙했습니다. 저도 가서 먹어보았습니다. # 메뉴 --- 가격 보고 살짝 어지러워졌는데요. ![Menu](/Review-Five-Guys-Menu.jpg) 페티 2개 들어간 햄버거가 13,400원 페티 1개 들어간 리틀 햄버거가 9,900원이였습니다. 이정도면 다른 프렌차이즈에서는 세트 시켜먹고도 남는데 쉐이크가 8,900원인거 보고 그냥 생각하지 않도록 하였습니다. # 주문 --- 저는 가장 비싼 베이컨 치즈버거에 올더웨이, 파이브가이즈 쉐이크에 솔티드카라멜, 오레오, 로투스비스코, 휘핑크림 추가해서 시켰습니다. 너무 비싸게 느껴져서 감자튀김은 시키지도 못했는데 26,300원 나왔습니다. ![Receipt](/Review-Five-Guys-Receipt.jpg) 특이한 점은 '손님'이라는 단어 대신에 'Guest'라고 하더라고요. 또한 번호표가 99번이 넘어가면 1부터 다시 올라가는 부분도 꽤 인상 깊었습니다. # 먹기 --- 앉을 자리 없어서 한참 해메다가 6명 자리에 한 커플이 앉아 있길래 옆에 양해 구하고 앉았고요. 나온 햄버거는 아래와 같습니다. 제가 사진 찍는데 재주가 없어서 이상하게 나왔네요. ![Hamburger](/Review-Five-Guys-Hamburger.jpg) 맛은 건강에 안 좋은맛인 거 같았습니다. 뭐 딱 봐도 생긴 게 건강에 안 좋을 거 같으니 아실 거 같고요. 그 외 이상하게 생각한 부분은 맛이 난해했어요. 제가 올더웨이로 시켜서 그런 건지는 모르겠지만 맛이 뭐랄까 다 섞여서 밥이 없는 죽 먹는 느낌. 대신에 쉐이크는 진짜 맛있었어요. 제가 먹어본 쉐이크 중에 제일 맛있었습니다. 뭐 스니커즈 맛이 난다고 했던 거 같은데 그건 잘 모르겠고요. # 마무리 --- 저는 30분 정도밖에 대기하지 않았으니 비교적 짧게 기다렸는데, 비싼 가격과 약간 난해한 맛은 이해할 수 없었습니다. 만약 쉐이크를 한 번 더 먹으러 갈 수 있다면 그건 가고 싶네요. 햄버거 말고요.

Unreal Fest 2023 Seoul 갔다 왔습니다.

후기

Unreal Fest 2023 Seoul 갔다 왔습니다.

코로나19 여파로 오프라인 세션이 열리지 않았던 Unreal Fest가 최근 열렸는데요. 저는 8월 29에 열리는 DAY1 공통 오프라인 행사에 다녀왔습니다. 제 생에 2번째 개발자 행사입니다. Google I/O Extended 2023 Seoul에서는 마실 거도 줬는데 여긴 뭐 주는 게 아무것도 없더라고요. 티켓값도 더 비싸면서... 대신에 영어로 진행되는 세션은 동시통역이 되어서 좋았습니다. 입장 전에 통역 리시버 챙겨줬어요. ![Interpretation Receiver](/Review-Unreal-Fest-2023-Seoul-Interpretation-Receiver.jpg) 아 그리고 선착순 300명 안에 들으면 언리얼 야광 키링을 준다고 해서 9시 30분 입장인데 8시 23분부터 가서 기다리고 있었습니다. ![Entrance Time Shot](/Review-Unreal-Fest-2023-Seoul-Entrance-Time-Shot.jpg) 그리고 체험 부스도 있었는데 저는 대충 체험 해보고 말았는데 이게 직원분들이 아니라 그냥 대본 읽는 알바생분들이라서 딱히 의미 있는 거 같지 않았습니다. 그냥 대충 신제품 시연하는 곳이었어요. 그리고 10시 30분이 되어서 행사 시작을 했습니다. # 오프닝 환영사 --- 처음에 에픽 게임즈 코리아의 박성철 대표님께서 오프닝 환영사를 하셨습니다. 처음에는 Unreal Fest는 Unreal Fest가 아니었고 Unreal Summit이었고 이것을 2009년에 언리얼 코리아에서 제일 먼저 시작해서 역수입이 되었다고 하셨어요. 언리얼 엔진은 게임뿐만 아니라 건축, 영화, 드라마 같은 곳에서도 업계를 따르지 않고 많이 사용된다고 하셨습니다. 또한 이번 오프라인 행사 티켓이 1주일 만에 마감되었다고 하더라고요. ![Opening Remarks](/Review-Unreal-Fest-2023-Seoul-Opening-Remarks.jpg) # 기조연설 --- 이 환영사 이후 에픽 게임즈의 CEO, Tim Sweeney님이 나와서 기조연설을 하였습니다. 끝까지 영어로 진행되었는데 이게 초반에 뭐가 문제였는지 통역 리시버가 작동이 안 되더라고요. 어쨌든 내용은 언리얼 엔진 5의 업그레이드는 게임을 만드는 데 많은 도움을 준다는 것이었고요. 또한 애플, 구글과의 분쟁에 대한 이야기도 있었는데요. 열심히 독점 수수료를 제거하기 위해 노력 중이라고 합니다. 또한 포트나이트에서 많은 발전이 있었다고도 언급하였습니다. 유저들이 콘텐츠를 만들어 배포하고 있고 유저들이 이것으로 수익을 창출 할 수도 있다는데요. 또한 포트나이트에서 콘텐츠를 만들 수 있는 포트나이트 언리얼 에디터라는 것을 만들었고 이곳에서 언리얼 엔진의 거의 모든 기능을 사용할 수 있다고 합니다. 에픽에서는 메타버스에서 웹 같은 표준을 만들고 싶다고 합니다. 이곳에서 경제활동을 하면 플렛폼을 따지지 않고 동기화 되는 표준을 만들고 있다고 하는데요. 대체 왜 메타버스 내에서 경제활동을 해야 하는지는 납득하지는 못하였지만 어쨌든 그런 내용이 있었습니다. ![Tim Sweeney](/Review-Unreal-Fest-2023-Seoul-Tim-Sweeney.jpg) # 언리얼 엔진 5.3 주요 업데이트 --- 오프닝 환영사와 기조연설 후 바로 언리얼 엔진의 5.3 주요 업데이트 내용으로 넘어갔습니다. 나나이트와 루멘이 엄청난 개선이 이루어졌다고 합니다. 또한 모바일에서도 레이트레이싱이 가능하게 되었고요. ![Review-Unreal-Fest-2023-Seoul-Nanite-Lumen](/Review-Unreal-Fest-2023-Seoul-Nanite-Lumen.jpg) 또한 건축 산업에서는 렌더링을 자연스럽게 하는 것뿐만 아니라 정확하게 하는 것이 중요해 직교 렌더링이라는 실험적 기능이 추가되었다고 합니다. 스파스 볼륨 텍스쳐가 추가되어 불이나 연기, 구름 같은 볼륨 데이터를 추가할 수 있게 되었다고 하고요. 캐릭터와 애니메이션도 AI를 이용해 더욱 자연스럽게 되었고 헤어 같은 것도 성능 개선이 있다고 합니다. 또한 업스케일링 기능이 있어서 고해상도 지원에도 유리하다고 하네요. ![Character & Animation Improvements](/Review-Unreal-Fest-2023-Seoul-Character-Animation-Improvements.jpg) 멀티 프로세스 쿡이 추가되며 개발자가 콘텐츠를 플랫폼별 포맷으로 변환할 때 추가 CPU 및 메모리 리소스를 활용할 수 있어서 로컬에서 시간 단축이 많이 된다고 합니다. ![Development Process Improvements](/Review-Unreal-Fest-2023-Seoul-Development-Process-Improvements.jpg) XR 기기가 점차 늘어나면서 XR 지원에 대한 중요성도 강조하며 XR 플랫폼에서도 사용할 수 있는 유용한 기능이 많다고 하는데요. 사용자의 시선을 추적해 사용자가 보고 있는 부분만 렌더링한다던가 이런 부분이 가능하다고 하고요. 또한 나나이트를 위한 단일 패스 스테레오 렌더링이 추가되는 등 다양한 개선이 있었다고 합니다. ![XR](/Review-Unreal-Fest-2023-Seoul-XR.jpg) 아까 언급한 것처럼 모바일에서 레이트레이싱이 가능한데 안드로이드에서만 된다고 하고 Xcode를 이용해서 iOS 시뮬레이터를 지원해 준다는데 이게 왜 지금 되는지 이해를 할 수 없습니다. ![Mobile](/Review-Unreal-Fest-2023-Seoul-Mobile.jpg) 이 외에도 모델링 툴의 개선, 범용 UI 개선 등 많은 내용이 있었지만 제가 제대로 이해하지 못해서 이 내용은 여기까지 하겠습니다. ![Unreal Engine](/Review-Unreal-Fest-2023-Seoul-Unreal-Engine-5.3-Update.jpg) # 패널 토의: 인터랙티브 3D 콘텐츠 제작의 혁신과 미래 --- 이 세션에서는 에픽 게임즈의 Pat Tubach님, 메타버스엔터테인먼트의 강성구님, 스마일게이트의 김진아님, 더쎈의 박영수님, 자이언트스탭의 이지철님이 나오셔서 간단한 토의를 하셨습니다. ![Panel Discussion](/Review-Unreal-Fest-2023-Seoul-Panel-Discussion.jpg) 이 세션에서는 엔터테이먼트 시장과 게임 시장의 파이프라인은 꽤 다르다, 언리얼 엔진이 이제 자동차 같은 구매 경험을 높이고 있다, 이펙트 부분에서 언리얼 엔진을 사용하기 참 좋다, 군중을 만들 때 언리얼 엔진을 사용하면 정말 효과적이다 등의 그냥 대충 언리얼 엔진이 사용되는 산업에서 언리얼 엔진의 장점을 쭉 들은 느낌이어서 이건 자세히 정리하진 않겠습니다. # 언리얼 엔진 모바일 게임 개발: 렌더링과 워크플로 --- 25년동안 언리얼 엔진 1부터 5까지 많은 부분에서 관여하셨던 에픽 게임즈 코리아의 Jack Porter님의 발표가 있었습니다. ![Jack Porter](/Review-Unreal-Fest-2023-Seoul-Jack-Porter.jpg) 언리얼 엔진은 크로스 플랫폼 개발과 확장성 향상, 호환성 개선, 메모리 사용량을 줄이는 여러 최적화 작업을 진행 중이라고 합니다. ![Unreal Engine Mobile Developmnet Focus](/Review-Unreal-Fest-2023-Seoul-Unreal-Engine-Mobile-Development-Focus.jpg) 앞에서 살짝 언급됐던 것처럼 iOS 앱을 Mac에서 시뮬레이팅 가능하다고 합니다. 대신에 Apple Silicon 칩이 탑재된 제품에서만요. ![iOS Simulator](/Review-Unreal-Fest-2023-Seoul-iOS-Simulator.jpg) 또한 Apple이 최근 더 많은 가상 램을 사용할 수 있게 되면서 그것에 대한 지원도 추가 되었다고 합니다. ![iOS Memory Entitlements](/Review-Unreal-Fest-2023-Seoul-iOS-Memory-Entitlements.jpg) 그리고 iOS 앱 빌드를 할 수 있는 여러 방법이 소개되었는데요. 이건 너무 머리 아파서 대충 사진만 첨부하겠습니다. 가장 좋은 방법은 그냥 Apple이 Xcode를 거치지 않고 앱 빌드를 할 수 있게 해줬으면 좋겠어요. ![iOS PC Workflows A, B, C](/Review-Unreal-Fest-2023-Seoul-iOS-PC-Workflows-ABC.jpg) ![iOS PC Workflows B + C](/Review-Unreal-Fest-2023-Seoul-iOS-PC-Workflows-B+C.jpg) 또한 Xcode에서 iOS 앱 디버깅 하기가 더 쉬워졌다고 하고요. ![iOS Easier Debug](/Review-Unreal-Fest-2023-Seoul-iOS-Easier-Debug.jpg) ![iOS Easier Debug In Windows](/Review-Unreal-Fest-2023-Seoul-iOS-Easier-Debug-In-Windows.jpg) 다음부터는 안드로이드 관련 이야기가 나왔습니다. 먼저 안드로이드 SDK와 AGDE가 업데이트 되었다고 합니다. ![Android SDK And AGDE Updates](/Review-Unreal-Fest-2023-Seoul-Android-SDK-And-AGDE-Updates.jpg) 또한 구글 플레이 결제 라이브러리도 업데이트 되었고요. ![Google Play Billing Library Update](/Review-Unreal-Fest-2023-Seoul-Google-Play-Billing-Library-Update.jpg) 스토리지 범위 지정과 AFS에 관한 이야기도 있었습니다. ![Android Scoped Storage And AFS 1](/Review-Unreal-Fest-2023-Seoul-Android-Scoped-Storage-And-AFS-1.jpg) ![Android Scoped Storage And AFS 2](/Review-Unreal-Fest-2023-Seoul-Android-Scoped-Storage-And-AFS-2.jpg) ![Android Scoped Storage And AFS 3](/Review-Unreal-Fest-2023-Seoul-Android-Scoped-Storage-And-AFS-3.jpg) 짜잘한 기타 업데이트 내용도 있었으니 확인해보시고요. ![Android Miscellaneous Updates](/Review-Unreal-Fest-2023-Seoul-Android-Miscellaneous-Updates.jpg) 아래에는 여러가지 안드로이드 개발자들을 위한 팁도 소개가 되어있습니다. ![Android Developer Tip 1](/Review-Unreal-Fest-2023-Seoul-Android-Developer-Tip-1.jpg) ![Android Developer Tip 2](/Review-Unreal-Fest-2023-Seoul-Android-Developer-Tip-2.jpg) ![Android Developer Tip 3](/Review-Unreal-Fest-2023-Seoul-Android-Developer-Tip-3.jpg) 모바일 렌더링 업데이트를 언급하며 가장 먼저 PC와 모바일의 렌더링 차이에 대해 언급을 하였습니다. ![Desktop Mobile Rendering Differences](/Review-Unreal-Fest-2023-Seoul-Desktop-Mobile-Rendering-Differences.jpg) 셰이더 파이프라인 캐시와 PSO 캐시의 문제점을 언급했고 PSO 캐시의 개선점도 말했습니다. ![Shader Pipline Cache PSO Caching](/Review-Unreal-Fest-2023-Seoul-Shader-Pipline-Cache-PSO-Caching.jpg) ![Runtime PSO caching](/Review-Unreal-Fest-2023-Seoul-Runtime-PSO-Caching.jpg) 퀄리티 부분의 자잘한 개선점도 언급되었습니다. ![Miscellaneous Quality Improvements](/Review-Unreal-Fest-2023-Seoul-Miscellaneous-Quality-Improvements.jpg) 또한 안드로이드 레이트레이싱을 위한 요구사항도 공개되었고요. ![Future Android Ray Rracing](/Review-Unreal-Fest-2023-Seoul-Future-Android-Ray-Rracing.jpg) 이 세션에서는 안드로이드 기기에서 언리얼 엔진을 사용해 레이트레이싱을 한다는 부분이 가장 흥미로웠습니다. # 물리 기반 세컨더리 애니메이션: 생동감 있는 캐릭터 구현하기 --- 에픽 게임즈 코리아의 강정훈님의 발표가 있었는데요. 먼저 피직스 에셋에 대한 내용이였습니다. ![Physics Assets 1](/Review-Unreal-Fest-2023-Seoul-Physics-Assets-1.jpg) ![Physics Assets 2](/Review-Unreal-Fest-2023-Seoul-Physics-Assets-2.jpg) ![Physics Assets 3](/Review-Unreal-Fest-2023-Seoul-Physics-Assets-3.jpg) ![Physics Assets 4](/Review-Unreal-Fest-2023-Seoul-Physics-Assets-4.jpg) ![Physics Assets 5](/Review-Unreal-Fest-2023-Seoul-Physics-Assets-5.jpg) ![Physics Assets 6](/Review-Unreal-Fest-2023-Seoul-Physics-Assets-6.jpg) ![Physics Assets 7](/Review-Unreal-Fest-2023-Seoul-Physics-Assets-7.jpg) ![Physics Assets 8](/Review-Unreal-Fest-2023-Seoul-Physics-Assets-8.jpg) ![Physics Assets 9](/Review-Unreal-Fest-2023-Seoul-Physics-Assets-9.jpg) ![Physics Assets 10](/Review-Unreal-Fest-2023-Seoul-Physics-Assets-10.jpg) 그 후 리지드 바디에 관한 내용이 발표되었고요. ![Rigid Body 1](/Review-Unreal-Fest-2023-Seoul-Rigid-Body-1.jpg) ![Rigid Body 2](/Review-Unreal-Fest-2023-Seoul-Rigid-Body-2.jpg) ![Rigid Body 3](/Review-Unreal-Fest-2023-Seoul-Rigid-Body-3.jpg) ![Rigid Body 4](/Review-Unreal-Fest-2023-Seoul-Rigid-Body-4.jpg) 또한 클로스용 모델링 가이드 등 많은 내용들이 발표되었습니다. ![Cloth Modeling Guide](/Review-Unreal-Fest-2023-Seoul-Cloth-Modeling-Guide-1.jpg) ![Cloth Modeling Guide](/Review-Unreal-Fest-2023-Seoul-Cloth-Modeling-Guide-2.jpg) # 메타휴먼 애니메이터: 손쉽게 제작하는 고퀄리티 페이셜 애니메이션 --- 에픽 게임즈 코리아의 박성재님께서 본인이 직접 메타휴먼 애니메이터를 생성하고 사용하는 모습을 보여주셨는데요. 메타휴먼 애니메이터는 iPhone과 PC만을 이용해 몇분만에 만드는 혁신적인 기능입니다. ![Introducing MetaHuman Animator](/Review-Unreal-Fest-2023-Seoul-Introducting-MetaHuman-Animator.jpg) 필요한 사항은 아래와 같습니다. iPhone 12 이상인 이유는 iPhone 12 이상의 AP가 가장 메타휴먼 애니메이터를 제작하는데 가장 최소 사양이라고 생각한다고 한다네요. ![MetaHuman Animator Requirements](/Review-Unreal-Fest-2023-Seoul-MetaHuman-Animator-Requirements.jpg) 다양한 방식으로 캡처가 가능하다고 합니다. ![MetaHuman Animator Capture Methods](/Review-Unreal-Fest-2023-Seoul-MetaHuman-Animator-Capture-Methods.jpg) 또한 디바이스별 뎁스 비교를 에픽 게임즈에서 직접한 자료도 제시해주셨습니다. iPhone 12와 iPhone 14의 차이도 상당하네요. ![Comparing Depth by MetaHuman Animator Device](/Review-Unreal-Fest-2023-Seoul-Comparing-Depth-By-MetaHuman-Animator-Device.jpg) 캡처 가이드도 제시를 해주셨습니다. 어떤 자세를 취해야 하는지, 어떤 상황이여야하는지 구체적인 상황을 제시해 주셨습니다. ![MetaHuman Animator Capture Guide 1](/Review-Unreal-Fest-2023-Seoul-MetaHuman-Animator-Capture-Guide-1.jpg) ![MetaHuman Animator Capture Guide 2](/Review-Unreal-Fest-2023-Seoul-MetaHuman-Animator-Capture-Guide-2.jpg) ![MetaHuman Animator Capture Guide 3](/Review-Unreal-Fest-2023-Seoul-MetaHuman-Animator-Capture-Guide-3.jpg) iPhone으로 캡처시의 워크플로도 알아볼 수 있었습니다. ![MetaHuman Animator iPhone Capture Workflows](/Review-Unreal-Fest-2023-Seoul-MetaHuman-Animator-iPhone-Capture-Workflows.jpg) 이 외에도 조금 더 자세한 내용이 있었지만, 현장에서 웃음을 자아내게 하는 어떠한 상황이 있었기에 이건 관심 있는 분들이 만약 다시 보기가 공개된다면 시청하시는 것을 추천해 드립니다. # PCG: 더 넓게, 더 퀄리티 노게, 하지만 말도 안되게 빠르게 --- 이거는 행사장에 있는 액티비티 하느려고 못들었습니다. 이 액티비티에 대해서도 꽤 할 말이 많아서 바로 다음에 할 겁니다. # 여담 --- 글 처음에서 말했던 것처럼 액티비티가 행사에 있었는데요. 그냥 언리얼 엔진의 새로운 기능을 체험해보고 도장을 받으면 룰렛을 통해서 경품을 받을 수 있습니다. 하지만 사람이 너무 많았고 이것을 체험해보려면 점심을 먹지 말던가 세션 하나를 듣지 못하는 것이나 마찬가지였습니다. ![Peoples](/Review-Unreal-Fest-2023-Seoul-Peoples.jpg) 마지막 시간이 되서야 세션당 줄을 만들었고 그제서야 제가 도장을 받을 수 있었습니다. 먼저 온 사람한테 도장을 그냥 주던가 아니면 처음부터 이렇게 줄을 서게 했으면 좋지 않았을까라는 생각이 들었어요. 이렇게 줄서는 방식이 바뀌기 전까지는 뒤에 앉으신 분들이 뛰어가야 참여가 가능했거든요. 저는 맨 앞에 앉아서 불리한 부분도 있었고요. 이렇게 바꾸고 남은 경품은 스타벅스 5000원 상품권과 선착순 300명 안에 들면 주는 키링과 스티커만 남았었어요. 많은 경품과 동일한 기회가 주어졌으면 좋지 않았을까라는 생각이 들었습니다. # 마무리 --- 제 생에 2번째 개발자 행사였던 Unreal Fest 2023 Seoul에 갔다 온 내용을 정리해 보았습니다. 이번에는 보조배터리와 메모할 기기를 가지고 가서 그런지 정리하기가 매우 수월해서 기분이 좋네요. 또한 한 달 뒤 발표자가 동의한 세션에 한해서 다시 보기가 제공된다고 합니다. 긴 글 읽어주셔서 감사합니다.

Next.JS 블로그 사이트맵 만들기

개발

Next.JS 블로그 사이트맵 만들기

`Next.JS`로 블로그를 개편한 지도 거의 2개월이 되어가는데요. 검색했을 때 블로그가 나오게 하려면 웹마스터 도구에 등록해야 합니다. 하지만 글을 작성할 때마다 글의 주소를 일일이 등록해 주어야 합니다. 하지만 사이트맵이 있다면, 그럴 필요가 없는데요. 만들어 봅시다. 본 내용은 `next-contentlayer`를 사용한 프로젝트를 기준으로 합니다. # 정적 사이트맵 생성을 위한 `sitemap.js` 만들기 --- 프로젝트 어딘가 본인이 원하는 곳에 `sitemap.js`를 만들어 주세요. 파일에 모듈을 임포트해 줍니다. ```javascript const fs = require("fs"); const path = require("path"); ``` 이 모듈은 `/posts` 폴더 안에 있는 블로그 글 파일의 이름을 불러오기 위한 것입니다. `/posts` 폴더 안에 있는 파일들의 이름을 불러오도록 해보겠습니다. ```javascript const getFileNames = () => { const postsDirectory = path.join(process.cwd(), "posts"); return fs.readdirSync(postsDirectory); }; ``` `getFileNames`라는 함수에 `/posts` 폴더 안에 있는 파일들의 이름을 불러오도록 하였습니다. 사이트맵은 날짜와 시간도 필요로 하므로 블로그 글 파일에서 프론트메터에서 불러오도록 해보겠습니다. ```javascript const extractFrontmatter = (fileContent) => { const frontmatter = {}; const lines = fileContent.split("\n"); for (const line of lines) { const match = line.match(/^(\w+):\s?(.+)/); if (match) { const key = match[1].toLowerCase(); if (!frontmatter.hasOwnProperty(key)) { frontmatter[key] = match[2]; } } } return frontmatter; }; ``` `extractFrontmatter`라는 함수에 블로그 파일에서 `Date`라는 프론트메터 안에 있는 값을 추출합니다. ```javascript const main = () => { const filenames = getFileNames(); const urls = filenames.map((filename) => { const filePath = path.join(process.cwd(), "posts", filename); const fileContent = fs.readFileSync(filePath, "utf8"); const frontmatter = extractFrontmatter(fileContent); const url = `https://blogurl.com/${filename.replace(".md", "")}`; const lastmod = frontmatter.date || ""; return { url, lastmod }; }); const sitemap = ` <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> <url> <loc>https://blogurl.com/</loc> </url> ${urls .map(({ url, lastmod }) => { return ` <url> <loc>${url}</loc> <lastmod>${lastmod}</lastmod> </url> `; }) .join("")} </urlset> `; fs.writeFileSync("public/sitemap.xml", sitemap); }; main(); ``` 또한 메인 블로그 페이지와 글들의 우선순위를 지정하고 사이트 변경 횟수를 지정해줍니다. ```javascript const main = () => { const filenames = getFileNames(); const urls = filenames.map((filename) => { const filePath = path.join(process.cwd(), "posts", filename); const fileContent = fs.readFileSync(filePath, "utf8"); const frontmatter = extractFrontmatter(fileContent); const url = `https://blogurl.com/${filename.replace(".md", "")}`; const lastmod = frontmatter.date || ""; return { url, lastmod }; }); const sitemap = ` <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> <url> <loc>https://blogurl.com/</loc> <changefreq>always</changefreq> <priority>1.00</priority> </url> ${urls .map(({ url, lastmod }) => { return ` <url> <loc>${url}</loc> <lastmod>${lastmod}</lastmod> <changefreq>always</changefreq> <priority>0.80</priority> </url> `; }) .join("")} </urlset> `; fs.writeFileSync("public/sitemap.xml", sitemap); }; main(); ``` 이제 위에서 정의한 `getFileNames`를 이용해서 파일 이름을 가져온 후 `filenames`에 저장하여 블로그 주소 뒤에 추가합니다. `extractFrontmatter`를 이용하여 프론트매터를 가져온 후 `lastmod`에 저장합니다. 이제 이 정보들을 사용하여서 `XML` 형식의 `sitemap`을 생성해서 `/public`에 저장합니다. 완성된 `sitemap.js`은 아래와 같습니다. ```javascript const fs = require("fs"); const path = require("path"); const getFileNames = () => { const postsDirectory = path.join(process.cwd(), "posts"); return fs.readdirSync(postsDirectory); }; const extractFrontmatter = (fileContent) => { const frontmatter = {}; const lines = fileContent.split("\n"); for (const line of lines) { const match = line.match(/^(\w+):\s?(.+)/); if (match) { const key = match[1].toLowerCase(); if (!frontmatter.hasOwnProperty(key)) { frontmatter[key] = match[2]; } } } return frontmatter; }; const main = () => { const filenames = getFileNames(); const urls = filenames.map((filename) => { const filePath = path.join(process.cwd(), "posts", filename); const fileContent = fs.readFileSync(filePath, "utf8"); const frontmatter = extractFrontmatter(fileContent); const url = `https://blogurl.com/${filename.replace(".md", "")}`; const lastmod = frontmatter.date || ""; return { url, lastmod }; }); const sitemap = ` <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> <url> <loc>https://blogurl.com/</loc> <changefreq>always</changefreq> <priority>1.00</priority> </url> ${urls .map(({ url, lastmod }) => { return ` <url> <loc>${url}</loc> <lastmod>${lastmod}</lastmod> <changefreq>always</changefreq> <priority>0.80</priority> </url> `; }) .join("")} </urlset> `; fs.writeFileSync("public/sitemap.xml", sitemap); }; main(); ``` # 빌드 시 `sitemap.xml` 생성되게 하기 --- 완성된 `sitemap.js`를 빌드 시 마다 실행되게 해야 하는데요. `package.json`을 아래와 같이 수정해 줍니다. ```json { "name": "project-name", "version": "0.1.0", "private": true, "scripts": { "dev": "next dev", "build": "next build", "start": "next start", "lint": "next lint", "postbuild": "node sitemap.js" }, ... } ``` 이제 빌드 시 `sitemap.js`가 실행되어 `/public` 폴더 안에 `sitemap.xml`이 생성되게 됩니다.

Termius 학생 인증 받기

개발

Termius 학생 인증 받기

`Termius`는 `SSH` 접근을 돕는 아주 유용한 도구입니다. 깔끔하고 사용하기 편해 아주 인기가 높죠. 하지만 월 $10짜리 Pro 요금제를 구독을 하지 않는다면 `Autocomplete`, `SFTP`, `Environment Variables`와 같은 자동화를 돕는 도구나 `SOCKS Proxy`, `HTTP Proxy` 같은 터널링 기능을 사용할 수 없습니다. 조금 웃긴 게, 최초 가입 시 이 요금제를 2주 정도 맛보기로 보여줍니다. 결제 수단 등록 안 하면 이 모든 기능을 빼앗아버리고요. 하지만 학생이라면 `GitHub Student Developer Pack`으로 인증받게 된다면 월 $10짜리 Pro 요금제가 주어지게 됩니다. 바로 받아봅시다. # 받기 --- 이번에는 놀랍도록 간단합니다. [account.termius.com/student](https://account.termius.com/student)에 접속합니다. 접속하면 `Termius` 계정으로 로그인하라고 할 수도 있는데, 로그인해 줍니다. 로그인하면 아래와 같은 화면이 표시될겁니다. ![Link GitHub](/How-To-Get-Termius-For-Students-Premium-Link-GitHub.png) 저 화면에서 `Link your GitHub account` 버튼을 누르면 인증이 완료됩니다. 만약 시도중인 브라우저에서 한번도 `GitHub`에 로그인한 적 없다면 `GitHub`에 로그인 해달라고 할 수 있는데, 로그인해주면 됩니다. ![After Link GitHub](/How-To-Get-Termius-For-Students-Premium-After-Link-GitHub.png) # 사용하기 --- 이제 `Autocomplete`, `Environment Variables` 등 다양한 기능을 사용할 수 있게 되었습니다. `SSH`를 사용할 Host들을 추가 후 사용하면 되겠습니다. # 마무리 --- `GitHub Student Developer Pack`을 이용해서 `Termius`에서 학생 인증을 받아보았습니다. 여기까지 `GitHub Student Developer Pack`을 이용한 혜택을 소개해 보았습니다.

JetBrains 무료 교육용 라이선스 받기

개발

JetBrains 무료 교육용 라이선스 받기

저번에는 `GitHub Student Developer Pack`을 받아봤습니다. 이제 이것을 이용해서 `JetBrains IDE`를 `무료 교육용 라이선스`를 이용해 사용할 수 있는데요. 바로 받아봅시다. # 받기 --- `JetBrains 무료 교육용 라이선스`를 받기 위해 먼저 [www.jetbrains.com/shop/eform/students/](https://www.jetbrains.com/shop/eform/students/)에 들어가면 아래와 같이 여러 방법으로 학생임을 인증할 수 있는 방법이 나와있습니다. ![JetBrains Product Pack for Students School Email Submit](/How-To-Get-JetBrains-Product-Pack-For-Students-School-Email-Submit.png) 이 네 가지 방법 중에서 저희는 `GitHub Student Developer Pack`을 받았으니 쉽고 간편하게 인증이 가능한 `GitHub`를 선택해 봅니다. ![JetBrains Product Pack for Students GitHub Authorize](/How-To-Get-JetBrains-Product-Pack-For-Students-GitHub-Authorize.png) `GitHub로 인증` 버튼을 누릅니다. 이때 라이선스 발급을 시도 중인 브라우저에서 `GitHub`에 로그인이 되어있다면 `GitHub`에 로그인해달라고 하지 않지만, `GitHub`에 로그인이 되어 있지 않다면 로그인해달라고 할 수도 있습니다. 그 후 채워져 있는 내용이 맞는지 확인하고 동의해야 할 것들에 동의하면 발급이 완료됩니다. ![JetBrains Product Pack for Students GitHub Submit](/How-To-Get-JetBrains-Product-Pack-For-Students-GitHub-Submit.png) # 사용하기 --- 모든 과정이 끝났다면 아래와 같은 화면이 표시됩니다. ![JetBrains Product Pack for Students License](/How-To-Get-JetBrains-Product-Pack-For-Students-Licence.png) 이제 원하는 `JetBrains IDE`를 다운로드해 사용하면 됩니다. # 마무리 --- `GitHub Student Developer Pack`을 이용해서 `JetBrains 무료 교육용 라이선스`를 발급받아보았습니다. 다음에도 제가 받고 있는 `GitHub Student Developer Pack`을 이용한 혜택을 소개해 보겠습니다.

GitHub Student Developer Pack 받기

개발

GitHub Student Developer Pack 받기

만약 학생(중학생, 고등학생, 대학생 등)이거나 교직원이라면 `GitHub Student Developer Pack`을 받을 수 있습니다. 이것을 받게되면 일단 `GitHub` Profile에 Pro Label이 추가가 되며, `GitHub Copilot`, `JetBrains Licenses`를 얻는 등 다양한 혜택이 주어집니다. 바로 받아봅시다. # 받기 --- `GitHub Student Developer Pack`을 받으려면 우선 [education.github.com/students](https://education.github.com/discount_requests/application)에 접속합니다. 그 후 Teacher인지, Student인지 선택합니다. 선택 했다면 학교 이메일로 인증을 해야하는데요. 밑에 학교에서 사용하는 이메일 주소를 추가해달라고 하니까 추가해줍시다. ![Add School Email Adress](/How-To-Get-GitHub-Student-Developer-Pack-Add-School-Email-Adress.png) `Add an email address` 버튼을 누르면 `GitHub`의 이메일 설정창으로 보냅니다. 여기서 학교 이메일을 추가해주고, 학교 이메일 계정으로 이메일을 인증해달라는 링크가 담긴 메일이 옵니다. 그 메일에 첨부된 링크를 선택하면 추가된 이메일 주소가 인증됩니다. 그러면 이제 아까 본 화면에서 학교 이메일이 추가되었을겁니다. ![Select School Email Adress](/How-To-Get-GitHub-Student-Developer-Pack-Select-School-Email-Adress.png) 만약 저렇게 뜨지 않고 학생증이나 다른 학생인 것을 인증할 수 있는 방법을 요구한다면 그 아무도 아직 학교 이메일로 `GitHub Student Developer Pack`을 받지 않은 것입니다. 만약 그렇다면 학생임을 인증할 수 있는 생활기록부나 학생증 등을 첨부 후 1일에서 5일 정도를 기다리면 받을 수 있게 되며 그다음 사람은 이러한 인증 절차가 필요하지 않습니다. # 사용하기 --- 모든 절차가 끝나고 `GitHub Student Developer Pack`을 받게 된다면 `GitHub` Profile에 Pro Label이 추가됩니다. 이제 `IntelliJ`나 `Visual Studio Code` 등에서 `GitHub Copilot`을 사용하거나 월 $4를 내며 구독해야 하는 `GitHub Pro`와 똑같은 혜택을 받게 되는 등 다른 여러 가지 혜택을 지원받을 수 있습니다. # 마무리 --- 생각보다 학생이라는 것만으로 무료로 얻을 수 있는 혜택이 꽤 많이 존재합니다. 다음에는 `JetBrains 무료 교육용 라이선스`를 받아보는 방법과 `Termius`에서 학생 인증을 받는 법에 대해 알아보도록 하겠습니다.

Apple 강남 갔다 왔습니다.

후기

Apple 강남 갔다 왔습니다.

삼성 강남에서 체험 끝나고 나서 아주 가깝게 Apple 강남이 있다는 사실이 떠올랐습니다. 그래서 원래였다면 Today at Apple 세션 뭐 있나 보고 예약하고 갔겠지만 그냥 안돼도 상관없다는 생각으로 무지성으로 갔습니다. 가는 길에 전광판들이 꽤 있었는데 그 전광판에 갤럭시 Z 폴드/플립5 광고로 도배되어 있는데 꽤 부담스러웠습니다. ![Galaxy Z Fold/Flip5 Ads](Review-Apple-Gangnam-Galaxy-Z-FoldFlip5-Ads.JPEG) # 도착 --- Apple Store 올 때마다 느끼는 거지만 통유리로 하고 가로를 넓게 하면 정말 광활하다는 생각이 들어요. 집 가야 하는데 제 매인 폰인 갤럭시 Z 플립3 5G의 배터리가 없어서 당장 iPad Air에 충전하고 있던 거 뽑고 충전하고 있으니까 어김없이 Apple Store 직원이 오셔서 말을 거시더군요. 물론 제가 삼성 강남 체험 끝나고 받은 종이 백을 책상 위에 올려놔서 그런 거일 수도 있었지만요. > 고객님 삼성 행사 다녀오셨지만 폰은 iPhone을 사용하시네요! 라는 말을 듣자마자 어질어질했지만 둘 다 사용한다고 말씀드리고 Today at Apple 세션이 있냐고 여쭤봤습니다만 이미 시작을 했다고 하더라고요. 시작한 지 얼마 안 돼서 바로 같이 할 수 있다는 긍정적인 답을 받았지만 초등학생 아이와 부모님이 있는 것을 보고 그냥 참여하지 않기로 했습니다. 직원 한 분이 더 오셔서 관심을 가지셨고요. 제가 폰을 두 개 사용하는 이야기부터 Google I/O Extended 2023 Seoul 갔다 온 이야기 등등 많은 이야기를 했고요. Apple Store 가서 누군가와 이렇게 오랫동안 이야기를 해본 건 처음이었어요. 뭐 하다가 제 진로가 개발 쪽이라는 이야기도 나왔는데 개발 쪽이면 언젠가 맥 사러 와야겠다는 이야기도 빼놓지 않으시던데 정말 프로페셔널 하신 거 같았습니다. 두 분 다 가고 저 혼자 또 있었는데 어디서 저한테 또 말을 거시더라고요. > 고객님 삼성 갔다가 오셨군요! 또 어질어질해졌지만 폰 두 개를 사용한다는 이야기를 했고, 예리하신 직원분께서 제가 갤럭시 워치를 사용한다는 것을 말해주시면서 작은 건 삼성, 큰 것들은 애플 제품을 쓴다는 이야기를 했고요. 이분은 행사에 관심을 가지시길래 Google I/O Extended 2023 Seoul에서 준 것들도 보여드렸고요. 그리고 또 아까 처음 뵀던 직원분도 오셔서 궁금하다고 하시길래 구경시켜드렸고요. 그 과정에서 스티커에 엄청 관심 가지시길래 원하시면 가지셔도 된다고 했더니 하나 가지고 가셨어요. 저 이런 거 받아놓고 관상용으로 쓰고 붙이지도 않고 스티커가 아까워서 드린 게 스티커에게도 저에게도 직원분에게도 아주 좋았을 겁니다. ![Stiker](/Review-Apple-Gangnam-Sticker.jpg) # 구경 --- 이번엔 진짜로 구경을 해봤습니다. 제 iPhone 12 mini도 충전할 겸 iPhone 14 Pro Max을 봤습니다. 혹시 제가 잠시 안온 사이에 홈 앱 문제를 고쳐놨나 싶지만 그렇진 않더라고요. 뭐 체험용 갤럭시 Z 플립5 커버 화면 위젯에 SmartThings 아무 앱이나 눌러보고 있었는데 메시지를 들어왔고요. 근데 이게 iMessage 주소가 다 보이더라고요? 커버 화면 위젯에 SmartThings 박아놓고 활성화 안 시키는 삼성도 메시지 연락처는 다 채워놓던데 아쉬웠습니다. ![iPhone Message App](/Review-Apple-Gangnam-iPhone-Message-App.jpg) 그리고 Safari를 켜봤는데요. 아까 iPad 볼 때도 그랬는데 항상 전시용 기기에 Safari 개인정보 보호 모드가 켜져 있더라고요. > 우리는 당신이 뭘 하는지 전혀 보지 않을게요! 라는 의미로 느껴져서 좀 재밌었습니다. ![iPhone Safari App](/Review-Apple-Gangnam-iPhone-Safari-App.jpg) 그 옆에 Beats Studio Buds +가 널려있더라고요. 사실 이 제품이 궁금해서 메인으로 쓰고 있는 갤럭시 버즈2 프로에서 넘어가려고 고민하고 있었던지라 청음을 해보았습니다. ![Beats Studio Buds +](/Review-Apple-Gangnam-Beats-Studio-Buds-+.jpg) 열어서 등록을 하려고 하니까 전시용으로 있는 iPhone에서도 잘 되었는데 제가 사용하고 있는 갤럭시 Z 플립 3 5G에서도 뜨더라고요. 사실 iOS와 안드로이드 모두 지원하면서 Google Fast Fair와 오디오 전환을 지원합니다. Apple 기기에서 쓸 때보다 더 많은 기능을 사용할 수 있어요. 그래서 구매를 고민했었습니다. ![Beats Studio Buds + Google Fast Fair](/Review-Apple-Gangnam-Beats-Studio-Buds-+-Google-Fast-Fair.jpg) 하지만 청음 하고 생각이 완전히 바뀌였습니다. 음색 자체는 나쁘지 않았는데 제가 사용하고 있던 갤럭시 버즈2 프로보다 노이즈 캔슬링 성능이 안 좋게 느껴졌고, 볼륨도 낮은 거 같아 그냥 마음을 접었습니다. 그래도 생긴 건 볼수록 이쁘더라고요. ![Beats Studio Buds + Transparent](Review-Apple-Gangnam-Beats-Studio-Buds-+-Transparent.jpg) Apple Watch도 봤는데 삼성 강남보다 전시 방식이 더 나은 거 같았어요. 요란하지도 않고 심지어 꽤 이뻤고요. 아 그리고 그 옆에 Apple TV 있었는데 개장한지 얼마 안 돼서 그런가 가로수길보다 훨씬 관리가 잘 되어있더라고요. ![Apple Watch](/Review-Apple-Gangnam-Apple-Watch.jpg) 아 그리고 이렇게 밴드들도 이쁘게 걸어놨는데 호들갑 좀 더하자면 엄청 비싼 박물관에 가서 전시를 보는 느낌이었습니다. ![Apple Watch Bands](/Review-Apple-Gangnam-Apple-Watch-Bands.jpg) # 마무리 --- Apple Store는 언제 놀러와도 재미있는 거 같고요. 또 나중에 시간 나면 놀러오도록 하겠습니다.

삼성 강남 갔다 왔습니다.

후기

삼성 강남 갔다 왔습니다.

Google IO Extended 2023 Seoul 끝난 후에 이대로 집에 돌아가긴 아쉬워서 근처에 뭐 할 거 없나 생각하다가 새로운 갤럭시 Z 폴드/플립 시리즈가 나왔고 예전에 삼성이 새로운 놀스팟? 이러면서 뭐라 뭐라 광고했던 게 떠올라서 갔습니다. 총 6층짜리였고 고객은 5층까지만 쓸 수 있더라고요. # 1층 --- 들어가자 마자 사람이 엄청 없을 줄 알았는데 새로운 갤럭시 Z 폴드/플립 시리즈가 나와서 그런지 사람들이 꽤 많더라고요. 저도 Z 플립/폴드를 구경했습니다. 근데 원래 못가져가게 유선 줄로 연결되어 있었는데 이젠 이게 마그네틱 커넥터로 바뀌었더라고요? 이건 좀 좋은거 같았고요. ![Magnetic Connectors](/Review-Samsung-Gangnam-Magnetic-Connectors.JPEG) 보다 보니까 갤럭시 Z 플립5 삼성닷컴 전용 색상도 있더라고요. 삼성닷컴 전용 색상이 무광이면 대체 왜 기본 색상에는 무광이 없는 걸까요? 그리고 이건 또 프레임도 무광이던데 대체 삼성이 뭘 하려는지 감이 잘 안 잡혔고요. ![Galaxy Z Flip5 Samsungdotcom Blue Color](/Review-Samsung-Gangnam-Galaxy-Z-Flip5-Samsungdotcom-Blue-Color.JPEG) 그다음에 Z 폴드5를 봤는데요. 10g이 줄었다고 했는데 그거보다 더 줄은 거 같았고요. 대부분 다들 이번에 갤럭시 Z 플립5의 커버 화면이 커졌다고 좋아하시던데, 저는 왜인지 전체적으로 그냥 마음에 안 들고 갤럭시 Z 폴드5가 끌리더라고요. 이것도 삼성닷컴 전용 색상이였어요. ![Galaxy Z Fold5 Samsungdotcom Blue Color](/Review-Samsung-Gangnam-Galaxy-Z-Fold5-Samsungdotcom-Blue-Color.JPEG) 이것저것 하고 있었는데 대부분 플립 아니면 폴드 하나씩 다 쥐고 계시더라고요. 뭔가 해서 봤는데 무슨 이벤트성으로 삼성 강남 내에서 사용할 수 있게 해주고 체험 후에 별을 모아오면 상품으로 변경이 가능하다고 했습니다. 그래서 저도 하려고 했는데 신분증이 없어서 기기를 빌리 진 못했습니다. 기기를 빌리면 GS25랑 콜라보 한 뭔 먹을 거도 준다고 했는데 그거도 못 받아서 매우 아쉬웠고요. 일단 이거 시작하면 4층부터 가야 합니다. # 4층 --- 엘레베이터 타고 도착하니까 페인트 냄새가 엄청나서 머리가 아팠고요. 여기서 체험하는건 원하는 플립 아무거나 골라서 플립 플렉스 스크린을 마음대로 꾸며보는 것이였습니다. ![Custom Z Flip5 Flex Screen](/Review-Samsung-Gangnam-Custom-Z-Flip5-Flex-Screen.JPEG) 뭐 별건 없었고요. 이거 하니까 별 주더라고요. 기분 좋았습니다. 별 주는 활동과 별개로 카트라이더 드리프트랑 콜라보 했는지 OLED G9 가져다 놓고 거기에 카트라이더 드리프트 띄어놨더라고요. 저도 한판 했습니다. ![Kartrider Drift OLED G9](/Review-Samsung-Gangnam-Kartrider-Drift-OLED-G9.JPEG) 그 옆에 갤럭시 Z 플립5랑 갤럭시 탭 S9 Ultra가 있었는데 Z 플립5는 가로 게임 띄워놨으면 좀 가로로 돌려놨으면 좋았을 거 같습니다. ![Kartrider Drift Galaxy Z Flip5 Galaxy Tap S9 Ultra](/Review-Samsung-Gangnam-Kartrider-Drift-Galaxy-Z-Flip5-Galaxy-Tap-S9-Ultra.JPEG) # 3층 --- 3층 오자마자 여러 케이스들이 보였고 맛있는 냄새가 났습니다. ![Case](/Review-Samsung-Gangnam-Case.JPEG) 여기에서는 플립수트 카드와 플립수트 케이스를 이용하는 체험을 하는데요. 플립수트 카드 사용하면 플렉스 스크린에 표시되는 커버 화면이 막 확확 바뀌던데 이거 좀 멋졌습니다. ![Galaxy Z Flip5 Flipsuit Card Cover Screen](/Review-Samsung-Gangnam-Galaxy-Z-Flip5-Flipsuit-Card-Cover-Screen.JPEG) 근데 저는 발표 보고 플립수트 카드가 MagSafe처럼 기기 후면에 딱 달라붙는 줄 알았는데 그건 아니더라고요? 오히려 이거 사용하려고 케이스 씌우면 기기가 못생겨져요. ![Galaxy Z Flip5 Flipsuit Case](/Review-Samsung-Gangnam-Galaxy-Z-Flip5-Flipsuit-Case.JPEG) 이거 다하고 3층에는 뭐가 재미있어 보이는 게 많아서 열심히 둘러봤는데 왜 맛있는 냄새가 나나 했더니 커피랑 빵을 팔고 있었습니다. ![Bakery](/Review-Samsung-Gangnam-Bakery.JPEG) 그 다음에 뭐 비스포크 홈 메타라고 삼성전자 가전을 둔 3D 가상 주택을 체험하는 게 있었는데 얼마나 관리를 안했으면 여긴 뭐 되는게 없었습니다. ![BESPOKE HOME META](/Review-Samsung-Gangnam-BESPOKE-HOME-META.JPEG) # 2층 --- 내려오니까 여기서는 수면 서베이라는 걸 하면서 내 수면에 따라서 어떤 동물인지 생성하는 그런 걸 했었는데, 이건 갤럭시 워치 6에 관한 기능 같았습니다. ![Sleep Survey](/Review-Samsung-Gangnam-Sleep-Survey.JPEG) 이런 활동이 끝나면 항상 별을 갤럭시 Z 플립5로 적립 받았는데 이건 삼성 페이로 결제하는 경험을 느껴보면서 이런 곳에서 별을 적립 받았는데 삼성페이도 NFC 결제가 된다는 것을 강조하고 싶었던 건지 뭔지 모르겠지만 이건 좀 멋지던데 모든 층에서 이렇게 했으면 더 좋지 않았나라는 아쉬움이 있어요. <s>(어차피 워치에서는 삼성페이도 없으면서 대체 왜?)</s> ![Samsung Pay Experience](/Review-Samsung-Gangnam-Samsung-Pay-Experience.JPEG) 그리고 뭐 여러 가지 제품들을 쭉 전시해놓았더라고요. 여긴 뭔가 잘 꾸며진 삼성 디지털프라자 같았습니다. ![Galaxy Tab S9 Series](/Review-Samsung-Gangnam-Galaxy-Tab-S9-Series.JPEG) 그리고 갤럭시 탭 S9 Ultra는 있는데 또 따로 전시를 해놓았더라고요. 이 터치패드 없는 키보드는 갤럭시 탭 S8/S8+ 거였는데 이번에 새로 추가된 건지 잘 모르겠습니다. 어차피 갤럭시 탭 S9/S9+/S9 Ultra가 전작과 카메라 모양이 아주 살짝 달라져서 커버들은 다 만들었겠구나 싶네요. ![Galaxy Tab S9 Ultra](/Review-Samsung-Gangnam-Galaxy-Tab-S9-Ultra.JPEG) 저기엔 뭔 사이클을 새워놨길래 뭔가 하고 오니까 갤럭시 워치 위젯처럼 생긴 게 있더라고요. ![Galaxy Watch Widget](/Review-Samsung-Gangnam-Galaxy-Watch-Widget.JPEG) 여기 밑에 여러 가지 운동을 테마로 한 갤럭시 워치 6들이 쭉 있었고요. 근데 이건 뭘 자랑하려는지 도무지 감이 안 잡혔습니다. 그냥 콜라보 한 스트랩들 자랑이었을까요? ![Galaxy Watch 6 Running](/Review-Samsung-Gangnam-Galaxy-Watch-6-Running.JPEG) ![Galaxy Watch 6 Tennis](/Review-Samsung-Gangnam-Galaxy-Watch-6-Tennis.JPEG) # 마무리 --- 별 모은거에 따라서 상품 받아가면 되는데 저는 양말 받았습니다. 근데 이게 진짜 너무너무 못생겨서 강아지 장난감으로 주고싶을 정도여서 올리진 않겠습니다. 다들 관심 있으시면 한번씩 가보시는것도 매우 좋을 것 같습니다.

Google I/O Extended 2023 Seoul 다녀왔습니다.

후기

Google I/O Extended 2023 Seoul 다녀왔습니다.

한국에서 열리는 Google IO Extended 중 가장 큰 규모의 Extended Seoul이 열린다는 소식을 접했는데요. festa에서 티켓을 구매할 수 있길래 구매하고 다녀왔습니다. # 도착 --- 1시에 시작하는 행사였지만 저는 30분 정도 일찍 도착했는데요. 길을 찾아가는 건 그리 어렵지 않았고요. 도착하면 세션 시간표와 홀 지도가 담긴 리플렛과 웰컴 드링크, 입장 팔찌를 받을 수 있습니다. 이거 팔찌 이뻐서 살리고 싶었는데 다니다 보니까 물에도 젖고 구겨져서 안타깝게 포기했습니다. ![Timetable](/Review-Google-IO-Extended-Seoul-Timetable.jpg) ![Event Map](/Review-Google-IO-Extended-Seoul-Event-Map.jpg) 웰컴 드링크는 입장할 때 생수(무려 에비앙!)와 처음 보는 플라스틱 병에 담긴 라떼가 있었는데 뭐 선택할 기회 없이 주는 거 아무거나 받았는데요. 그게 라떼였습니다. 빙그레가 후원사라고 하더라고요? 찾아보니까 신제품이라고 하더라고요. 맛있어서 한 개 더 마시고 싶었는데 안 보여서 생수 마셨고요. 티켓값 1만 원이었는데 제가 먹은 음료(커피, 생수, 콤부차) 값만 해도 1만 원은 넘은 거 같고요. ![Welcome Drink](/Review-Google-IO-Extended-Seoul-Welcome-Drink.png) # Keynote --- 시간표에 나와 있는 것처럼 좋던 싫던 도착하자마자 좋던 싫던 구글에서 6-7년 정도 근무하신 Manikantan Krishnamurthy 님의 키노트를 들어야 합니다. 아까도 말했지만 좀 일찍 왔는데 저보다 일찍 오신 분들도 엄청나게 많더라고요. 그래서 발표 대신에 뭐 틀어주는 영상 봤는데 엄청 AI 이야기를 하더라고요? `생성형 AI가 우리 모두를 도울 것이다`, `AI가 검색의 새로운 경험을 줄 것이다` 등등에 내용인데 제가 영어를 잘 못해서 이해는 잘 안 갔고요. ![AI Video](/Review-Google-IO-Extended-Seoul-AI-Video.jpg) 발표 전에 간단한 Google I/O Extended 소개와 행사장 소개를 했고요. 그다음에 올라오셔서 발표를 하셨습니다. 안타깝게도 한국어를 못하신다고 하셨고 다음에 만날 때는 한국어를 공부해오신다고 했는데 제가 영어를 못해서 제대로 이해한 게 맞나 모르겠고요. ![Keynote](/Review-Google-IO-Extended-Seoul-Keynote.jpg) Keynote 내용은 한국은 모바일 결제 시장이 엄청나고 <s>(그래서 구글 페이는 언제?)</s> 택시도 폰으로 쉽게 잡을 수 있고 멋지다! 라는 내용과 구글이 모바일 우선에서 AI를 우선하는 회사로 바뀌였고 지금도 AI로 엄청난 변화가 일어나고 있고 이 변화를 여러분들이 이끌 수 있다 뭐 이런 내용이었는데 이것도 제가 영어를 잘 못해서 제대로 이해한 건지 모르겠습니다. # What's new in android development tools --- 다음 세션도 Keynote를 들은 똑같은 행사장에서 저는 들었는데요. 카카오뱅크에서 근무하시는 노현석님의 `Android Studio`의 새로운 내용에 관한 것이었어요. 저는 안드로이드 개발은 한 번도 해본 적 없지만 `Android Studio`, `Xcode` 같은 네이티브 앱을 개발하는 툴들의 악명을 너무 많이 들어서 대체 왜 그런가 했는데 이 세션 들으면서 알았습니다. ## Flamingo 첫 번째로 `Android Studio`의 새 버전인 `Flamingo`에 대한 내용이 있었습니다. `Flamingo`에서는 `build option default values`가 완전히 반대로 바뀌어서 툴 하나 업데이트했다고 앱 빌드 안되면 개열받을 거 같지만 그래도 이런 데에서 알려주니까 대부분의 개발자분들은 문제없을 거 같다는 생각이 들었고요. ![build option default values](/Review-Google-IO-Extended-Build-Option-Default-Values.jpg) 이다음 내용부터가 저는 꽤 충격적이었는데요. 빌드를 할 때 Task를 카테고리별로 그룹화해준다는 겁니다. > 빌드를 할 때 Task를 카테고리별로 그룹화해주지 않았다는 건 Task 카테고리별 그룹화가 없을 땐 그냥 무작위로 막 보여줬나? 그러면 빌드 시간에 문제 생기는 애들을 내가 하나하나 스크롤 하면서 찾아야 해? 라는 생각이 들면서 머리 속이 난리가 났지만 여태껏 안드로이드 개발자분들 문제 없이 잘 개발하셨으니까 저 혼자 호들갑 떨었을 가능성이 매우 높습니다. ![build analyzer task](/Review-Google-IO-Extended-Build-Analyzer-Task.jpg) 테마 혹은 컬러 팔레트에 따라 바뀌는 앱 아이콘을 미리 볼 수 있다는 내용도 있었습니다. 이건 뭐 그냥 아이콘 넣어놓으면 알아서 할 테니까 문제가 없지 않나 싶긴 했었는데요. > 실 기기에서는 똑바로 안 나올 수 있고 사이즈를 잘못 넣어서 난리가 날 수도 있는 건데 이걸 확인하고 싶으면 여태 실기기를 가져와서 확인해야 하는 거였구나 라는 생각과 왜 이런 아이콘을 적용하는 앱들이 매우 적은지 알게 되었습니다. 한편으로는 거의 모든 시스템 앱에 이런 아이콘을 적용하는 삼성 개발자분들이 엄청나 보였고요. ![theme icon preview](/Review-Google-IO-Extended-Theme-Icon-Preview.jpg) 아이콘도 미리 보기 지원 안 했으니까 앱 안에서 사용되는 Dynamic Color도 당연히 안됐겠죠? 네, 그렇더라고요. 근데 이것도 지원해 준대요 `Flamingo`부터요... ![dynamic color preview](/Review-Google-IO-Extended-Dynamic-Color-Preview.jpg) 앱을 수정하고 그 수정 내역을 바로 확인해 볼 수 있는 Live Edit에서 Compose를 수정하면 바로 수정사항이 반영이 안됐다고 하더라고요. 근데 이제부터는 아주 잘 된다고 합니다. ![Live edit for compose](/Review-Google-IO-Extended-Live-Edit-Compose.jpg) 그리고 원래 실기기에서 앱을 보려면 폰을 옆에 두거나 다른 앱 사용해서 미러링을 해야만 실기기 화면을 볼 수 있다고 하는데 이제는 미러링을 `Android Studio` 안에서 할 수 있대요. 이건 좀 멋진거 같았어요. ![mirroring](/Review-Google-IO-Extended-Mirroring.jpg) ## Hedgehog 두 번째로 `Android Studio`의 베타 버전인 `Hedgehog`에 대한 내용이었습니다. `Hedgehog`에서는 `Studio Bot`이라는 LLM 기반의 봇이 추가되었다고 하는데요. 근데 아무리 실험 단계라고 하지만 그렇게 똑똑해보이진 않더라고요. 분명 구글은 AI 중심이라고 했었는데... 좀 그렇네요. ![studio chat](/Review-Google-IO-Extended-Studio-Chat.jpg) `AI Assistant`와의 비교도 있었는데, 아무것도 모르는 제가 봐도 `AI Assistant`가 똑똑한게 보여요. 근데 아직까지는 미국에서만 사용 할 수 있다니까 한국 정식 지원을 할 때 쯤이면 `GitHub Copilot Chat`, `AI Assistant`보다 더 나은 모습을 보여줬으면 좋겠습니다. ![AI Assistant](/Review-Google-IO-Extended-AI-Assistant.jpg) 그 외에도 `Hedgehog`의 여러가지 신기능에 대한 언급이 있었는데요. 이건 제가 좀 알지 못하는 부분이라 이해에 어려움이 있었습니다. ![New Compose Multipreview templates](/Review-Google-IO-Extended-New-Compose-Multipreview-Templates.jpg) ![Embedded Layout Inpector](/Review-Google-IO-Extended-Embedded-Layout-Inpector.jpg) 이 모든 발표를 마친 후에 핵심 내용이 담긴 자료도 있었으니 보고 싶은 분들은 보시고요. ![Flamingo](/Review-Google-IO-Extended-Flamingo.jpg) ![Hedgehog](Review-Google-IO-Extended-Hedgehog.jpg) # Google Cloud Security Story --- 앞 세션을 마친 후에 저는 다음 세션을 들으러 갔고요. 구글 클라우드에서 보안 일을 하시는 서진원 님의 `Cloud`와 `On Premise`, `캡챠`에 관한 내용들이었습니다. ## Cloud vs On Premise `Cloud`와 `On Premise` 방식에는 보안상 많은 차이가 존재한다고 이야기 해주셨는데요. `On Premise` 방식은 보안문제가 발생하고 보안 문제를 인식 하는데까지 운이 좋으면 바로 인식 할 수 있지만 그렇지 않은 경우가 매우 많으며 만약 인식했다고 하여도 꽤 많은 시간이 소요된다고 합니다. ![On Premise](/Review-Google-IO-Extended-On-Premise.JPEG) 반면 `Cloud` 방식은 `Cloud API`를 통하여 자동으로 대응을 실행하는데, 이 과정이 5초도 안된다고 해서 꽤 놀라웠습니다. ![Cloud](/Review-Google-IO-Extended-Cloud.JPEG) 예전에는 `Cloud`를 사용할까 `On Premise`를 사용할까 고민하는 추세였다면 요즘에는 언제 넘어갈까 고민하는 추세라고 하고요. 잘 모르는 제가 들어봐도 이렇게 쉬우면 당연히 `Cloud` 공부 필수가 맞는 거 같습니다. 이다음에는 `Google Cloud`를 이용하게 되면 고객이 걱정하는 것들에 대해서도 말을 해주셨는데요. `Google Cloud`에서 원할 때 언제든 고객의 데이터에 접근해 빼돌릴 수 있다는 이야기를 자주 들으신다고 하는데 서버 랙 사용 기록, 서버실 출입 기록 모두 기록되며 직원마다 접근 권한이 다르기 때문에 혼자서 하는 건 어렵고 여러 명이 뭉쳐서 한다고 해도 많은 어려움이 있을 것이라고 말씀해 주셨습니다. ![Defense in depth](/Review-Google-IO-Extended-Defense-In-Depth-At-Scale.JPEG) 근데 `Google Cloud`가 아닌 `Google Cloud`에서 납품받는 서버에 하드웨어 백도어가 있을 때도 보안 대책이 있다고 합니다. `Titan`이라는 보안 모듈과 자체 제작 OS를 이용해서 시스템 무결성 검사를 하고 이 검사를 통과하지 못한 서버는 OS 단에서 아예 배제를 시켜버린다고 하네요. ![Titan](/Review-Google-IO-Extended-Titan.JPEG) Google Cloud에서는 여러 보안 제품을 사용하고 있는데, 이게 모두 외산 Framework입니다. 근데 왜 국산을 쓰지 않냐는 의문이 들 수 있죠. 국내에는 이런 Framework가 아예 없다고 합니다. 매우 안타까운 부분이고요. ![Secure framework](/Review-Google-IO-Extended-Google-Cloud-Secure-Framework.JPEG) 업무할 때도 여러 보안 대책이 있다고 합니다. `Google Workspace`를 이용해서 메일로 들어오는 바이러스 파일을 거르고 그 파일이 걸러지지 않을 경우 `Chrome`이 한 번 더 검사를 한다고 합니다. `Chrome`은 탭 하나하나가 모두 엔진이기 때문에 문제가 되는 탭을 닫게 되면 다른 탭에는 전혀 영향이 끼치지 않는다는데 그래서 램을 많이 먹는다고 하는데 뭐 어쨌든 엄청 멋졌고요. 그리고 구글 검색 크롤러가 하루 약 10억 개의 사이트를 돌며 검사하는데 1백만 개의 악성코드 데이터베이스를 업데이트해서 `Chrome`이 바이러스를 탐지하는데 돕는다고 했고 `ChromeOS`를 업무에 사용해서 마지막까지 설치가 안 되게 완벽하게 막는다고 했는데 진짜 멋졌습니다. ![Ransomware mitigation](/Review-Google-IO-Extended-Ransomware-Mitigation.JPEG) 그다음에 막 Google Cloud에서 여러 보안 인증도 받고 그랬다고 이야기 해주셨는데 여긴 너무 어려워서 제가 이해를 못했습니다. ## reCAPTCHA Google Cloud 이야기 끝나고 `reCAPTCHA` 이야기를 해주셨습니다. 다들 `reCAPTCHA`가 뭔지 아시죠? 그 어디 들어갈 때 '로봇입니까?' 이렇게 물어보고 계속 나한테 사진 고르라고 하는 삐져나온 부분 골라야 할지 안 할지 맨날 헷갈리는 그거 맞습니다. 팁을 하나 주셨는데 삐져나온 부분도 선택을 해야 한다고 하고요. 만약에 그거 선택 안 하면 계속 어려워질 수도 있다고 하고요. `reCAPTCHA`의 버전들을 보여주셨는데요. 저희에게 가장 익숙한 `reCAPTCHA 2.0`부터 최근 나온 `reCAPTCHA Enterprise`까지 보여주셨습니다. ![reCAPTCHA history](Review-Google-IO-Extended-ReCAPTCHA-History.JPEG) 그 중 `reCAPTCHA Enterprise`의 동작 흐름도를 보여주셨는데요. 유저가 페이지에 접속하면 `user agent`를 받아서 Google 서버로 던진 다음에 이 `user agent`에 0.1부터 1까지의 점수를 매긴 후 0.5 이상이면 통과 시킨다고 합니다. 대체로 0.1, 0.2, 0.3, 0.7, 0.8, 0.9 정도의 숫자가 많고 중간 정도의 숫자는 적다고 합니다. 그냥 유저가 접속 하기만 해도 `reCAPTCHA` 인증이 되는게 엄청 멋졌습니다. ![reCAPTCHA Enterprise](/Review-Google-IO-Extended-ReCAPTCHA-Enterprise.JPEG) 이 세션은 처음부터 끝까지 멋지다와 재밌다 두가지의 감정에서 왔다갔다 하는 재미있는 세션이였습니다. 만약 한번 더 들을 수 있다면 한번 더 듣고 싶어요. # 일 잘하는 개발자는 회사에서 어떻게 일할까? --- 이 세션은 헤이딜러에서 근무하시는 박상권 님의 세션이었고요. 이 세션에서는 기술 관련 내용과 코드 한 줄이 없었습니다. 박상권 님께서 발표하시면서 고인물 개발자 형이 썰 풀어주는 것처럼 편하게 들으면 된다고 하셨었는데, 진짜 그렇게 들었습니다. 사진은 찍었는데 다 텍스트로 설명이 가능 한 부분이어서 이 글에는 아마 사진이 없을 겁니다. ## 암묵지 없애기 만약 우리가 처음 회사에 들어왔다고 가정해봅시다. 서비스 도메인에 대한 지식이 아예 없겠죠. 그러면 업무 하는데에 꽤 지장이 있을 수 있습니다. 또한 회사를 다니고 있는 사람들 끼리도 서비스 도메인에 대한 생각이 다를 수 있고요. 그래서 이러한 암묵지들을 어디에는 정리해야한다고 합니다. 대신에 이 암묵지를 정리하는 것은 누구도 고민하지 않았던 문제라던가 규칙이 있는 문제를 수정하는 것이 아닌 모두 고민했지만 명확하게 정하지 않았던 것에 정하고 규칙이 없는 것에 만들고 이름이 없는 것에 정하려고 하는 것이라고 합니다.예를 들어주신 것은 저 화면에선 `X` 버튼인데 다른 화면에서는 `<-`거나, 저 영역에는 스켈레톤이 있지만 다른 곳에서는 없는 이유가 무엇인지 같은 것들 말이죠. ## 기술로만 해결하려고 하지 않기 문제를 해결하기 위해 방법을 찾을 때 기술적으로만 해결하려고 하면 안 된다고 합니다. 통화대기 시간이 길다는 CS를 받았을 때 통화 연결음에서 나는 `뚜~` 소리를 좀 길게 한다거나, 엘리베이터가 느리다는 CS가 들어왔을 때는 엘리베이터에 거울을 설치하는 이런 방법으로도 문제를 해결해야 한다고 합니다. 또한 디자이너 혹은 다른 누군가가 무엇을 요구했을 때에도 안된다고 말하기보다는 다른 대안을 제시하는 것이 더 좋은 방향이라고 합니다. ## 최적의 개발방향을 찾기 기획자가 해결한 방법보다 내가 더 나은 방향을 알고 있다면 주저 없이 제안해야 한다고 합니다. 완성도가 5% 정도 떨어지지만 개발 시간을 80% 이상 단축할 수 있는 문제를 해결하는 가장 빠르고 확실한 방법은 무조건 제안해야 합니다. 내 개발 방식보다 고객의 문제를 해결하는 더 좋은 구현을 고민해야 한다고 합니다. 내가 1달 동안 야근을 해서 짠 코드라도(물론 그렇다고 말하면서 다른 대안을 제시할 수도 있지만) 집착해서는 안 됩니다. 또한 누가 이렇게 시켰다고 해서 무조건 그렇게 하는 것이 아닌 관성적으로 개발해온 업무방식이나 코드를 더 좋은 방식으로 개선할 수 있습니다. ## 모든 것을 기록하기 말로 논의한 회의 등도 모두 기록해 기억이 안날 때 검색하고 누가 왜 그렇게 했는지 또는 참고가 필요할 때 많은 도움이 될 수 있습니다. 또한 뭔가 물어보거나 할 때 개인 DM보다는 공개 채널을 이용해 비슷한 내용에 대한 문의나 요청을 막을 수 있고 누구든 그 소통 기록을 찾아볼 수 있어서라고 합니다. 한일과 해야 할 일을 명확히 정리해 어떤 것을 했고 무엇을 해야 하는지도 정리해야 합니다. 또한 내가 그 일을 당장 할 수 없다면 까먹기 전에 리마인더를 작성해 놓는 것도 좋고요. 회고는 마치 오답노트와 같다고 합니다. 어떤 목표를 가지고 업무를 했는지, 어떤 부분이 부족했는지, 다음에 어떤 시도를 할지 적어 놓는 등 매우 중요한 역할을 하는 것이 회고인데요. 대충 연말만 되면 몇 년도 회고 이런 식으로 작성을 많이 하는데 최소한 분기에 한 번씩은 해야 좋다고 합니다. 이 세션은 개발자 뿐만 아니라 많은 직업군에서 도움이 될만한 내용을 많이 가지고 있다고 생각하는 세션이였어요. 이 세션을 참여하시는 분들이 제일 많았던거 같아요. # Go 언어에서의 패키지 취약성 관리와 deps.dev API를 활용하여 다른 언어에서 이를 구축하는 방법 --- 이 세션은 당근마켓에서 근무하고 계신 이태현 님께서 패키지 취약성 관리를 하는 법을 다룬 세션을 진행해 주셨습니다. `Go`와 `python`을 예시로 보여주셨었습니다. ## govulncheck를 이용한 패키지 활용법 먼저 `CLI`를 사용해서 `govulncheck`를 사용하는 방법입니다. `govulncheck .`을 `CLI`에 입력하게 되면 `govulncheck`가 파악하고 알아서 취약점이 있는 모듈을 업데이트 해줍니다. ![govulncheck CLI](/Review-Google-IO-Extended-Govulncheck-CLI.JPEG) 그 다음은 `IDE(Virtual Studio Code)`를 이용한 방법이였습니다. `setting.json`에 다음과 같이 입력하면 됩니다. ![govulncheck IDE](/Review-Google-IO-Extended-Govulncheck-IDE.JPEG) 그렇게 입력하고 나면 그 다음부터 `IDE(Virtual Studio Code)`에서 다음과 같이 표시되며 패키지 취약성을 확인 할 수 있습니다. ![govulncheck IDE warming](/Review-Google-IO-Extended-Govulncheck-IDE-Warming.JPEG) 다음은 `makefile`을 이용한 방법입니다. 아래와 같은 파일을 생성합니다. ![govulncheck makefile](/Review-Google-IO-Extended-Govulncheck-Makefile.JPEG) 그 후에 CLI에 다음과 같이 입력하면 `govulncheck .`와 같은 일을 수행하게 됩니다. ![govulncheck makefile warming](/Review-Google-IO-Extended-Govulncheck-Makefile-Warming.JPEG) 마지막으로 `pre-commit`을 사용하는 방법이고요. 이 방법은 `production`에 전혀 영향을 끼치지 않고 내가 `git commit` 하기 전 알아서 해결해주는 방법으로 개인적으로 저는 이 방법이 제일 좋다고 느껴졌습니다. `.git/hooks/pre-commit` 파일에 아래와 같이 저장 후 권한을 755로 설정하면 `git commit`시 실행됩니다. ![govulncheck pre-commit](/Review-Google-IO-Extended-Govulncheck-Pre-Commit.JPEG) ## python에서 사용하기 이렇게 멋지게 패키지에 취약점을 알고 취약점으로 공격 들어오는 것들을 막을 수 있는데요, 이걸 `go`에서만 사용하긴 아깝죠? 그래서 이걸 `python`에도 써봅시다. 우선 `pip`를 이용해 `fastapi`라는 모듈을 설치해요. ![govulncheck python pip](Review-Google-IO-Extended-Govulncheck-Python-Pip.JPEG) 그다음 아래와 같이 `python` 파일을 작성합니다. ![govulncheck python parser](/Review-Google-IO-Extended-Govulncheck-Python-Parser.JPEG) ![govulncheck python main](/Review-Google-IO-Extended-Govulncheck-Python-Main.JPEG) 이렇게 작성해 줬으면 이제 `main.py`를 실행시켜보면 아래와 같이 잘 잡고 잘 해결합니다. ![govulncheck python warming](Review-Google-IO-Extended-Govulncheck-Python-Warming.JPEG) 근데 위에서는 `pip`를 사용해 모듈 설치를 했는데 저러면 패키지 지울 때 종속성 패키지는 삭제가 안된다고 하고요. `poetry` 사용하면 같이 삭제된다고 합니다. 알고 계시면 좋을 거 같고요. # 엑티비티 --- 한 세션 끝나고 다음 세션 기다릴 동안 20분 정도의 쉬는 시간이 있습니다. 그 쉬는 시간 동안 여러 엑티비티를 즐길 수 있는데요. 저는 친구 없어서 `리뷰보드`, `내 마음 속에 캡챠`, `Dart & Flutter` 정도만 즐겼고요. `Devocean` 부스에서 앱 깔고 인증하면 추첨을 통해서 상품 준다고 했는데 전 역시 운이 진짜 없어서 아무것도 못받았습니다. ## 리뷰보드 이거는 포스트잇에 후기 쓰면 종이 뽑기를 할 기회가 있는데요. 이거 4, 5등은 `JetBrains` 스티커였고 3등이 아마 `JetBrains 티셔츠`였을 거고요 2등이 개발 책 1권 1등이 `JetBrains 1년 이용권` 이였습니다. 아까도 말했던것처럼 전 운이 정말 없어서 5등만 나왔습니다. 근데 `PyCharm`, `IntelliJ` 스티커가 마음에 들어서 만족스럽습니다. ![JetBrains sticker](/Review-Google-IO-Extended-Build-JetBrains-Sticker.jpg) ## 내 마음 속에 캡챠 `캠릿브지 대학의 연결구과` 같은 한국인만 읽고 해석할 수 있는 문장을 적은 뒤에 `reCATCHA`를 풀면 되는 것이었는데요. 30초 이내에 풀면 책 한 권이어서 도전했습니다. 저번 세션에서 `reCATCHA` 잘 푸는 팁을 얻었기 때문에 21.96초 만에 풀고 예전에 읽고 싶었던 책 하나 받아 갔습니다. 근데 이거 `React`로 만드셨던데 왜인지 모르겠지만 `PWA`가 적용되어 있더라고요. ![interactive developer](Review-Google-IO-Extended-Interactive-Developer.jpg) ## Dart & Flutter 다트 3번 던져서 몇 점 이상이면 상품 주는 거였는데 이게 몇 점 이상이었는지 상품이 뭐였는지도 기억이 안 났습니다. 저는 다트 개 못해서 한 개도 못 맞췄고요 근데 줄 서 있다가 `JetBrains` 티 받았어요. ![JetBrains t-shirts](/Review-Google-IO-Extended-JetBrains-T-Shirts.jpg) 다른 것들도 해보고 싶었는데, 줄이 길거나 친구가 있어야 하거나 그래서 못했고요. `도전 코딩 연습`과 `내 마음속의 캡챠`는 리더보드를 `vim 에디터`를 사용하는 것이 매우 인상 깊었고요. 개발자 행사라는 게 많이 느껴졌습니다. # 굿즈 --- 행사 참여자는 굿즈 수령이 가능했는데요. 굿즈에는 Google Extended 티와 스티커, 실로 되어있는 에코백이라고 해야 할지 뭐 그런 거였습니다. 에코백은 행사에서 주는 거만 넣고 다녔는데 거의 다 늘어졌고요. 완벽하게 막힌 게 아니라 그냥 구명이 다 나있는 디자인이라 뭐 어떻게 사용하지는 못할 거 같아 아쉬웠습니다. 티는 깔끔하고 이뻤습니다. 근데 평소에 입고 다니지는 못할 거 같아 아쉬웠고요. 스티커들도 모두 이뻤습니다. 끝나고 애플스토어 강남 갔는데 애플스토어 가기 전에 삼성 강남 갔다 온 거 때문에 직원분들이 이리저리 말을 거시던데 그 과정에서 굿즈 받은 거 자랑하면서 스토어 직원분께서 하나 가지고 싶어 하시길래 하나 드렸고요. 애플스토어 강남이랑 삼성 강남도 조금 있다가 글 쓸게요. ![Google Extended t-shirts](/Review-Google-IO-Extended-Google-Extended-T-Shirts.jpg) ![Google Extended sticker](/Review-Google-IO-Extended-Google-Extended-Sticker.jpg) # 마무리 --- 정말 재밌었고요. 매우 유익하다는 생각이 들었습니다. 다음에는 누구랑 같이 가면 더 재밌을 거 같다는 생각이 들었습니다. 그리고 보조배터리와 키보드를 사용 가능한 큰 기기를 가져와야 할거 같다는 생각도 했고요. 긴 글 읽어주셔서 감사합니다.

Apple 가로수길 갔다 왔습니다.

후기

Apple 가로수길 갔다 왔습니다.

근처에 일이 있었는데 시간이 애매하게 남아서 뭘 할까 하다가 예전에 Apple 여의도에서 애플 펜슬 펜촉 사고 박수 받고 Today at Apple이 재미있었던 경험이 떠올랐습니다. ![Apple Yeouido](/Review-Apple-Garosugil-Apple-Yeouido.jpg) 그래서 근처에 Apple Store가 있는 지 찾아봤는데 강남이랑 가로수길 쪽이 가깝길래 그 쪽에 Today at Apple 세션이 뭐 있는지 확인 후에 예약해서 갔습니다. ![Today at Apple Ticket](/Review-Apple-Garosugil-Today-at-Apple-Ticket.jpg) # 간단한 구경 --- Apple Store 가로수길에 도착 했는데 아직 세션까지 시간이 좀 남아서 Apple Store 구경했어요. 사람들이 많이 찾는 iPhone, iPad나 Mac 이런건 거의 완벽에 가깝게 세팅이 되어 있는데 많이 안찾는 Apple TV 같은건 Sirl remote가 이상하거나 계정 설정이 이상하더라고요. 그리고 홈 앱 설정도 약간 이상했던게 TV가 악세서리로 추가 되어 있었는데, 이게 아이콘도 이상하고 옵션들도 좀 이상하더라고요. ![iPhone Home App](/Review-Apple-Garosugil-iPhone-Home-App.jpg) 어쩌피 사람들이 굳이 저처럼 기기 구경하러와서 홈 앱을 열어 따지진 않을테니까 그럴 수 있다고 생각했습니다. 그리고 폰 배터리가 없어서 구경하는 척 하면서 제 플립 충전 좀 하려고 iPad 있는 곳으로 가서 충전기를 뽑고 제 플립에 꼽고 구경하고 있었는데 Touch ID 데모랑 Face ID 데모가 좀 이상하더라고요? ![Touch ID Demo](/Review-Apple-Garosugil-Touch-ID-Demo.jpg) ![Face ID Demo](/Review-Apple-Garosugil-Face-ID-Demo.jpg) Touch ID 데모 배경이 iOS 15 것이 적용 되어 있지만 iPadOS는 최신이였고, Face ID 데모는 또 배경이 아예 없더라고요? 이런건 좀 많이 아쉬웠습니다. 뭐 이것도 그럴 수 있다고 생각하고 iPad Pro로 제 코드 서버에 들어와서 코딩 좀 하고 있으니까 Apple Store 직원분께서 오셔서 저한테 프로크리에이트 써본 적 있냐고 말을 거시더라고요. 예전에 Apple 여의도에서 Today at Apple 하면서 써본 적 있다고 하니까 프로크리에이트로 금손처럼 하늘 그림 그리는 법 알려주셔서 같이 하늘을 그렸고요. 그 다음에 갤럭시 밖에 안쓰냐, iPad로 어떤거 자주 하시냐 이런 이야기 하다가 저한테 Today at Apple 세션 참가할 생각이 없냐 물어봐주셔서 이미 예약을 했다고 말씀드렸고 체크인 후 기다렸습니다. # Today at Apple --- ![Today at Apple](/Review-Apple-Garosugil-Today-at-Apple.jpg) 세션 시작 시간이 돼도 저 말고 예약하신 분들이 계셨는데 안오셔서 3분 정도 기다렸는데 다른 분들도 도착해서 세션을 진행했습니다. 세션은 뭐 별거 없었고 iPad에 기본으로 설치되어 있는 메모 앱을 어떻게 사용하는지에 대한 내용이었어요. 다 아는 내용이라 재미없었는데 내 휴가 그려보기 이건 좀 재미있었고요. 세션 하는 동안 지급받은 iPad로 좀 딴짓을 했는데 이 iPad에 저장되어 있는 메모에 `지도`를 사용한 메모가 있더라고요. 한국에서 이 기능은 지원 안되는 게 빼는 게 나은 거 같은데 어차피 세션 중에 딴짓하는 사람은 저 밖에 없을 거고요. ![Today at Apple iPad Memo App](/Review-Apple-Garosugil-Today-at-Apple-iPad-Memo-App.jpg) # 마무리 --- 이거 다 마친 다음에 Mac들 좀 구경 하다가 볼 일 보러 갔습니다. 재밌었고요. 다음에도 시간 남을 때 또 구경하러 오거나 Today at Apple 하면 재밌을 거 같습니다.

Next.JS로 블로그를 다시 만들었습니다.

개발

Next.JS로 블로그를 다시 만들었습니다.

블로그가 개설된 지 2개월 하고도 1주일이 지났습니다. 올릴 글은 많았지만 올리지 않았습니다. 블로그가 개설된 이후 제가 짜 놓은 코드 꼬락서니가 마음에 들지 않았고 그래서 글도 쓰기 싫어 방치했습니다. 사실 그것도 있고 시간이 많이 없었는데요. 어떤 기회로 `Next-Contentlayer`를 사용하는 프로젝트를 할 기회가 있어서 그 프로젝트로 어느 정도 감을 잡은 후에 제 블로그를 갈아엎어야겠다는 계획을 세웠습니다. 그리고 지금 블로그를 완벽하게 완성시켰죠. 어떻게 만드는지 과정을 공유해 볼까 합니다. 당장 이 블로그 소스 궁금하신 분은 [github.com/dohun0310/d3h1-Blog](https://github.com/dohun0310/d3h1-Blog)에 올려놨으니까 그거 보시면 되겠습니다. # 갈아 엎을 시간 --- `Jekyll` 기반의 블로그는 엉망이었습니다. SCSS 파일을 썼는데 한 파일에 블로그의 모든 스타일링을 다 때려 박았으니 알아보기도 엄청나게 힘들었고 그냥 코드를 엄청나게 이상하게 짰습니다. 그리고 디자이너가 준 디자인을 개발하기 힘들다고 갈아엎은 것도 마음에 안 들었어요. 아니 그냥 다 변명이고 제 마음에 안 들었어요. 그래서 생각했죠. 새로 만들고 다 갈아엎어버려야겠다고요. 그래서 어떻게 만들까 하다가 제가 좋아하는 `React`로 만들려고 했는데 제가 존경하는 어떤 분께서 `Next.JS`가 쉽고 좋다고 추천을 해줘서 `Next.JS`를 사용하기로 했고 `Next.JS`에 정적 사이트를 쉽게 만들 수 있도록 도와주는 `Next-Contentlayer`라는 모듈이 있길래 그거 끌고 와서 만들었어요. 이제 뭐 쓸지 다 정했으니까 디자인 받아와야겠죠? 전에 디자인해 주신 분께 모바일 어떻게 만들어야 할지 모르겠다고 말하니까 또 금방 하나 찍어내주셨어요. 멋진 걸로요. ![New design](/I-Recreated-The-Blog-Using-Next.js-Blog-New-Design.png) # 제작 시작 --- 이제 `Next.JS`로 블로그 제작을 시작해 봅시다. 모두 `Node.JS`랑 `npm` 아니면 `yarn` 아니면 `pnpm`랑 `create-next-app` 하나 정도는 있으시죠? 터미널에 아래와 같이 입력하면 프로젝트 파일이 만들어집니다. ```bash create-next-app 프로젝트명 ``` 만드셨으면 필요한 모듈들 설치를 해야 합니다. 아래와 같이 진행해 주시면 됩니다. ```bash npm install contentlayer next-contentlayer rehype-highlight rehype-pretty-code shiki next-sitemap @emotion/styled @emotion/css @emotion/react 혹은 yarn add contentlayer next-contentlayer rehype-highlight rehype-pretty-code shiki next-sitemap @emotion/styled @emotion/css @emotion/react 혹은 pnpm add contentlayer next-contentlayer rehype-highlight rehype-pretty-code shiki next-sitemap @emotion/styled @emotion/css @emotion/react ``` 자신이 사용하는 패키지 매니저에 따라서 알아서 해주시면 되고요. 이 모듈들은 블로그 제작을 돕고 `CSS in JS`를 할 수 있게 해주고 `코드 블록`을 이쁘게 꾸며주는 플러그인들입니다. 모듈 설치다 했으면 이제 본격적으로 코드 짜봐야겠죠. 그전에 설정부터 먼저 해줍시다. 먼저 프로젝트 최상단에 위치한 `next.config.js` 파일에 들어가서 수정해 주세요. ```typescript //next.config.js const { withContentlayer } = require("next-contentlayer"); /** @type {import('next').NextConfig} */ const nextConfig = { reactStrictMode: true, swcMinify: true, }; module.exports = withContentlayer(nextConfig); ``` 먼저 프로젝트 최상단에 위치한 `tsconfig.json`도 알맞게 수정해주세요. ```json //tsconfig.json { "compilerOptions": { ... ], "paths": { "@/*": ["./*"], "contentlayer/generated": ["./.contentlayer/generated"] } }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", ".contentlayer/generated", "next-sitemap.config.js"], "exclude": ["node_modules"] } ``` 여기까지 하셨으면 최상단에 `contentlayer.config.ts`라는 파일 하나 생성해주시고 아래처럼 작성하시면 됩니다. ```typescript //contentlayer.config.ts import { defineDocumentType, makeSource } from "contentlayer/source-files"; import highlight from "rehype-highlight"; import rehypePrettyCode from "rehype-pretty-code"; const Post = defineDocumentType(() => ({ name: "Post", filePathPattern: `**/*.md`, contentType: "mdx", fields: { category: { type: "string", required: true }, title: { type: "string", required: true }, date: { type: "date", required: true}, description: { type: "string", required: true }, }, computedFields: { url: { type: 'string', resolve: (doc) => `/${doc._raw.flattenedPath}`, }, }, })) const contentSource = makeSource({ contentDirPath: "posts", documentTypes: [Post], mdx: { remarkPlugins: [], rehypePlugins: [ [ rehypePrettyCode, { theme: "github-dark" }, ], highlight, ], }, }); export default contentSource; ``` 다른 포털에도 표시 되어야 하니까 최상단에 `next-sitemap.config.js` 파일 하나 만들어서 아래처럼 작성해야 `sitemap`이 생성되기 때문에 다른 포털에 표시될 수 있고요. ```javascript //next-sitemap.config.js module.exports = { siteUrl: "블로그 주소", generateRobotsTxt: true, } ``` 모듈 설정 끝났으니까 코드 짜봅시다. # 마크다운 렌더링 하기 --- `Next.JS`가 폴더로 라우팅해서 편하게 우리가 쓸 수 있죠. 저는 도메인 바로 뒤에 아이디가 오는 형식으로 구성하고 싶어서 `app/[...slug]` 경로에 `page.tsx` 파일을 만들었어요. 이거 마음에 안 드시면 공식 문서 참고하셔서 다르게 하셔도 되고요. ```typescript //app/[...slug]/page.tsx import { allPosts } from "contentlayer/generated"; import { getMDXComponent } from "next-contentlayer/hooks"; import { notFound } from "next/navigation"; import { format } from "date-fns"; import { StyledPost } from "./style"; import { Footer, Giscus } from "@/components"; export const generateStaticParams = async () => allPosts.map((post) => ({ params: { slug: post._raw.flattenedPath.split('/') }})) export const generateMetadata = ({ params }: { params: { slug: string[] } }) => { const slug = params.slug.join('/'); const post = allPosts.find((post) => post._raw.flattenedPath === slug) if (!post) { return {} } return { title: post.title, description: post.description, openGraph: { type: "website", url: "본인 블로그 주소", title: post.title, description: post.description, siteName: "d3h1 Blog", }, twitter: { card: "summary_large_image", site: "본인 블로그 주소", title: post.title, description: post.description, }, } } const PostLayout = ({ params }: { params: { slug: string[] } }) => { const slug = params.slug.join('/'); const post = allPosts.find((post) => post._raw.flattenedPath === slug) if (!post) { notFound() } const Content = getMDXComponent(post.body.code) return ( <StyledPost> <div className="post-container"> <article> <h1 className="post-title">{post.title}</h1> <time dateTime={post.date}>{format(new Date(post.date), "yyyy년 MM월 dd일")}</time> <Content /> <Giscus /> </article> <Footer /> </div> </StyledPost> ) } export default PostLayout ``` 이제 posts라는 폴더를 프로젝트 최상단에 만들고 그 폴더 안에 `example.md` 파일을 만들어보세요. 그리고 그 안에는 아래와 같이 작성하세요. ```markdown //posts/example.md --- category: 잡담 //원하는 카테고리 title: 예시 글 date: 2023-07-26 //오늘 날짜 description: Next.JS 프로젝트를 생성하고 처음 쓰는 글 --- 아무렇게 쓴 글씨 ``` 그리고 터미널에 자신의 `패키지 매니저`에 맞게 아래와 같은 명령을 입력 후 실행해 보세요. ```bash npm dev 혹은 yarn dev 혹은 pnpm dev ``` 이제 터미널에 뭐라뭐라 뜰겁니다. ```bash warning ../package.json: No license field $ next dev ``` 이 문구 밑에 뜨는 `- ready ~~~`를 주목하세요. 거기에 `url: `이라고 되어 있는데에 어떤 주소가 있을텐데 그곳을 `Ctrl + 클릭`하면 브라우저 창이 하나 열릴겁니다. 주소 뒤에 `/example`을 입력하고 접속해보면 우리가 쓴 글이 잘 렌더링 된 것을 확인 할 수 있죠. 마음에 안드는 부분은 `page.tsx`에 `@emotion/styled`를 바로 가져와서 사용하거나 따로 `style.tsx`로 빼서 스타일링 해서 사용하시면 됩니다. 나는 `CSS in JS`가 싫다고 하시면 알아서 하시면 되고요. # 글 목록 가져오기 --- 우리 이제 글 표시할 수 있으니까 글 목록을 만들어봐야겠죠. `app` 폴더 밑에 `page.tsx`라는 파일이 있을 겁니다. 거기에 우리는 글 목록을 표시해 볼 거예요. 그 파일 열고 아래와 같이 작성하세요. ```typescript //app/page.tsx import { allPosts } from "contentlayer/generated"; import Link from "next/link"; import Image from "next/image"; const Home = () => { const Posts = allPosts.sort((a, b) => Number(new Date(b.date)) - Number(new Date(a.date))); return ( {Posts.map((post) => ( <article key={post._id}> <Link href={post.url}> <Image src={post.teaser} alt={post.title} width={640} height={360} /> <p className="post-category">{post.category}</p> <h1 className="post-title">{post.title}</h1> <p className="post-description">{post.description}</p> </Link> </article> ))} ); }; export default Home; ``` 이렇게 `page.tsx`를 작성하면 아까 우리가 `/example`을 붙였던 주소에 `/example`을 지우고 다시 접속해 보면 글 목록이 표시될 겁니다. 쉽죠? 생긴 게 마음에 안 드실 텐데 그것도 나중에 `@emotion/styled` 쓰시거나 다른 방법으로 스타일링을 하면 됩니다. # 마무리 --- 예전에 `Jekyll` 블로그 만든 건 그냥 코드를 다 빼다 박았는데 이번에는 초보자분들이 알아서 해볼 수 있도록 글을 작성해 봤어요. 제가 저번 주 토요일부터 이걸 만들기 시작했으니까 대충 만드는데 5일 정도 걸렸네요. 이번 블로그는 매우 마음에 듭니다. 제가 코드를 이상하게 짠 거 같지도 않고 훌륭한 분의 도움을 받아 코드가 탄탄하거든요. 제 우분투 세팅 법도 공유하고 싶고 Today at Apple 갔다 온 후기도 써봐야겠습니다. 따라 오시느려고 수고 많으셨습니다. 이제 자신만의 멋진 블로그를 만들어보세요.

Jekyll를 이용해 블로그를 만들었습니다.

개발

Jekyll를 이용해 블로그를 만들었습니다.

안녕하세요. 오늘은 블로그를 개설하고 처음 제대로 된 글을 작성해보려고 합니다. 이 블로그를 만든 경험과 사용된 코드들을 공유하려고도 합니다. # 블로그가 가지고 싶어! --- 어느 날, 자기 전에 블로그가 가지고 싶다는 생각이 들었습니다. 급하게 이불을 걷어 차고 책상 앞에 앉아 주로 사용되는 티스토리와 네이버 블로그를 비교하기 시작했습니다. * 티스토리: 수익 창출 가능, 커스텀 가능, 서버의 불안정성 높음, 커스텀을 많이 할 경우 느려짐 * 네이버 블로그: 수익 창출 불가능, 커스텀 불가능, 서버의 안정성 높음, 기본 UI도 깔끔함 이렇게 비교를 하고 보니까 티스토리와 네이버 블로그 모두 사용하고 싶지 않아졌습니다. 일단 마음대로 커스텀 할 수 있는 티스토리는 커스텀을 하면 할수록 블로그가 느려지고 네이버는 커스텀 가능한 부분 자체도 적었고 개인 사용자는 수익 창출이 불가능이나 마찬가지였고 구글에서 검색을 할 경우 노출도 잘되지 않거든요. 게다가 두 플랫폼 모두 에디터가 엄청나게 무겁고 별로입니다. 그래서 그냥 직접 만들기로 하였습니다. # 블로그를 만들자! --- `React.JS`를 사용할지 `Next.JS`를 사용할지 생각하다가 '백엔드는 어떻게 하지?'라는 생각이 들었습니다. 사실 `React.JS`나 `Next.JS`를 이용해 프론트엔드를 작업하고 포스팅할 때마다 js 파일을 생성하면 백엔드 작업이 그렇게 복잡해지지 않을 텐데 그러면 뭔가 별로라는 생각이 들어 다른 대안이 있지 않을까 열심히 검색해 보았습니다. 검색을 한 결과 [Jekyll](https://jekyllrb.com/)를 이용해서 블로그를 만들면 제가 원하는 블로그를 만들 수 있다는 결과에 도달했습니다. 테마가 다양하고, 내 입맛대로 커스텀 할 수 있고, 수익 창출이 가능하고 제가 등록만 한다면 모든 포털 사이트에 제 블로그를 노출시킬 수 있는 방법이었으니까요. # Jekyll 시작하기 --- 저는 `WSL2`를 이용해 `VSC`를 사용하는 개발 환경입니다. 제 환경에서 `Jekyll` 프로젝트를 시작하기 위해서는 아래와 같은 명령을 터미널에 입력해 필요한 패키지를 설치하면 되었습니다. ```bash sudo apt install ruby-full build-essential zlib1g-dev sudo gem install jekyll bundler ``` 필요한 패키지들을 모두 설치하였으면 `Jekyll` 프로젝트를 만들고 싶은 경로에 진입하여 아래와 같은 명령어를 입력하면 `Jekyll` 프로젝트가 생성됩니다. ```bash jekyll new 프로젝트명 ``` 이렇게 프로젝트를 생성하고 나서 생성된 폴더로 들어가 아래와 같은 명령어를 입력합니다. ```bash sudo bundle install jekyll serve ``` 이렇게 하고 [127.0.0.1:4000](127.0.0.1:4000)를 웹 브라우저의 주소창에 입력하고 접속하면 `Jekyll`의 기본 테마인 `minima`가 적용된 `Jekyll` 화면을 아래와 같이 확인 할 수 있습니다. ![Minima](/I-Made-The-Blog-Using-Jekyll-Jekyll-Minima.png) # Jekyll 프로젝트에 테마 적용하기? --- 이렇게 `Jekyll` 프로젝트를 처음 만들게 되면 심심하다 못해 재미없어 보이는 Jekyll의 기본 테마가 적용된 모습을 확인할 수 있는데요. 하지만 저는 이런 재미없는 테마보다는 더욱 개성 있고 이쁜 테마를 `Jekyll`에 적용해 보고 싶었습니다. 그래서 `Jekyll`의 테마가 모여있는 [Jekyll Themes](http://jekyllthemes.org/)에 접속하여 인기 있는 테마 몇몇 개를 적용해 보았습니다. 하지만 제 마음에 드는 테마가 없었고 그래서 제 블로그를 제 입맛에 맞게 제가 직접 한번 꾸며보려고 하였습니다. 마침 주변에 멋진 디자인을 만드는 멋진 사람이 있었고 부탁을 해 마음에 꼭 맞는 디자인을 받아볼 수 있었습니다. ![First design](/I-Made-The-Blog-Using-Jekyll-Blog-First-Design.png) 만들기 어려워보이는 부분이 있어 제가 조금 다듬고 그것에 맞추어 저만의 블로그를 만들기 시작했습니다. ![Light design](/I-Made-The-Blog-Using-Jekyll-Blog-Light-Design.png)![Dark design](/I-Made-The-Blog-Using-Jekyll-Blog-Dark-Design.png) # Jekyll 프로젝트 완성하기 --- 저는 `PWA(Progressive Web App)`을 매우 좋아하는 편이여서 가장 먼저 적용하기로 하였습니다. [PWABuilder](https://www.pwabuilder.com/imageGenerator)를 사용하여서 PWA에 사용할 manifest.json과 아이콘 파일들을 다운로드해서 `manifest.json`은 `Jekyll` 프로젝트 경로 최상단에, 아이콘 파일들은 `assets` 폴더에 저장하였습니다. 그다음 `head.html`의 `head` 태그가 끝나기 전 아래와 같은 코드 한 줄을 추가해 주면 PWA는 활성화됩니다. ```html <link rel="manifest" href="{{ '/manifest.json' | relative_url }}"> ``` `head.html`을 건드린 김에 `OpenGraph`와 `favicon`, `title`도 적용해 보겠습니다. 먼저 `favicon`을 적용시켜보겠습니다. [Favicon & App Icon Generator](https://www.favicon-generator.org/)를 사용하여 `favicon.ico` 파일을 얻습니다. 그 후, 얻은 `favicon.ico` 파일을 `assets` 폴더에 `favicon.ico` 파일을 저장하고, `head.html`의 `head` 태그가 끝나기 전 아래와 같은 코드 한 줄을 추가해 주면 `favicon`이 표시되는 것을 확인할 수 있습니다. ```html <link rel="icon" href="{{ '/assets/favicon.ico' | relative_url }}" type="image/x-icon" sizes="32x32"> ``` 이제 `OpenGraph`와 `title`을 적용시켜보겠습니다. `OpenGraph`에서 표시될 이미지를 `opengraph.png`로 이름을 변경 후 `assets` 파일 안에 저장하고, `head.html`의 `head` 태그가 끝나기 전 아래와 같은 코드들을 추가 후 알맞게 수정해 준다면 `OpenGraph`와 `title`이 표시될 것입니다. ```html {% raw %}{% if page.teaser %} <meta property="og:image" content="{{ page.teaser }}"> <meta property="twitter:image" content="{{ page.teaser }}"> {% else %} <meta property="og:image" content="{{ '/assets/opengraph.png' | relative_url }}"> <meta property="twitter:image" content="{{ '/assets/opengraph.png' | relative_url }}"> {% endif %} {% if page.title %} <title>{{ page.title }} | 블로그 이름</title> <meta name="title" content="{{ page.title }} | 블로그 이름"> <meta property="og:title" content="{{ page.title }} | 블로그 이름"> <meta property="twitter:title" content="{{ page.title }} | 블로그 이름"> {% else %} <title>블로그 이름</title> <meta name="title" content="블로그 이름"> <meta property="og:title" content="블로그 이름"> <meta property="twitter:title" content="블로그 이름"> {% endif %} {% if page.description %} <meta name="description" content="{{ page.description }}"> <meta property="og:description" content="{{ page.description }}"> <meta property="twitter:description" content="{{ page.description }}"> {% else %} <meta name="description" content="새로운 것을 즐기고, 변화를 만들고"> <meta property="og:description" content="새로운 것을 즐기고, 변화를 만들고"> <meta property="twitter:description" content="새로운 것을 즐기고, 변화를 만들고"> {% endif %} <meta property="og:type" content="website"> <meta property="og:url" content="블로그 주소"> <meta property="twitter:card" content="summary_large_image"> <meta property="twitter:url" content="블로그 주소">{% endraw %} ``` 이 코드는 `_post`에 작성될 글에 아래와 같이 선언되어 있어야 완벽하게 작동합니다. ```yaml --- layout: post title: "제목" teaser: "teaser 경로" category: category 이름 description: "설명" --- ``` 이제, 외관을 꾸며보겠습니다. 먼저 `home.html`부터 수정해 보겠습니다. ```html {% raw %}--- layout: default --- <header class="header"> {{ content }} </header> <div id="content"> <ul class="category"> <li> <a class="category-link {% if page.url == "/" or page.url contains "page" %} active{% endif %}" href="{{ site.baseurl }}/"> 메인 </a> </li> {% assign pages_list = site.pages %} {% for node in pages_list %} {% if node.title != null %} {% if node.layout == "category" %} <li> <a class="category-link {% if page.url == node.url %} active{% endif %}" href="{{ site.baseurl }}{{ node.url }}"> {{ node.title }} </a> </li> {% endif %} {% endif %} {% endfor %} </ul> <ul class="post-list"> {% assign date_format = site.minima_reboot.date_format | default: "%b %-d, %Y" %} {% for post in site.posts %} <a href="{{ post.url | relative_url }}" class="post"> <div class="teaser"> <img src="{{ post.teaser }}" alt="{{ post.title }} teaser image"/> </div> <span class="date"> {{ post.date | date: date_format }} </span> <h1 class="title"> {{ post.title | escape }} </h1> <div class="description"> <p> {{ post.description }} </p> </div> </a> {% endfor %} </ul> </div>{% endraw %} ``` `category` 버튼들은 `a` 태그를 사용해 만들고 해당 category 페이지에 있을 때 `active` 되어서 다른 버튼들과는 다르게 표시됩니다. 위에서처럼 `_posts` 폴더에 작성될 글에 잘 선언이 되어 있다면 post-list에 teaser와 date, title, description까지 정상적으로 출력됩니다. 또한 `category` 기능이 정상적으로 동작하기 위해서는 `category.html`이라는 파일을 `_layouts` 폴더 안에 아래와 같이 작성해야 합니다. ```html {% raw %}--- layout: default --- <header class="header"> <h1 class="content-header"> {{ page.title }} </h1> </header> <div id="content"> <ul class="category"> <li> <a class="category-link {% if page.url == "/" or page.url == "/page2/" %} active{% endif %}" href="{{ site.baseurl }}/"> 메인 </a> </li> {% assign pages_list = site.pages %} {% for node in pages_list %} {% if node.title != null %} {% if node.layout == "category" %} <li> <a class="category-link {% if page.url == node.url %} active{% endif %}"href="{{ site.baseurl }}{{ node.url }}"> {{ node.title }} </a> </li> {% endif %} {% endif %} {% endfor %} </ul> <ul class="post-list"> {% assign date_format = site.minima_reboot.date_format | default: "%b %-d, %Y" %} {% assign category = page.category | default: page.title %} {% for post in site.categories[category] %} <a href="{{ post.url | relative_url }}" class="post"> <div class="teaser"> <img src="{{ post.teaser }}" alt="{{ post.title }} teaser image"/> </div> <span class="date"> {{ post.date | date: date_format }} </span> <h1 class="title"> {{ post.title | escape }} </h1> <div class="description"> <p> {{ post.description }} </p> </div> </a> {% endfor %} </ul> </div>{% endraw %} ``` `category.html`까지 작성이 완료 되었다면, `Jekyll` 프로젝트의 최상단에 `category`라는 폴더를 생성 후 그 폴더 밑에 원하는 `카테고리 이름.md`라는 파일을 생성 후 그 파일을 다음과 같이 작성하면 됩니다. ```yaml --- layout: category title: 원하는 카테고리 이름 --- ``` `header.html`은 다음과 같이 작성하면 됩니다. ```html <header id="nav-header" class="border-dark border-left-0 border-right-0"> <div id="nav-container" class="container position-relative d-flex justify-content-between align-items-center"> <a href="/"> '자신의 로고 svg' </a> </header> ``` 이제 html 수정을 맞쳤으니 scss를 작성 해보겠습니다. 먼저 header를 화면에 계속 표시하고 블러를 적용하겠습니다. ```scss #nav-header { position: fixed; -webkit-backdrop-filter: saturate(180%) blur(20px); backdrop-filter: saturate(180%) blur(20px); width: 100%; border-bottom: 1px solid #f8f9fa } #nav-container { justify-self: space-between; align-items: center; height: 76px; a { text-decoration-color: #000000; } h1 { font-size: 24px; font-weight: bold; color: #000000; } } ``` 다음은 `home`에 대한 `scss`를 적용해보겠습니다. ```scss #content { h1, h2, h3, h4 { size: 26px; text-align: left; } a { color: #000000; text-decoration: none; } p { a{ color: #3081f7; text-decoration: solid underline; } } .category { list-style: none; padding: 0px; margin: 20px 0; li { display: inline-block; margin-right: 10px; a.category-link { display: block; width: 66px; height: 40px; border: 1px solid #e6e6e6; border-radius: 100px; background-color: #FFFFFF; font-size: 14px; line-height: 40px; text-align: center; color: #000000; text-decoration: none; &.active { border: none; background-color: #000000; color: #FFFFFF; &:hover { background-color: #000000; transition: none; } } &:hover { background-color: #f0f0f0; transition: all 0.5s ease-out; } } } } .post-list { display: flex; flex-wrap: wrap; list-style: none; padding: 0px; margin: 0px; gap: 24px; } .post { width: calc(25% - 18px); &:hover { .teaser { border: 1px solid #cccccc; transition: all 0.5s ease-out; } .title { text-decoration: underline; } } } .teaser { display: flex; flex-direction: column; justify-content: space-between; height: 55%; border: 1px solid #e6e6e6; border-radius: 8px; transition: all 0.5s ease-out; overflow: hidden; img { width: 100%; height: 100%; object-fit: cover; border-radius: 8px; } } .date { color: #666666; font-size: 12px; } .title { color: #000000; font-size: 18px; :hover { text-decoration: underline; } } .description { p { display: inline-block; color: #666666; font-size: 14px; margin: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; white-space: normal; line-height: 1.2; max-height: 42px; text-align: left; word-wrap: break-word; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; } } } ``` 위 코드는 다음과 같은 역활을 합니다. `content`에 표시되는 `page title`의 글자 크기를 26px로 지정하고, 왼쪽 정렬하게 만듭니다. `category`가 `active`일 때 검정색으로 나오게 만들고 `hover` 시 `ease-out` 효과와 함께 `#f0f0f0`으로 표시되게 만듭니다. `post`의 간격을 8px로 설정하고 `post`에 `hover` 시 teaser의 `outline`에 애니메이션과 색 변환을 합니다. 이 외에도 모든 스타일링에 관여합니다. 코드블럭을 조금 더 이쁘게 강조하고 싶다면, [Rouge Theme Preview Page](https://spsarolkar.github.io/rouge-theme-preview/)를 사용하여서 자신이 원하는 테마를 찾고 적용하면 됩니다. # 마무리 --- 이렇게 제가 `Jekyll`를 활용해 블로그를 만든 경험을 공유해 보았습니다. 아직 블로그가 완성되었다고 보기에는 어려운 부분이 많습니다. 아직 `paginate`도 적용하지 못하였고, 검색바도 완성하지 못하였고 광고 등 제가 원했던 기능들을 귀찮거나 어려워서 아직 넣지 못하였는데, 블로그를 일단 어느 정도 완성시킨 후 시간이 날 때마다 관련 내용을 포스팅하며 완성시키는 것도 좋을 것 같아 필수적인 부분들만 완성해 보았습니다. 아직 블로그에 무엇을 주제로 올릴지 결정하지 못해 블로그가 조금 난해해질 수도 있는데, 이쁘게 완성시킨 블로그인 만큼 천천히 시간을 들여가며 이쁘게 사용해 보겠습니다. 긴 글 읽어주셔서 감사합니다!