Transcript
00:00:00감사합니다.
00:00:30네, 안녕하세요 여러분. 오늘 Adonis.js에 관한 스트림에 오신 것을 환영합니다. 재미있을 것 같네요. 제가 한 번도 써본 적 없는 흥미로운 프레임워크이자 라이브러리입니다. 항상 써보고 싶었기에 이번 스트림에서 한번 다뤄보려고 합니다.
00:01:00잠시만 정리 좀 할게요.
00:01:07모두 잘 지내시길 바랍니다. 함께해주셔서 감사합니다.
00:01:16자, 그럼 시작해 보죠. 네, 여러분 안녕하세요. 오늘 저는 아도니스(Adonis)에 대해 좀 더 깊이 알아보고 탐구해 보려고 합니다. 그냥 재미삼아서 하는 건데요, 아도니스JS는 다른 프레임워크와는 꽤나 다른 자바스크립트 프레임워크거든요.
00:01:38물론, 지금은 2019년이 아니죠. 그러니 요즘 자바스크립트 프레임워크가 얼마나 중요한지 논할 수도 있겠죠, 그렇죠? 매일 새로운 프레임워크가 쏟아져 나오던 프레임워크 전쟁의 시대는 끝났으니까요.
00:01:54오늘날은 온통 AI 이야기뿐이죠. 하지만 요즘 다들 AI만 이야기하니까, 저는 반대로 AI와는 전혀 관련 없는 주제로 라이브 스트리밍을 해보면 어떨까 싶었습니다.
00:02:08아도니스는 꽤 흥미로운 프레임워크이자 라이브러리입니다. 말씀드렸듯이 직접 써본 적은 없지만, 어떤 것인지는 알고 있죠. 꽤 오랜 기간 느슨하게나마 지켜봐 왔거든요.
00:02:20결국 아도니스는 '자바스크립트용 라라벨(Laravel)'이라고 생각합니다. 제가 이해하고 있는 아도니스는 그렇습니다. 풀스택 프레임워크이고, 리액트 프레임워크들이 풀스택이 되기 전부터 이미 존재했죠.
00:02:40그러니까... 넥스트JS(Next.js)가 나오기 전에 출시되었는지까지는 확실하지 않지만, 넥스트JS가 엄청난 인기를 얻기 전부터 있었다고 할 수 있겠네요.
00:02:51네, 아도니스는 정말 흥미로운 기능들을 많이 내장하고 있어요. 오늘 제 계획은 공식 소개 가이드를 따라가면서 무엇이 들어있는지 살펴보고, 직접 이것저것 해보면서 어떻게 작동하는지 알아보는 겁니다.
00:03:10아, 구글 AI 플랜의 새로운 컴퓨터 기반 할당량에 대한 댓글이 있네요. 관련 내용을 읽어본 것 같긴 한데, 자세히 살펴보지는 못해서 딱히 코멘트할 게 없네요.
00:03:24와, 이건 꽤 큰 변화네요. 자, 봅시다. 아도니스가 뭐죠? '백엔드 우선(back-end first)' 타입 세이프 프레임워크군요. 백엔드 우선이긴 하지만, 풀스택 기능도 갖추고 있다는 건 알고 있습니다.
00:03:37라라벨을 아신다면 아시겠지만, 아도니스로도 뷰(view)를 렌더링할 수 있죠.
00:03:42Node.js와 타입스크립트로 웹 애플리케이션을 구축하는 데 필요한 핵심 빌딩 블록을 제공하며, 외부 라이브러리 없이도 완전한 백엔드를 작성하고 유지 관리할 수 있게 해줍니다.
00:03:52아까 말씀드렸듯이, 라라벨처럼 단순히 리액트 컴포넌트를 서버에서 렌더링하는 기능을 주는 Next.js 같은 풀스택 프레임워크 그 이상입니다.
00:04:06다소 거친 요약일 수도 있지만, 그게 Next.js의 핵심 아이디어라고 할 수 있죠.
00:04:12라우팅 등도 지원하지만, Adonis는 라라벨처럼 더 많은 것을 제공합니다.
00:04:16별도의 외부 라이브러리 없이도 인증 기능이 내장되어 있습니다.
00:04:21파일 업로드, 캐싱, 속도 제한 등을 지원하며 훨씬 더 많은 기능을 제공하죠.
00:04:26고유의 ORM, 즉 객체 관계 매핑도 내장되어 있습니다.
00:04:33SQL 데이터베이스 등을 다루는 자체 래퍼죠.
00:04:35정말 강력하고 유능합니다.
00:04:38결국 풀스택 앱을 만들고 싶을 때 다른 외부 의존성을 많이 추가하지 않아도 Adonis.js 하나만으로 충분하다는 것이 큰 장점이죠.
00:04:47물론, 특히 요즘처럼 공급망 공격이 많은 시기에 제한된 의존성을 가진다는 건 정말 흥미로운 점입니다.
00:04:55물론 Adonis 자체가 공격당하면 위험하긴 하지만, 필요한 외부 의존성이 줄어든다는 것은 장점입니다.
00:05:03어이, Daki! 당신의 유명한 리액트 강의를 마치는 중이에요.
00:05:07순수 타입스크립트나 리액트 플러스 타입스크립트 다음에는 무엇을 배우는 게 좋을까요?
00:05:11네, 리액트와 타입스크립트를 같이 배우는 건 좋은 생각입니다.
00:05:12Next.js도 좋은 생각이죠.
00:05:14아니면 리액트 다음으로 리액트 네이티브를 배워 모바일 앱 개발로 넘어가는 것도 합리적인 다음 단계라고 생각합니다.
00:05:20다들 괜찮은 다음 단계가 될 거예요.
00:05:24더 긴말할 것 없이, 텍스트를 다 읽기보다는 바로 시작해 보죠.
00:05:28경로를 정합시다.
00:05:31여기서 배울 것들입니다.
00:05:33사실 시작해 보고 싶어요.
00:05:36한 가지 짚고 넘어갈 건, 세 가지 접근 방식입니다.
00:05:40Adonis.js는 프론트엔드를 구축하는 세 가지 주요 접근 방식을 지원합니다.
00:05:44오, 이건 중요하겠네요.
00:05:47각 방식은 뷰 레이어를 다루는 서로 다른 관점을 나타냅니다.
00:05:52하이퍼미디어.
00:05:52하이퍼미디어 애플리케이션은 서버에서 완전한 HTML 페이지를 생성하여 브라우저로 보냅니다.
00:05:57템플릿 엔진을 사용하여 인터페이스를 구축하죠.
00:06:00Adonis.js에는 자체 템플릿 엔진인 'Edge'가 내장되어 있습니다.
00:06:05그리고 Alpine.js와 같은 경량 자바스크립트 라이브러리를 사용하여 상호작용을 추가하는 방식이죠.
00:06:10필요하다면 HTMX나 Poly를 사용합니다.
00:06:12저는 이 방식을 사용해 보려고 합니다.
00:06:16물론, 라라벨 세계에서 온 Inertia.js를 사용하여 리액트를 프론트엔드로 사용할 수도 있습니다.
00:06:25이건 라라벨 진영에서 나온 건데,
00:06:28프론트엔드 싱글 페이지 애플리케이션과
00:06:32풀스택 애플리케이션의 백엔드를 이어주는 다리 역할을 합니다.
00:06:38그리고 당연히 REST API만 구축하는 백엔드로 사용할 수도 있고요.
00:06:46같은 컨트롤러에서 세 가지 다른 리턴 방식이 가능합니다.
00:06:49좋아요, 한번 보죠.
00:06:50Adonis에 내장된 라우터를 사용해 경로를 등록할 수 있습니다.
00:06:56여기가 컨트롤러네요.
00:07:02거기서 viewRender를 호출해 미리 정의한 뷰를 렌더링할 수 있습니다.
00:07:06이 특별한 구문은 Adonis에 포함된 Edge 템플릿 언어입니다.
00:07:16대안으로 Inertia를 사용할 수도 있는데, 역시 컨트롤러가 필요합니다.
00:07:20컨트롤러 안에서 뷰에 렌더를 호출하고 props를 전달할 수 있죠.
00:07:28네, 그 안으로 데이터를 넘기는 거죠.
00:07:30그리고 여기에 자바스크립트, 리액트 코드를 작성할 수 있죠.
00:07:34제가 알기로는 서버 사이드 렌더링이 될 겁니다.
00:07:37기본적으로 리액트 컴포넌트 내에서 데이터를 가져올 필요가 없죠.
00:07:42모든 게 알아서 처리됩니다.
00:07:44그것도 좋네요.
00:07:45하지만 제가 뭘 쓸지는 좀 더 봐야겠네요.
00:07:47둘 중 하나겠죠. 작은 풀스택 앱을 만들어보고 싶거든요.
00:07:50어떻게 될지 보죠.
00:07:51저는 아마 Edge 템플릿 엔진으로 시작해서 예전 방식대로 다중 페이지 애플리케이션을 만들 것 같아요.
00:07:57서버 사이드에서 HTML을 렌더링하는 방식이죠.
00:07:59모든 애플리케이션이 클라이언트 사이드 리액트가 필요한 건 아니니까요.
00:08:03그걸 이해하는 게 정말 중요하다고 생각해요.
00:08:05무엇을 만드느냐에 따라 다른 거죠.
00:08:07모든 앱이 엄청나게 반응형이고 인터랙티브한 프론트엔드가 필요한 건 아닙니다.
00:08:12예를 들어 블로그를 만든다면, 굳이 필요 없겠죠.
00:08:16더 복잡한 애플리케이션이라도 필요 없는 경우가 많을 겁니다.
00:08:20채팅창 내용을 잠깐 확인할게요.
00:08:22안녕하세요, Max.
00:08:23AI 엔지니어링 코스요?
00:08:24언젠가는 할 수 있겠지만, 지금은 상황이 너무 빨리 변해서
00:08:28강의를 내놓는 순간 이미 과거의 것이 될 것 같아요.
00:08:32그런 건 원치 않아요.
00:08:32그래서 오늘은 아닙니다.
00:08:35차라리 소프트웨어 기초 같은 강의를 먼저 만들고 싶네요.
00:08:39하지만 언젠가는 제가 AI를 어떻게 활용하는지 꼭 공유하고 싶습니다.
00:08:44지금처럼 매주 변하는 게 아니라, 어느 정도 안정된 시점에 말이죠.
00:08:48안녕하세요, Max.
00:08:48Adonis는 10년 넘게 유지되어 온 것으로 알고 있는데,
00:08:51틈새시장이라 사업적인 리스크가 있다고 생각하시나요?
00:08:55네, 정말 좋은 질문입니다.
00:08:57아주 오랫동안 유지되어 왔다는 건 알고 있습니다.
00:09:0110년이나 된 줄은 몰랐네요.
00:09:02하지만 정말 긴 시간이죠.
00:09:05Adonis 팀의 규모가 얼마나 큰지는 잘 모릅니다.
00:09:09지금 아주 잘 유지되고 있다는 건 확실해요.
00:09:13X(트위터)에서 메인 관리자, 즉 Adonis 프로젝트 소유자가 활발히 활동하는 걸 자주 보거든요.
00:09:20전 세계적으로 사용되지 않는 프로젝트에는 항상 어느 정도 위험이 따르기 마련이죠.
00:09:30하지만 그렇게 오랫동안 유지되어 왔다는 사실 자체가 관리자의 헌신을 증명하는 게 아닐까 합니다.
00:09:38그래도 Vercel의 지원을 받는 Next.js 같은 것이 장기적으로는 더 확실하게 유지될 가능성이 높다고 볼 수는 있겠죠.
00:09:50하지만 절대라는 건 없으니까요.
00:09:52Adonis는 Next.js가 갖지 못한 확실한 장점들이 있기도 하고요.
00:09:57하지만 분명 유효한 우려 사항입니다.
00:10:00라이브 방송 좋네요.
00:10:01프로그래밍 언어나 프레임워크에 대한 당신의 접근 방식이 좋고, Adonis는 처음 보는데 꽤 흥미롭네요.
00:10:05오늘 어떤 걸 얻게 될지 궁금합니다.
00:10:07저도 궁금하네요.
00:10:08참여해 주셔서 감사합니다.
00:10:09재미있을 거예요.
00:10:10화면 영역 강조 표시에는 어떤 도구를 쓰시나요?
00:10:12DemoPro라는 앱이에요.
00:10:15Mac 전용 애플리케이션입니다.
00:10:17구매한 지 아마 꽤 오래됐을 거예요.
00:10:21정말 훌륭하죠.
00:10:21화면에 직접 그릴 수 있게 해주는 기능들을 제공하거든요.
00:10:25네.
00:10:27아직도 왜 자바스크립트 커뮤니티에서 이걸 받아들이지 않는지 모르겠어요.
00:10:30의견이 분명한(opinionated) 프레임워크는 정말 좋잖아요.
00:10:33사람들이 Svelte나 Vue는 좋아하는데, 왜 Adonis는 아닐까요?
00:10:35글쎄요.
00:10:36저도 항상 궁금했던 점이에요.
00:10:37처음 Adonis를 봤던 게 한 7~8년 전쯤이었던 것 같아요.
00:10:44그때도 왜 더 유명해지지 않을까 생각했거든요.
00:10:48개인적으로 깊이 파볼 시간이 없었네요.
00:10:52그리고 결코 엄청나게 인기가 많았던 적도 없고요.
00:10:54그러다 보니 강의 주제로 삼을 기회도 없었죠.
00:10:59잘 모르겠네요.
00:11:00정말 괜찮아 보이는데 말이죠.
00:11:02어쨌든 시작해보면 얼마나 좋은지 알 수 있겠죠.
00:11:07자, 시작해 봅시다.
00:11:09네.
00:11:10물론 Node가 필요하겠죠. 새 애플리케이션을 생성하기 위해 npm create를 씁니다.
00:11:16복사할게요.
00:11:19작은 폴더를 이미 만들었어요.
00:11:21저는 npm 대신 더 빠르고 보안이 좋은 bun을 사용할 겁니다.
00:11:25이 폴더에서 생성할 수 있을까요?
00:11:27될까요?
00:11:29네.
00:11:29좋아요.
00:11:30이제 선택해야겠네요.
00:11:31하이퍼미디어 앱을 사용할까요?
00:11:33템플릿 엔진, 리액트, 뷰 앱 중에 말이죠.
00:11:38저는 하이퍼미디어로 가겠습니다.
00:11:39스타터 키트를 다운로드하고 의존성을 설치하며 데이터베이스를 마이그레이션 중입니다.
00:11:45기본 스타터 애플리케이션을 제공해주나 보네요.
00:11:53명령어 실패.
00:11:55Node ace migration run.
00:11:58어라.
00:11:59시작이 좋지 않네요.
00:12:01bun을 써서 그런가?
00:12:04아니면...
00:12:05최신 Node 버전인 Node 26을 사용해서 그럴 수도 있습니다.
00:12:12Node로 실행하려고 해서 문제가 생겼을지도 모르겠네요.
00:12:20한번 보죠.
00:12:21이렇게 실행할 수 있을까?
00:12:24좋아.
00:12:25오류, 예외가 발생했네요.
00:12:28이런, 맙소사.
00:12:29라이브 스트림에서 뭐 좀 시도하려고 하면 꼭 문제가 생기더라고요.
00:12:35Adonis bin console TS에서 startenv 모듈을 찾을 수 없대요.
00:12:45확인해 봅시다.
00:12:47Node 때문인가?
00:12:48더 낮은 Node 버전을 사용해 볼게요.
00:13:01아니네요.
00:13:02다른 오류가 떴어요.
00:13:08바인딩 파일을 찾을 수 없다고 하네요.
00:13:14허.
00:13:14어라.
00:13:15Node 버전 때문일 수도 있으니, 폴더 내용을 싹 다 지우고 다시 시도해 볼게요.
00:13:24이번엔 NPM으로 다시 만들어보고, 제발 공급망 공격 같은 건 당하지 않기를 바랄 뿐입니다.
00:13:34요즘은 NPM 쓰기가 정말 겁나네요.
00:13:38저는 BUN이나 PNPM을 선호하거든요.
00:13:42자.
00:13:43다시 해보죠.
00:13:44잘 되길 바라며.
00:13:52이 정도면 딱히 잘못될 것도 없어야 하는데 말이죠.
00:14:11명령어 실패.
00:14:12시작이 정말 엉망이네요.
00:14:19이거 알려진 문제인가요?
00:14:23혹시 다들 아는 건가?
00:14:27딱히 그런 것 같진 않네요.
00:14:36좋아.
00:14:37한번 보죠.
00:14:38AI한테 물어보는 것도 방법이죠.
00:14:43해결할 수 있을지 보죠.
00:14:46요즘 제가 가장 좋아하는 코딩 에이전트인 Pi를 실행할게요.
00:14:57이 프로젝트에서 Adonis를 시작하려고 해요.
00:15:02실행했죠.
00:15:03명령어가 뭐였더라?
00:15:04NPM create this.
00:15:09알겠어요.
00:15:10NPM create.
00:15:13Adonis.js 최신 버전.
00:15:17마이그레이션 실행 중에 실패했어요.
00:15:22수동으로 실행해도 안 되고요.
00:15:24오류 로그를 붙여넣어서 결과를 한번 보죠.
00:15:29좋은 아침.
00:15:30아니면 저녁인가요?
00:15:32여긴 오후네요.
00:15:34AI가 도와줄 수 있을지 보죠.
00:15:38그 에러 메시지를 처리할 수 있다면요.
00:15:41Adonis.js가 뭐죠?
00:15:42Adonis.js는 자바스크립트 프레임워크입니다.
00:15:44풀스택 프레임워크죠.
00:15:47자바스크립트계의 라라벨 같은 겁니다.
00:15:50라라벨을 아신다면요.
00:15:51즉, '배터리 포함(batteries-included)' 프레임워크입니다.
00:15:53Next와는 다르죠.
00:15:54Next.js나 주로 서버 라우팅과 렌더링에 집중하는 Tanstack Start와는 달라요.
00:15:59대신 인증 기능이 내장되어 있습니다.
00:16:01자체 ORM도 함께 제공되죠.
00:16:03그게 핵심입니다.
00:16:04지금은 초기 설정 고정 과정에서 몇 가지 문제에 직면해 있습니다.
00:16:10아, 그렇군요.
00:16:11그러니까, 그건 아니군요.
00:16:14알겠습니다.
00:16:15이해가 돼요.
00:16:16Adonis는 아니군요.
00:16:18아마도요.
00:16:19그런데 문제는 이 설정 명령어가 라이프사이클 스크립트를 실행하려고 했던 것 같아요.
00:16:28그러니까 의존성에 연결된 스크립트죠.
00:16:31공급망 공격 때문에 제가 ignore-scripts를 true로 설정해 놨거든요.
00:16:35Bun도 제가 알기로 기본적으로는 실행하지 않고요.
00:16:38그래서 실행이 필요한 스크립트가 있었던 모양입니다.
00:16:45그래서 AI가 이걸 일시적으로 비활성화했습니다.
00:16:49이제 마이그레이션을 실행했고요.
00:16:54좋아요.
00:16:57이제 초기 설정 단계에서 누락된 것이 없기를 바랍니다.
00:17:05확인해 봐야겠죠.
00:17:07이제 개발 서버를 실행해 볼 수 있으니까요.
00:17:15자, 해보죠.
00:17:19네, 여기서 저 브라우저는 쓰고 싶지 않아요.
00:17:22어디 봅시다.
00:17:24좋아요.
00:17:25화면에 뭔가 떴네요.
00:17:31좀 이상해 보이는데.
00:17:37원래 이렇게 보여야 하나요?
00:17:41허.
00:17:43알겠습니다.
00:17:45어쨌든.
00:17:50자, 어디 보자.
00:17:51여기서 가입할 수 있네요.
00:18:05이제 로그인했습니다.
00:18:07로그아웃도 가능하고요.
00:18:08이 모든 게 기본적으로 구현되어 있네요.
00:18:12안 생겨도 될 문제들이 항상 튀어나오죠.
00:18:15네.
00:18:16정말 전형적이에요.
00:18:17라이브 스트리밍에서 새로운 기술을 다뤄보려고 할 때마다 벌써 세 번째 이러는 것 같네요.
00:18:22결국 실패하고 말죠.
00:18:23그래도요.
00:18:23이제 잘 작동합니다.
00:18:25이제 아무 문제 없이 돌아가는 것 같아요.
00:18:31이 temp 폴더는 좀 신경 쓰이네요.
00:18:33여기에 제 프로덕션 데이터베이스가 저장되나요?
00:18:36아니면 개발 데이터베이스인가요?
00:18:37스키마요.
00:18:38사용자들.
00:18:39네.
00:18:39오케이.
00:18:40SQLite를 사용하고 있네요. 가볍고 단순해서 마음에 듭니다.
00:18:45여기 무엇이 있는지 잠시 후에 살펴보겠습니다.
00:18:48Udemy는 강사를 팔로우해서 새 콘텐츠가 나올 때 알 수 있는 기능을 추가해야 해요.
00:18:53그럼요.
00:18:54다른 강사들과 함께 Udemy에 추가하면 좋을 만한 쿨한 기능들에 대해 오랫동안 이야기해 왔거든요.
00:19:01하지만 뭐,
00:19:02그들은 별로 원하지 않는 것 같더라고요.
00:19:05AI를 쓰기 전에 스스로 문제를 해결하려고 노력하시는 모습이 좋네요.
00:19:08저는 첫 번째로 AI에게 복사해서 붙여넣기 할 것 같거든요.
00:19:11그럼 전 망한 건가요?
00:19:12보시다시피 제가 못 했을 때 AI가 해결해주었죠.
00:19:15하지만 저도 이 스트리밍이 디버깅이 아닌 Adonis에 대한 내용이기를 바랐기에 전체 에러 스택을 다 훑고 싶진 않았습니다.
00:19:25그래서 특히 긴 에러 메시지를 파싱하고 그 이유를 따져볼 때 AI가 정말 유용합니다.
00:19:31AI에게 넘기기 전에 최소한 잠깐이라도 에러 메시지를 직접 살펴보는 게 의미가 있다고 생각해요.
00:19:38왜냐하면 때로는 아주 쉽게 해결될 문제일 수 있거든요.
00:19:42포트 문제 같은 간단한 것일 수도 있고요.
00:19:45이번 경우는 아니었지만 다른 문제라면요.
00:19:47그리고 무엇이 진행 중이고 어떤 부분이 깨지는지에 대해 최소한의 아이디어를 가지고 있는 것이 결코 나쁘지 않으니까요.
00:19:58어쨌든, 무엇이 있는지 살펴봅시다.
00:20:01이 프로젝트에는 당연히 package.json 파일이 있고요.
00:20:08이 프로젝트를 구성하는 파일들에 대한 매핑 정보가 있습니다.
00:20:14그리고 Adonis 관련 의존성들도 있고요.
00:20:19Vine은 뭐죠?
00:20:24유효성 검사 라이브러리군요, 알겠습니다.
00:20:25유효성 검사 라이브러리가 있고, better-sqlite3, edge.js, 그게 템플릿 언어군요.
00:20:34Luxon은요?
00:20:39그건 또 뭐죠?
00:20:41날짜와 시간을 다루는 라이브러리군요.
00:20:44알겠어요. 그리고 assertion, 테스트 러너 타입, Alpine도 있네요.
00:20:54Alpine은 기본적으로 가벼운 클라이언트 측 자바스크립트 코드를 추가하기 위한 자바스크립트 라이브러리라서, 바닐라 자바스크립트를 직접 짤 필요가 없으면서도 React처럼 무거운 라이브러리를 쓸 필요도 없죠.
00:21:05아, Adonis rc.ts는 설정 파일인 것 같네요. 실험적 플래그, 명령어들, ace 명령어 목록이 있네요.
00:21:15네, 마지막으로 라라벨로 작업한 지 꽤 오래됐네요.
00:21:202014년, 15년, 16년쯤 라라벨 개발을 많이 했었는데, 기억하기로 라라벨은 Adonis처럼 기능이 아주 많았고 자신만의 명령어를 등록할 수 있게 해줬습니다.
00:21:38라라벨에서는 artisan 명령어였던 것 같은데, 여기서는 Node로 실행하는 ace 명령어인 것 같네요.
00:21:49즉, Adonis가 제공하는 도구이고, 자신만의 하위 명령어를 등록할 수 있는 것 같습니다. 그리고 파일들을 직접 가져와서 등록할 수도 있고요.
00:22:05예를 들어 myFile.ts 같은 곳에서 나만의 유틸리티 명령어를 등록하는 거죠.
00:22:15서비스 공급자(Service Provider)를 가져오고 등록하는 걸 보니, 웹 서버가 시작될 때 의존성 주입과 관련하여 다양한 서비스가 작동하도록 등록하는 부분 같네요.
00:22:26여긴 무엇이 있나요?
00:22:28여긴 무엇이 있나요?
00:22:28데이터베이스 제공자, 인증 제공자가 있네요. 여러 기능들을 위한 공급자들이죠.
00:22:34Preload도 있고, 그렇군요. 여기가 설정 파일이네요. 이해했습니다.
00:22:40또 뭐가 있죠?
00:22:41포트 등을 설정하는 env 파일이 있고, 로그 레벨, 앱 키도 있네요.
00:22:50비밀번호 해싱이나 다른 용도로 쓰이는지 확실하진 않지만요.
00:23:01세션 드라이버 쿠키도 있네요. 인증을 위해 쿠키를 사용하는군요. 데이터베이스 설정도 있고요.
00:23:12Git 무시.
00:23:14temp 폴더, 네.
00:23:16테스트 폴더, 유닛 테스트가 설정되어 있네요.
00:23:23Resources 폴더, 라라벨이랑 비슷하네요.
00:23:27Laravel에도 클라이언트 측 리소스를 담은 resources 폴더가 있었죠. 여기도 마찬가지로 클라이언트 측 CSS와, 말씀드렸던 Alpine을 사용한 JavaScript 코드가 들어 있습니다.
00:23:40views는 기본적으로 프론트엔드 페이지나, 페이지로 렌더링될 템플릿, 그리고 모든 컴포넌트가 들어있는 것 같네요.
00:23:49하지만 이 템플릿 시스템이 어떻게 작동하는지는 아직 잘 모르겠습니다.
00:23:53이 Edge 템플릿 언어를 위한 확장 프로그램을 설치할 수 있는지 빨리 확인해 봐야겠네요. 공급망 공격은 당하지 않길 바라야죠.
00:24:02Edge 템플릿 지원, 여기 있네요. Adonis.js에서 만든 공식 Edge 템플릿 구문 강조 프로그램입니다.
00:24:09설치해 보죠.
00:24:12아, 제발 해킹은 당하지 말아야 할 텐데.
00:24:16좋네요, 이제 좀 낫네요.
00:24:18이제 구문 강조가 적용되었습니다.
00:24:20템플릿 언어의 개념은, 예전에는 다른 JavaScript 프레임워크에서도 템플릿 언어를 사용하는 게 꽤 흔했죠.
00:24:32기본적으로 서버에서 HTML 페이지를 렌더링하고, 완성된 HTML 코드를 클라이언트로 보내는 방식이죠.
00:24:39더 편리하고 동적으로 만들기 위해 HTML 파일을 여러 템플릿으로 구성하고, 그 템플릿 안의 플레이스홀더를 동적 값으로 교체하는 겁니다.
00:24:51예를 들어, pages 폴더 안에 있는 이 홈페이지는 레이아웃에 기반하고 있네요.
00:25:02따로 지정하지 않으면 어디엔가 등록된 기본 레이아웃을 사용하겠죠.
00:25:09이 부분은 그 레이아웃에 주입되는 거고요.
00:25:12레이아웃에는 플레이스홀더들이 있겠네요.
00:25:14어디 봅시다, components 폴더에 레이아웃이 정의되어 있군요.
00:25:20여기가 레이아웃 파일입니다.
00:25:22HTML 기본 뼈대가 보입니다.
00:25:24body 태그 안에 main 슬롯이 있네요.
00:25:29여기가 실제 페이지 콘텐츠가 렌더링될 자리를 정의하는 Edge 템플릿 언어 구문인 것 같네요.
00:25:39이 언어가 어떻게 작동하는지 아직은 잘 모르겠지만요.
00:25:42읽으면서 이해해보려 합니다.
00:25:44이름을 지정할 수 있는 것 같기도 하고요.
00:25:47혹은 예약어일지도 모르죠.
00:25:49잘 모르겠습니다.
00:25:50async네요.
00:25:51흥미롭군요.
00:25:52await하고 있고요.
00:25:53여기가 렌더링될 때까지 레이아웃 렌더링을 끝내지 않는 거죠.
00:25:57slots.main이군요.
00:25:59확실히 예약어인 것 같습니다.
00:26:01그 외에도 라라벨에서 봤던 파셜(partials) 개념도 있네요. 레이아웃뿐만 아니라 다른 컴포넌트들을 가져와서 페이지에 삽입하는 건 흔한 방식이죠.
00:26:18헤더 파셜, 플래시 알림 파셜 등이 보입니다. 화면에 보여줄 경고 메시지용이겠죠.
00:26:26예를 들어, 헤더 파셜은 partials 폴더의 header 파일에서 찾을 수 있습니다.
00:26:33자, 헤더를 열어보죠.
00:26:35링크를 렌더링하기 위한 템플릿 구문이 보이네요.
00:26:40링크가 이렇게 렌더링되는 건 동적이기 때문입니다.
00:26:43내부 링크라면 라우트 등록 정보에 의존하겠죠.
00:26:47홈 라우트로 이동하는 '홈'이라는 텍스트의 링크를 설정하고 있네요.
00:26:52확인할 수 있습니다.
00:26:54어디서 볼 수 있죠?
00:26:55하단에서 볼 수 있나요?
00:26:58아니면,
00:26:59이거네요.
00:26:59SVG 파일이군요.
00:27:01이게 그 SVG인 것 같네요.
00:27:04홈이라는 이름의 대체 텍스트가 있고요.
00:27:06클릭하면 홈 라우트로 이동하죠.
00:27:13사용자가 로그인했는지 여부에 따른 조건부 렌더링도 있네요.
00:27:19말이 되네요.
00:27:20아직 헤더 안에 있습니다.
00:27:23오케이.
00:27:23여기에 @vite라고 되어 있네요.
00:27:26그러니까, 프런트엔드 에셋을 번들링하고 관리하는 데 Vite를 사용하고 있는 것 같네요.
00:27:35그리고 최적화되고 번들링된 app.js와 app.css 파일을 여기로 주입하는 것 같고요.
00:27:45더 구체적으로는, resources 폴더 아래의 JS와 CSS에서 그걸 찾을 수 있겠네요.
00:27:49그러니까 저 JavaScript를 CSS 파일로 옮기는 거죠.
00:27:53처리되는 건지는 잘 모르겠지만요.
00:27:57알겠어요.
00:27:58메인 개발 서버를 시작하면 Vite 서버도 자동으로 실행되겠죠.
00:28:05좋습니다.
00:28:06이해가 돼요.
00:28:06모든 걸 다 이해한 건 아니지만요.
00:28:08스택 관련 내용은 디버깅용인 것 같네요.
00:28:11잘 모르겠어요.
00:28:12더 많은 컴포넌트가 있군요.
00:28:15그리고 네.
00:28:16더 파봐야겠습니다.
00:28:17정확히 무슨 일이 일어나는 건지 말이죠.
00:28:19나중에 천천히 하죠.
00:28:21채팅으로 돌아가겠습니다.
00:28:22질문들이 좀 있네요.
00:28:24최신 LLM 모델들은 사용하기 더 비싸지고 더 이상 보조금도 안 나오는데,
00:28:28오픈 소스나 자체 호스팅 모델이 더 중요해질까요?
00:28:31그 결과로 개발자들이 DevOps를 배워야 할까요?
00:28:35앞으로 오픈 모델이 더 중요해질 거라고 봅니다.
00:28:42하지만 직접 실행하려면 역시 비용이 들겠죠.
00:28:45매우 고사양 장비를 갖춰야 하거나,
00:28:48예를 들어 1만 달러짜리 Mac Studio 같은 거요.
00:28:52아니면 다시 대여해야 하니까요.
00:28:53그러니까 비용은 항상 들기 마련입니다.
00:28:56하지만 프론티어 모델 가격이 비싸짐에 따라 오픈 모델이 흥미로운 대안이 될 수 있겠죠.
00:29:03무엇을 하려는지에 따라 다르겠지만, 아주 뛰어난 오픈 모델이 아직은 많지 않거든요.
00:29:10하지만 결국 그렇게 되겠죠.
00:29:12그렇다고 DevOps를 꼭 배워야 한다고는 생각 안 합니다.
00:29:16그냥 그 분야 자체에 관심이 있다면 배우시는 게 좋겠죠.
00:29:19하지만 오픈 모델을 직접 배포하고 운영하는 건 하드웨어가 있거나,
00:29:25VPS를 빌려서 한 번씩 해보는 정도라면 모를까요.
00:29:28한 번 제대로 설정하는 법만 익히면 됩니다.
00:29:32일반적으로 DevOps를 깊게 배울 필요는 없다고 봅니다.
00:29:36아, 네, 제 Flutter 강의를 들어주셔서 감사합니다.
00:29:41멋진 언급을 해주신 Don Solid 님, 감사합니다.
00:29:47그리고 이 도구는 왜 사용해야 하나요? 그냥 AI 서비스를 직접 쓰는 게 낫지 않나요?
00:29:51어떤 도구를 말씀하시는지 잘 모르겠네요.
00:29:54혹시 새 강의를 Udemy에 올릴 계획이 있으신가요?
00:29:57아직도 Udemy 강의를 하시나요?
00:30:01가끔 하긴 합니다.
00:30:02하지만 지금 Udemy의 상황이 아주 좋은 편은 아닙니다.
00:30:07Coursera 인수 건 등 앞으로 어떻게 돌아갈지 지켜봐야 할 것 같아요.
00:30:14그리고 콘텐츠 보안 정책(CSP)과 관련해서는, 제가 생각하기에 해당 레이아웃으로 가서,
00:30:22그냥 head 섹션에 필요한 내용을 추가하면 될 겁니다.
00:30:25어차피 결국은 HTML이니까 그냥 거기에 추가하시면 됩니다.
00:30:32그러면 작동할 거예요.
00:30:34물론 저는 이제 막 Adonis를 시작한 단계지만요.
00:30:42좋아요, 그럼 이건 됐고.
00:30:44프론트엔드나 리소스 쪽은 일단 넘어가도록 하죠.
00:30:48start 폴더를 살펴봅시다.
00:30:50나머지를 다 둘러보지 않았으니 이게 서버 측 부분일 것 같네요.
00:30:56더 있거든요.
00:30:57마이그레이션이 포함된 database 폴더가 있습니다.
00:31:00다른 프레임워크와 마찬가지로 여기서도 마이그레이션 파일을 통해 데이터베이스 테이블을 정의하는 방식입니다.
00:31:08이런 형식을 사용하는 것 같군요.
00:31:12마이그레이션 파일을 자동으로 생성해주는 명령어들도 당연히 있을 겁니다.
00:31:17그리고 해당 마이그레이션을 실행해서 데이터베이스에 적용하고 테이블과 스키마를 설계하게 되죠.
00:31:24스키마 TS 파일이 있네요.
00:31:28데이터베이스 테이블을 클래스 형태로 설정하는 것 같습니다.
00:31:33아마 특정 명령어를 통해 프로그래밍 방식으로 마이그레이션을 생성하겠죠.
00:31:40설정 관련 파일들이 굉장히 많네요.
00:31:43이것저것 설정할 수 있는 것들이 많군요.
00:31:50나중에 필요할 때 확인해보면 될 것 같습니다.
00:31:53bin 폴더의 server TS 파일은 HTTP 서버 진입점입니다.
00:31:57서버 TS 파일은 Adonis.js HTTP 서버를 시작하기 위한 진입점입니다.
00:32:02이 파일을 직접 실행하거나 serve 명령어를 사용할 수 있습니다.
00:32:05개발 서버를 시작할 때 serve 명령어를 사용했으니 그때 이 파일이 실행된 거죠.
00:32:13여기서 뭘 하는지 볼까요?
00:32:18임포터와 이그나이터(igniter)가 있네요.
00:32:23기본적으로 서버를 부팅하고 포트에서 대기하는 역할을 합니다.
00:32:27분명 어딘가에 라우트를 등록하고 있을 겁니다.
00:32:34console 파일은 Adonis.js 명령줄 프레임워크를 부팅하기 위한 진입점입니다.
00:32:38사용자 정의 명령어를 등록하거나 내장 명령어를 ace 명령어로 실행할 때 사용하겠죠.
00:32:45그다음 앱 폴더를 보면,
00:32:46시작 관련 요소들을 여기서 등록하는 것 같습니다.
00:32:49start 폴더가 흥미롭네요.
00:32:51start 폴더 안에 routes TS 파일이 있습니다.
00:32:54이 파일에서 애플리케이션의 라우트를 명확하게 등록하네요.
00:33:00슬래시 경로처럼 말이죠.
00:33:02도메인 뒤에 아무것도 없는 경로죠.
00:33:04홈 페이지를 렌더링합니다.
00:33:06리소스 뷰 폴더의 경로를 참조하고 있네요.
00:33:12그러니까 resources/views 안쪽입니다.
00:33:15render pages home이라고 하면 여기 pages 폴더로 이동하게 되는 거죠.
00:33:20그 안에서 홈 페이지를 렌더링하고요.
00:33:23본질적으로 여기서 일어나는 과정은 이렇습니다.
00:33:28라우트를 그룹화할 수도 있네요.
00:33:31왜 그룹화를 할까요?
00:33:33공통 미들웨어를 적용하기 위해서겠죠?
00:33:35게스트 미들웨어 같은 것들요.
00:33:38무슨 기능을 하든 간에요.
00:33:40가입 및 로그인 라우트가 여기 있네요.
00:33:44인증되지 않은 사용자만 접근할 수 있도록 하는 미들웨어인 것 같습니다.
00:33:49반대로 인증된 사용자만 접근할 수 있는 라우트를 보호하기 위해 auth 미들웨어를 쓰기도 하죠.
00:33:56로그아웃 라우트처럼 인증된 상태여야만 의미가 있는 경우 말입니다.
00:34:00라우트를 등록하는 방법은 직접 뷰를 렌더링하거나, Laravel에서도 그랬듯이 컨트롤러와 메서드를 라우트에 연결하는 것이 더 일반적인 철학으로 보입니다.
00:34:21가입 경로를 보면, get과 post 라우트가 있고 같은 컨트롤러 파일을 사용하지만, 생성(create)과 저장(store)을 담당하는 각각 다른 컨트롤러 메서드를 타겟으로 합니다.
00:34:35컨트롤러 파일을 보면 adonis.js 서버 쪽에 위치해 있네요.
00:34:47네, 그런데 이건 동적으로 생성된 것 아닌가요?
00:34:51우리가 직접 만들었나요?
00:34:53안 만들었나?
00:34:55아니요, 컨트롤러를 여기서 등록하는군요.
00:34:59동적으로 생성되는 걸로 생각됩니다.
00:35:01자, 여기 NewAccountController가 있네요.
00:35:04클래스가 이렇게 정의되어 있습니다.
00:35:08그리고 그 안에 create 메서드와 store 메서드가 있네요.
00:35:12결국 이 메서드들이 해당 작업을 담당하는 거죠.
00:35:15이것도 어떻게든 동적이거나 자동으로 생성된다고 봅니다.
00:35:21create 메서드(get 라우트)에서는 단순히 뷰를 렌더링하고요.
00:35:25이론적으로는 이걸 사용하지 않고 직접 get 요청에 처리할 수도 있지 않을까 싶은데,
00:35:41가능한지 모르겠네요. 컨트롤러를 거치지 않고 바로 렌더링할 수는 없나요?
00:35:46무조건 컨트롤러를 써야 하나요?
00:35:50그런 것 같네요.
00:35:51하지만 어차피 렌더링 방식은 똑같네요.
00:35:56Post 라우트에서는 내장 유효성 검사기를 사용하여 사용자 입력을 검증합니다.
00:36:04그리고 User 모델을 통해 사용자 인스턴스를 생성하죠. 그건 나중에 더 다룰게요.
00:36:11그 후 사용자를 웹 애플리케이션에 인증시킵니다.
00:36:15세션 및 쿠키 기반 인증을 하는 것 같군요.
00:36:18그런 다음 홈 라우트로 리다이렉트합니다.
00:36:21한번 볼까요?
00:36:24Models 폴더가 있네요.
00:36:26거기에 User 모델이 정의되어 있습니다.
00:36:28앞서 데이터베이스 테이블과 스키마에 대해 언급했었죠.
00:36:40아마 모델만 정의하면 나머지는 자동으로 생성되는 것 같지만, 좀 더 살펴보죠.
00:36:47결국 여기에서 애플리케이션에서 사용할 User를 정의하는 겁니다.
00:36:53그리고 Adonis에서 제공하는 기능을 확장하고요.
00:36:57여기 getter인 initials가 있네요.
00:37:03이름과 성을 결합해서 전체 이름을 가져오는 간단한 헬퍼 함수입니다.
00:37:10계산된 값을 이런 식으로 만들 수 있다는 걸 보여주네요.
00:37:15오케이, 알겠습니다.
00:37:17사용자 검증(Validators) 부분이군요.
00:37:19이름은 생소하지만 Wine이라는 라이브러리를 사용해서 이메일 형식이 올바른지, 길이는 적절한지 등을 검증합니다.
00:37:31잠시만요.
00:37:36가입 시 특정 값을 강제하기 위해 어디서든 재사용할 수 있는 검증 로직을 만들 수 있는 것 같군요.
00:37:49Middleware의 AuthMiddleware는 핸들 메서드를 가진 클래스인데, 여기서 인증을 확인하고 통과하면 next를 반환해서 요청한 라우트로 접근하게 해줍니다.
00:38:07인증에 실패하면 에러를 던져서 다음 이동을 막는 것 같네요.
00:38:14GuestMiddleware는 정반대일 겁니다.
00:38:21사용자가 이미 인증되었는지 확인하고 인증되었다면 리다이렉트합니다.
00:38:28인증되지 않은 경우에만 원래 가려던 경로에 접근하도록 허용하죠.
00:38:32오케이.
00:38:33Exceptions 폴더에서는 우리만의 커스텀 에러를 정의할 수 있습니다.
00:38:38오케이.
00:38:40오케이.
00:38:42자.
00:38:45가까운 시일 내에 계획 중인 새로운 강의는 무엇인가요?
00:38:52아마 BUN(번) 관련 강의를 할 수도 있겠네요.
00:38:55이 강의가 만족스러울지 아직 고민 중입니다.
00:38:58이미 녹화한 내용은 있지만 품질이나 방향성이 마음에 드는지 확인하고 싶어서요.
00:39:06소프트웨어 공학 기초나 시스템 디자인 관련 강의도 올해 안에 만들고 싶습니다.
00:39:12에이전트 AI 강의는 잘 팔리긴 하겠지만 앞서 말했듯이 고민이 있어요.
00:39:20제가 에이전트 엔지니어링을 어떻게 하는지, AI와 어떻게 작업하는지 공유하는 강의를 꼭 만들고 싶습니다.
00:39:26문제는 이 분야가 너무 빠르게 변한다는 거죠.
00:39:30지금 당장 강의를 만드는 건 별로 유용하지 않을 것 같아요.
00:39:33조금 더 안정화되었다고 느껴지면 에이전트 엔지니어링이나 AI 엔지니어링 관련 강의를 꼭 만들고 싶습니다.
00:39:42puck.js처럼 보이네요.
00:39:44네.
00:39:45왜 2026년에 누군가 그걸 쓰려고 할까요?
00:39:48아무도 Vue(뷰)를 쓰지 않을 것 같아요.
00:39:51SPA가 대세니까요.
00:39:53저는 동의하지 않습니다.
00:39:56우리는 싱글 페이지 애플리케이션과 모든 곳에서의 React(리액트)에 너무 익숙해져 있어요.
00:40:01리액트는 훌륭하죠.
00:40:02그리고 AI가 리액트를 사랑한다는 건 분명한 사실이기도 합니다.
00:40:07하지만 Adonis는 일반적으로 꽤 니치한 편이죠.
00:40:10그렇다고 모든 곳에 리액트를 써야 한다고 생각하는 건 잘못된 가정이라고 봐요.
00:40:17서버에서 템플릿을 렌더링하는 것만으로도 충분할 때가 많거든요.
00:40:23그걸로 충분합니다.
00:40:24리액트를 추가하면 복잡성과 번들 사이즈만 더 커질 수 있고요.
00:40:30최근 몇 주간 발생한 보안 취약점들을 생각해보세요.
00:40:35익숙하다는 이유만으로 불필요한 것을 도입하지 않는 데에도 분명 가치가 있습니다.
00:40:41우리는 모든 곳에 리액트를 사용하는 데 너무 익숙해져서, 당연히 써야 할 표준 옵션으로 받아들이고 있죠.
00:40:47전 그렇지 않다고 생각합니다.
00:40:49물론 동의해요.
00:40:50이건 확실히 좀 구식처럼 보이긴 하죠.
00:40:53하지만 제가 말했듯이 저도 수년 전에 이런 식으로 페이지를 작성했었습니다.
00:41:00그래도 오늘날 틀린 방식이라고 하기는 어렵습니다.
00:41:03분명 이례적이고 네이티브처럼 느껴지거나 상식적인 방법처럼 보이진 않죠.
00:41:12하지만 충분히 의미가 있을 수 있다고 봅니다.
00:41:14모든 것을 고려했을 때, 이전에도 말했듯이 Adonis는 다양한 뷰 렌더링 방식을 지원합니다.
00:41:23Inertia.js를 다리로 사용하여 React를 프론트엔드로 지원하기도 하고요.
00:41:29그러니 이런 뷰 기반 접근 방식 없이도 Adonis.js 풀스택 애플리케이션을 완벽하게 구축할 수 있습니다.
00:41:38하지만 저는 어떻게 보이는지 확인하고 싶어서 먼저 살펴본 것뿐입니다.
00:41:43Hano랑 좀 비슷하게 생겼네요.
00:41:45네, Hano가 훨씬 가볍죠, 안 그런가요?
00:41:48Hano는 인증이나 ORM 같은 기능들이 내장되어 있지 않으니까요.
00:41:56Adonis.js는 어떠신가요?
00:42:00흥미롭긴 한데, 전에는 전혀 사용해본 적이 없어서요.
00:42:03오늘 처음 탐색해보는 중입니다.
00:42:05이제 막 시작했거든요.
00:42:07하나의 프레임워크 안에 모두 포함되어 있다는 아이디어가 맘에 들어요.
00:42:13요즘 같은 공급망 공격이 많은 시대엔 특히 더요.
00:42:16게다가 자바스크립트 생태계에서는 너무 복잡한 솔루션을 택하는 경향이 있다고 생각합니다.
00:42:21수십 개의 라이브러리를 가져와 엮는데, 그건 공급망 공격 위험 외에도,
00:42:26모든 라이브러리가 항상 잘 관리되지는 않는다는 문제가 있죠.
00:42:31그러니 모든 게 다 갖춰진 '배터리 포함' 프레임워크가 분명한 장점이 있다고 생각합니다.
00:42:39기본 지식을 갖춘 컴퓨터 공학 학생들에게 어떻게 프로그래밍을 배우라고 추천하시나요?
00:42:44다음 단계는 무엇인가요?
00:42:45프로젝트를 만드는 것일까요, AI를 탐색하는 것일까요?
00:42:46저는 학습을 위해 AI를 활용할 것 같아요.
00:42:48AI의 도움을 받아 프로젝트도 만들겠지만, AI만 전적으로 의존하진 않을 겁니다. 왜냐하면,
00:42:53그렇게 하면 아무것도 배울 수 없으니까요.
00:42:54소프트웨어 공학 기초를 배우려고 노력할 것 같습니다.
00:42:57코드를 직접 손으로 한 줄 한 줄 작성해보고요.
00:43:01AI가 생성한 모든 코드를 검토하고 제대로 이해하려고 노력할 겁니다.
00:43:05비판적으로 질문도 던지면서요.
00:43:07코드에 대해 AI와 논의하는 용도로 쓸 수도 있겠죠.
00:43:10하지만 솔직히 말씀드리면 저도 요즘 AI를 활용해 어떻게 가장 잘 가르치고 배울 수 있는지 알아가는 중입니다.
00:43:15배우고 있는 단계죠.
00:43:20AI에게 물어보면서 배울 수 있게 프로젝트를 어떻게 만드느냐는 거죠?
00:43:27네.
00:43:27AI를 스파링 파트너로 활용할 것 같습니다.
00:43:32알겠습니다.
00:43:32자, 한번 보죠.
00:43:34아까 이야기한 대안들도 확인해보고 싶거든요.
00:43:38그러고 나서 코드를 수정해보죠.
00:43:40일단 대안을 살펴볼 겁니다.
00:43:42만약 제가...
00:43:47다시 만들어 보겠습니다.
00:43:49처음부터 다시 하고 싶거든요.
00:43:51다시 만들게요.
00:43:52서버를 멈추고,
00:43:53React 키트를 사용하는 대안적인 접근 방식을 시도해봅니다.
00:44:01이제 또 충돌할지도 모르겠네요.
00:44:08잠시만 확인해보죠.
00:44:15제대로 작동하게 하려면 어떤 명령어를 실행해야 하더라?
00:44:19Permanent.
00:44:20영구적인 건 원하지 않아요.
00:44:27이게 아마 될 겁니다.
00:44:32봅시다.
00:44:36봅시다.
00:44:37웁스.
00:44:38그건 하려던 게 아닌데.
00:44:39점 하나면 충분합니다.
00:44:42좋아요.
00:44:44잘 작동하는지 봅시다.
00:44:55바지에 슈바르츠뮐러(Schwarzmullering)를 하다니.
00:44:57좋은 건지 나쁜 건지 모르겠네요.
00:45:09제 Flutter 강의를 처음부터 직접 디자인했냐고요?
00:45:11네.
00:45:12모두 제 작업이죠.
00:45:14자, 이제 다시 시작해 봅시다.
00:45:21똑같이 보이는지 확인해 보죠.
00:45:24네.
00:45:25같은 앱이네요.
00:45:26하지만 당연히 파일 구조는 달라졌을 겁니다.
00:45:29어디 봅시다.
00:45:32앱 폴더.
00:45:36이제 transformer(변환기)가 생겼네요.
00:45:38하지만 그건 그냥 백엔드 관련 작업인 것 같아요.
00:45:42아니군요.
00:45:42서버에서 클라이언트로 데이터를 전송하기 위한 것 같아요.
00:45:46프론트엔드로 보내는 거죠, 한번 봅시다.
00:45:48bin, config, database, inertia 폴더가 있네요.
00:45:53오케이.
00:45:53Inertia가 이제 프론트엔드 폴더인 것 같네요.
00:45:56CSS.
00:45:57네.
00:45:57알겠습니다.
00:45:58여기 뭐가 있죠?
00:45:59app.tsx 파일이 있네요.
00:46:11뭔지는 정확히 모르겠지만, 프론트엔드를 하이드레이션하고 백엔드와 연결하기 위한 것 같네요.
00:46:18Inertia 앱을 생성하고,
00:46:20페이지 제목을 설정하는 것 같네요.
00:46:22앱.
00:46:23좋아요.
00:46:24스크립트 설정 파일이 어디 있죠? 에러가 표시되는데, 그냥 deprecated(구식)라서 그런 거니 괜찮아요.
00:46:29그건 괜찮습니다.
00:46:32서버 사이드 렌더링 TSX 파일이네요.
00:46:34그건 서버 사이드 렌더링 진입점이고, 이건 클라이언트 진입점이네요.
00:46:39오케이.
00:46:39Inertia가 어떻게 작동하는지, 이 2시간짜리 영상이 뭔지 전혀 모르겠네요.
00:46:46홈페이지가 여기 있네요.
00:46:47이제 일반적인 React 컴포넌트가 되었군요.
00:46:51별다른 건 없어요.
00:46:52레이아웃 같은 게 있나요?
00:46:53네, 레이아웃이 있네요.
00:46:54Default TSX 파일이요.
00:46:55이건 어디서 설정하죠?
00:46:56앱에서 설정하는 건가요?
00:46:59페이지 컴포넌트를 확인해 보죠.
00:47:00Pages 폴더를 보면,
00:47:03레이아웃, 레이아웃, 레이아웃, 레이아웃.
00:47:05레이아웃이 불러와지고 있네요.
00:47:07좋아요.
00:47:08그런 식으로 작동하는군요.
00:47:10여기에 레이아웃이 있어요.
00:47:12그리고 기본 레이아웃도 가져왔네요.
00:47:16좋아요.
00:47:16오, useEffect가 있네요.
00:47:19그건 금지인데.
00:47:24좋아요.
00:47:25네.
00:47:26정말 그냥 React네요.
00:47:27우리가 알다시피 Link 컴포넌트는 Inertia에서 옵니다.
00:47:30아니면 Adonis.js의 Inertia 패키지에서 오겠죠.
00:47:35알겠습니다.
00:47:37제가 이해한 바로는, 어디 봅시다.
00:47:47네.
00:47:47Children은 당연히...
00:47:51좋아요.
00:47:52좋아요.
00:47:53좋아요.
00:47:54흥미롭네요.
00:47:54Children은 항상 React에서 그렇듯 태그 사이의 컴포넌트죠.
00:48:05그런데 Children도 User 속성을 가진 Props 객체를 가지고 있네요.
00:48:13아마도 어딘가 컨트롤러에서 채워지겠죠.
00:48:20먼저, 새로운 세션, 회원가입의 새로운 계정 컨트롤러나 Inertia 렌더링 쪽이요.
00:48:29그런데 거기선 Props를 전혀 전달하지 않네요.
00:48:32세션 컨트롤러는 어디 있죠?
00:48:35이게 어디서 채워지는 걸까요?
00:48:36왜냐하면 여기에 Transformer라는 게 있는데, 전 이게 서버 사이드 데이터를 클라이언트 사이드로 변환하는 건 줄 알았거든요.
00:48:46확실하지 않네요.
00:48:50이것, 이 리소스, 무엇이든 반환해라.
00:48:56아마 데이터베이스에서 데이터를 가져오기 위한 용도일 수도 있겠네요.
00:48:59잘 모르겠네요.
00:49:01오케이.
00:49:02자, 이렇게 설정이 되었군요.
00:49:03공식 가이드를 계속 봅시다.
00:49:05저는 직접 코드베이스를 먼저 파고드는 걸 정말 좋아해요.
00:49:08그리고 가이드를 따르기 전에 스스로 이해해 보려고 노력하죠.
00:49:12그렇게 하면 더 많이 배우는 것 같거든요.
00:49:16요즘 누가 코드를 읽나요, 그렇죠?
00:49:18그러니 스트리밍을 통해 하는 건 어떨까요?
00:49:22농담입니다.
00:49:23저는 코드를 읽어요.
00:49:26폴더 구조.
00:49:28좋아요.
00:49:28방금 폴더 구조를 살펴봤어요.
00:49:31앱 폴더.
00:49:32앱 디렉토리는 애플리케이션의 도메인 로직을 위한 코드를 구성합니다.
00:49:36예를 들어, 컨트롤러, 모델, 메일 같은 것들이죠.
00:49:39네, 라라벨처럼 메일 전송도 도와주는데, 물론 매우 편리하죠.
00:49:44bin 디렉토리는 Adonis.js 애플리케이션을 실행하기 위한 진입점 파일들을 포함합니다.
00:49:50앱이 어떻게 부팅되는지 커스텀하려는 게 아니라면 보통 이 파일들은 수정할 필요가 없어요.
00:49:56좋아요.
00:49:56config 폴더에는 모든 애플리케이션 및 타사 설정 파일들이 들어 있습니다.
00:50:01이 디렉토리 안에 애플리케이션에 로컬한 설정을 저장할 수도 있어요.
00:50:05네, config 폴더에 보면 이미 데이터베이스 같은 것들이 있는데, 우린 SQLite를 사용하죠.
00:50:13아마도 Postgres 데이터베이스 같은 걸로 연결할 수도 있을 거라 생각해요.
00:50:20클라이언트를 선택할 수 있죠.
00:50:21그러니 여기서 Bun의 SQLite 클라이언트 같은 걸 사용할 수도 있겠네요.
00:50:24잘 모르겠지만요.
00:50:25데이터베이스 경로, temp 경로를 정의하죠.
00:50:28자, temp 폴더 여기 있고, 마이그레이션, 그 외에 뭐가 있죠?
00:50:34config, inertia, 서버 사이드 렌더링, 서버 사이드 렌더링 모드 토글.
00:50:39네, 서버 사이드 렌더링을 원하니 true로 바꿉시다.
00:50:47로거도 있네요.
00:50:48그러니까 말이 되네요.
00:50:50빨리 확인해 보고 싶어요.
00:50:52만약 이걸 false로 설정하면, 페이지 소스를 봤을 때, 데이터가 전달된 앱 div가 있겠죠.
00:51:06하지만 클라이언트 사이드에서 렌더링되기 때문에 주 HTML 내용은 없을 겁니다.
00:51:10클라이언트 사이드 렌더링을 수행하는 일부 스크립트를 가져오겠죠.
00:51:15검색 엔진 최적화(SEO)에는 좋지 않아요.
00:51:18그래서 이걸 true로 설정하면, 보시다시피 훨씬 더 많은 내용이 보이죠?
00:51:26내용이 모두 인라인 처리되어 읽기는 조금 어렵지만, 실제 HTML 내용이 존재하네요.
00:51:31그러니 true로 유지할게요.
00:51:34오케이, 데이터베이스.
00:51:35데이터베이스 디렉토리는 데이터베이스 계층 관련 아티팩트들을 보관합니다.
00:51:39기본적으로 Adonis.js는 Lucid ORM을 사용하죠.
00:51:43ORM의 아이디어는 데이터베이스 테이블을 코드 상의 클래스, 모델로 표현하는 것입니다.
00:51:51그럼 기초가 되는 스키마와 마이그레이션이 자동으로 생성되죠.
00:51:57네, 이 프레임워크를 탐구하는 건 이번이 처음이라, 어떻게 작동하는지 지금 알아가는 중이에요.
00:52:03데이터베이스를 바꾼다고 이 폴더를 재구성할 필요는 없습니다. 마이그레이션, 버전, 스키마 변경, 초기 관리자 유저 같은 시드 데이터를 원하면 시더까지 다 있죠.
00:52:15오케이, providers.
00:52:16Providers 디렉토리는 애플리케이션에서 사용되는 서비스 프로바이더를 저장하는 데 사용됩니다.
00:52:20서비스 프로바이더가 뭐죠?
00:52:22서비스 프로바이더.
00:52:22이 가이드에서 다루네요.
00:52:24음, 전부 다 읽지는 않을 거예요.
00:52:27서비스 공급자는 애플리케이션 시작 및 종료 시 특정 시점에 실행되는 수명 주기 후크를 가진 자바스크립트 클래스입니다.
00:52:35이를 통해 제어 역전(IoC) 컨테이너에 바인딩을 등록하고, 매크로를 사용하여 프레임워크 클래스를 확장하고, 정확한 시점에 초기화를 수행하며, 종료 시 리소스를 정리할 수 있습니다.
00:52:53그래서 내장 프로바이더들이 몇 개 있는 거군요.
00:52:58어디 있죠?
00:53:02아까 봤는데.
00:53:04내장 프로바이더들이 어디 있죠?
00:53:09Providers.
00:53:09여기 API 프로바이더가 있네요.
00:53:12API 응답을 위한 커스텀 시리얼라이저(직렬화기)군요.
00:53:17좋아요, 여기 데이터를 직렬화하는 프로바이더가 있네요.
00:53:22인증을 돕거나, 기본 미들웨어를 등록하는 더 많은 내장 프로바이더들이 있을 거라고 가정해요.
00:53:30그럴 것 같네요.
00:53:33저장은 하지 맙시다.
00:53:35오케이, public 디렉토리에는 원시 정적 자산이 들어 있습니다.
00:53:39이 폴더를 놓쳤었나?
00:53:40Public.
00:53:46저는 public 폴더가 없네요.
00:53:48하지만 public 자산은 따로 없나 봐요.
00:53:51최적화되지 않은 원시 자산들을 가지기 위해 public 폴더를 추가할 순 있겠죠.
00:54:05Adonis는 일자리가 거의 안 보이던데.
00:54:07왜 수요도 없는 걸 탐구하나요?
00:54:10그냥 재미로?
00:54:10네, 만약 일자리를 찾고 있다면 Adonis.js는...
00:54:15오, 정말 어려운 질문이네요.
00:54:17제 말은, 네, 일자리를 찾는다면 Adonis.js는 도움이 안 돼요.
00:54:22하지만 첫째로, 대안을 탐구하는 건 항상 시야를 넓혀주죠.
00:54:27여기서 배운 새로운 개념들이 다른 기술 스택을 사용하는 다른 애플리케이션에도 적용될 수 있어요.
00:54:33재미로 한다는 건 매우 타당한 이유죠.
00:54:36그리고 만약 일자리를 찾는 게 아니라, 자신만의 SaaS나 사업을 구축하려는 목적이라면 당연히 타당한 선택지가 될 수 있죠.
00:54:48물론 일자리를 찾는다면, 지역에 따라 매우 틈새시장일 순 있어요.
00:54:52그리고 솔직히 말해서, 너무 틈새라 일자리를 찾기는 매우 어려울 겁니다.
00:54:58하지만 일자리가 있는 지역에 있다면 경쟁자가 거의 없겠죠.
00:55:01물론 이건 매우 이론적인 이야기입니다.
00:55:07하지만 저에게는 지금 그저 재미일 뿐이에요.
00:55:08벌써 8년 전부터 읽어왔던 거라,
00:55:10마침내 어떻게 작동하는지 이해하고 싶거든요.
00:55:15마침내 어떻게 작동하는지 이해하고 싶어서요.
00:55:19리소스 디렉토리는 Inertia 앱에서 엣지 템플릿과 CSS 및 JavaScript 파일 같은 컴파일되지 않은 프론트엔드 에셋을 저장합니다.
00:55:30Resources 폴더가 있나요?
00:55:32있네요.
00:55:33Inertia 레이아웃이요.
00:55:35오.
00:55:35그건 이 React 앱이 렌더링될 원시 HTML 골격 같은 거군요.
00:55:41여기에 콘텐츠 보안 정책(CSP)을 설정할 수 있겠네요.
00:55:44일부 정적 자산을 여기로 가져올 수도 있고요.
00:55:48이미 있는 것 외에 메타데이터를 등록할 수도 있겠죠.
00:55:51알겠습니다.
00:55:52Inertia 디렉토리는 Inertia 스타터 키트를 사용하는 프로젝트에만 존재합니다.
00:55:56말이 되네요.
00:55:57프론트엔드 소스 코드를 포함하는 하위 애플리케이션을 나타냅니다.
00:56:01components, layouts, utils 같은 폴더를 추가로 만들어 구성하는 건 자유죠.
00:56:06즉, 본질적으로 거기서 View나 React 앱을 구축하는 겁니다.
00:56:09프론트엔드와 백엔드의 명확한 분리.
00:56:11Adonis.js는 백엔드와 프론트엔드 사이에 명확한 경계를 유지합니다.
00:56:14아무것도 노출하지 않기 위해, 혹은 브라우저에서 실행되지 않는 백엔드나 서버 사이드 Node.js API 때문에 충돌하지 않도록 프론트엔드 애플리케이션에 백엔드 코드를 가져오지 말아야 합니다.
00:56:30실제로는 프론트엔드가 HTTP 요청을 통해 백엔드와 통신하고 일반 JSON 데이터를 받죠.
00:56:35Adonis.js는 이를 명시적으로 모델링하도록 장려합니다.
00:56:39데이터는 API 응답을 통해 가져오고 변환됩니다.
00:56:43Inertia를 사용할 때 정확히 어떻게 통신하는지 궁금하네요.
00:56:49예를 들어 로그인을 한다고 치면,
00:56:52여기 폼이 있네요.
00:56:54네.
00:56:54흥미롭군요.
00:56:56그건 Adonis.js 프레임워크에서 제공하는 컴포넌트입니다.
00:57:01그게 경로를 받아오는데, 보통의 React 앱에서 직접 만든 REST API로 보내는 HTTP 요청을 보내는 방식과는 다르죠, 맞나요?
00:57:12대신, 우리는 이 폼이 어떤 경로에 연결되어 있는 것처럼, 마치 예전의 멀티 페이지 애플리케이션을 만들듯이 구현했습니다.
00:57:19그리고 폼을 제출하면, 아마도 이너시아(Inertia)와 아도니스(Adonis)가 내부적으로 그 요청을 생성해서 해당 경로로 전송할 겁니다.
00:57:28그리고 모든 것이 우리 대신 처리되겠죠, 본질적으로요.
00:57:31그러니 우리가 직접 요청을 보내고, 응답을 기다리고, 상태를 관리할 필요가 없습니다.
00:57:37여기서는 그렇게 할 필요가 없죠.
00:57:42네.
00:57:44새로운 프레임워크를 배울 때 당신의 사고 과정은 어떤가요?
00:57:48다른 프레임워크와 비교하시나요?
00:57:51아니면 완전히 새로운 것으로 취급하시나요?
00:57:53아마도 자동으로 이미 알고 있는 것들과 조금씩 비교하게 되는 것 같습니다.
00:57:57하지만 물론, 아도니스는 예를 들어 Next.js 등과는 너무 달라서 아주 많이 비교하지는 않습니다.
00:58:03제가 처음에 했던 주된 비교는, 이게 완전히 다른 철학을 가지고 있다는 것을 이해해야 한다는 점입니다.
00:58:10그러니까 단순히 라우팅을 하고 컴포넌트를 렌더링하는 것만이 아니라, '배터리가 포함된(batteries included)' 완전한 프레임워크를 사용하는 것이죠.
00:58:18그래서 아주 많이 비교하는 편은 아닙니다.
00:58:19꽤 새로운 것으로 보고 있죠.
00:58:21라라벨(Laravel)과는 조금 비교합니다. 왜냐하면 이게 JavaScript용 라라벨이니까요.
00:58:25그리고 아주 좋은 댓글을 남겨주신 Bleem님께 감사드립니다.
00:58:29콘텐츠를 좋아해 주셔서 기쁩니다.
00:58:32좋아요.
00:58:34공유 타입.
00:58:35프론트엔드는 여전히 아도니스가 자동으로 생성한 공유 TypeScript 타입을 활용할 수 있습니다.
00:58:40이들은 .adonis.js 클라이언트 디렉토리에 저장되며, 경로, 속성 등에 대한 타입 정의를 포함하여 우리가 TypeScript를 활용할 수 있게 합니다.
00:58:48Start.
00:58:49start 디렉토리에는 애플리케이션의 부트 라이프사이클 동안 가져오고 싶은 파일들이 포함되어 있습니다.
00:58:55예를 들어, 경로를 등록하고 이벤트 리스너를 정의하는 파일들은 이 디렉토리 안에 있어야 합니다.
00:59:00아도니스는 start 폴더에서 파일을 자동으로 불러오지 않습니다.
00:59:03아도니스는 단지 비슷한 파일들을 그룹화하는 규칙으로 사용될 뿐입니다.
00:59:06알겠습니다.
00:59:07그래서 start 폴더에 kernel TS 파일이 있는 거군요.
00:59:12아, 네, 이미 봤네요.
00:59:14맞아요, 맞아요, 맞아요.
00:59:16여기에 새로운 미들웨어를 등록할 수 있겠네요. 가이드의 일부로 해야 할지 나중에 확인해 보죠.
00:59:24테스트 폴더도 있군요.
00:59:25데이터베이스 같은 임시 파일을 위한 temp 폴더도 있고요.
00:59:28Ace.js는 ace 명령어를 실행하기 위한 진입점입니다.
00:59:33여기에 그 파일이 있나요?
00:59:35Ace.
00:59:36Ace, 네.
00:59:37알겠습니다.
00:59:38이 파일은 수정하지 마세요.
00:59:39네.
00:59:41네.
00:59:44프로젝트 매니페스트인가요?
00:59:46Lint 패키지를 사용하고요.
00:59:48Config를 사용하네요.
00:59:49네, 알겠습니다.
00:59:51개발 환경 설정.
00:59:54아도니스 애플리케이션은 완벽하게 구성된 개발 환경과 함께 제공됩니다.
00:59:57네, 코드 에디터.
01:00:01네, Edge 확장을 이미 설치했지만 이너시아와 React를 사용하면 필요 없을 것 같습니다.
01:00:09TypeScript.
01:00:10그럼 제가 이해하기로 모든 게 구성되어 있을 겁니다.
01:00:12거기에 시간 낭비하고 싶지 않아요.
01:00:14구성 및 환경.
01:00:18아도니스의 구성은 세 가지 별도 시스템으로 조직되어 있으며, 각각 특정 목적을 수행합니다.
01:00:23Config 파일은 config 폴더 안에 애플리케이션 설정을 담고 있습니다.
01:00:28환경 변수는 .env 파일에 보관되며 런타임 비밀 정보와 환경마다 바뀌는 값들을 저장합니다.
01:00:33말이 되네요.
01:00:34그건 그렇고, 비밀 정보와 관련해서, 특히 공급망 공격이 많은 요즘 제 추천은 .env 파일에 저장하지 않는 것입니다.
01:00:41강의 같은 걸 할 때는 빨리 하고 삭제하니까 .env를 사용할 수도 있겠지만요.
01:00:47하지만 계속 사용해야 하는 비밀 정보라면 InPhysical 같은 서비스를 사용하는 게 좋습니다.
01:00:53돈 받고 하는 광고는 아니고요.
01:00:54Doppler나 다른 서비스를 사용해도 됩니다.
01:00:57이것들은 클라우드 서비스입니다.
01:00:58InPhysical은 무료로 시작할 수 있고요.
01:01:01네.
01:01:02비밀 정보를 클라우드에 저장하고 CLI를 통해 불러올 수 있죠.
01:01:06만약 당신의 컴퓨터가 해킹당하더라도 비밀 정보가 그렇게 쉽게 추출되지는 않을 겁니다.
01:01:14그냥 작은 팁입니다.
01:01:17Adonis R-CTS 파일은 프레임워크 자체를 구성합니다.
01:01:20네.
01:01:20그러니까 config 파일들은 애플리케이션을 위한 것이고, 그 파일은 프레임워크 자체를 위한 것이군요.
01:01:26거기서 아마 기본적으로 찾을 폴더 이름 같은 것들을 바꿀 수 있겠네요.
01:01:33구성은 config 디렉토리에 있습니다.
01:01:35일반적인 아도니스 프로젝트에는 여러 config 파일이 포함되어 있습니다.
01:01:38봤습니다.
01:01:39이게 데이터베이스 config 파일이군요.
01:01:42메일 config고요.
01:01:43이 config 파일이 환경 변수를 어떻게 참조하는지 보세요.
01:01:46이게 환경 변수를 사용하는 올바른 방법이죠.
01:01:49네.
01:01:49말이 되네요.
01:01:50예를 들어 이메일을 보내는 애플리케이션이 있다면, 이메일 전송 방식을 설정할 수 있습니다.
01:01:55그런데 몇몇 값들은 .env 파일에 넣어서 config 파일에 하드코딩되지 않게 하는 거죠.
01:02:02그건 설정을 조정하기 위한 일반적인 구성일 뿐이고, 실제 값이나 비밀 정보는 환경 변수로 불러오는 방식입니다.
01:02:12구성 파일들은 애플리케이션 부트 사이클 중에 로드됩니다.
01:02:16Edge 템플릿은 사용하지 않고, 아마도 .env 환경 변수는 자동으로 로드되겠죠.
01:02:25앱 키는 아도니스가 쿠키 암호화, 세션 서명 및 기타 암호화 작업에 사용하는 특별한 환경 변수입니다.
01:02:35그래서 앱 키를 만들기 위해 키 생성을 실행하겠지만, 이미 하나 가지고 있습니다.
01:02:41네, 이해했습니다.
01:02:46그냥 기본값으로 충분할 거라고 생각해요.
01:02:49이번 방송을 config 파일만 조정하다가 끝내고 싶지는 않거든요.
01:02:53그럼 배포를 계속해 보죠.
01:02:58네, 알겠는데 배포하고 싶지는 않습니다.
01:03:00저는 FAQ를 만들고, 개발 쇼를 구축해서, 커뮤니티 쇼케이스 웹사이트를 만들고 싶습니다.
01:03:11이 튜토리얼에서 당신은 개발 쇼를 만들게 될 것입니다.
01:03:14네, 그렇게 하고 싶어요.
01:03:17하지만 질문 먼저 받겠습니다.
01:03:21GitHub Actions가 TanStack 보안 문제의 주범이라고 생각하시나요, 아니면 TanStack의 잘못인가요?
01:03:27기술적으로는 TanStack의 잘못입니다. 제가 기억하기로는 이런 일이 일어나지 않도록 충분히 설정을 할 수 있었거든요.
01:03:38하지만 물론, GitHub Actions처럼 이런 특정 오류가 일어나기 아주 쉽게 만드는 시스템이 있다는 것 또한 당연히 좋지는 않죠.
01:03:50글쎄요, 저는 엄청난 CI/CD 전문가는 아닙니다.
01:03:55저는 수년간 모든 종류의 자동화를 위해 GitHub Actions를 사용해 왔습니다.
01:04:00하지만 저는 여러 팀이 복잡한 워크플로우를 가지고 같은 저장소에 계속해서 푸시하는 대규모 기업에서 일하는 건 아니니까요.
01:04:12그래서 저는 GitHub Actions에 만족합니다.
01:04:14물론, 다른 형태로 사용하고 있긴 하지만요.
01:04:18전부 너무 단순한 건 아니지만, 가장 정교한 워크플로우를 사용하는 것도 아닙니다.
01:04:29JavaScript 강의에 대해 묻고 싶습니다.
01:04:3190개가 넘는 영상을 보고도 이해하지 못하는 건 잘못된 건가요?
01:04:33아무것도 이해하지 못했다면 그건 좋은 징조가 아니죠.
01:04:38아마 제 책임일 수도 있겠네요.
01:04:39하지만 그렇게 말하기는 어렵네요.
01:04:43하지만 영상을 순서대로 보셨다면 뭔가 하나는 클릭이 되어야 할 텐데요.
01:04:51하지만 제가 Windows를 쓰고 당신은 Apple을 써서 어렵게 느끼시는 것 같네요.
01:04:54그게 차이를 만들지는 않을 텐데요.
01:04:56JavaScript는 그냥 JavaScript니까요.
01:04:57글쎄요, 이해하지 못한다는 게 JavaScript 문법을 이해 못 한다는 것이라면 그건 사실 똑같습니다.
01:05:07그러니 Windows든 Apple이든 문제가 되지는 않을 겁니다.
01:05:10안녕하세요, Max.
01:05:11커뮤니티에 기여해 주셔서 감사합니다.
01:05:13안녕하세요, 정말 친절한 말씀 감사합니다.
01:05:16React와 Angular 중 무엇을 선호하시나요, 아니면 프로젝트에 따라 다른가요?
01:05:20프로젝트에 따라 다릅니다.
01:05:21하지만 요즘은 주로 React를 사용합니다. AI가 가장 좋아하는 프레임워크니까요.
01:05:26그리고 좋든 싫든 코딩할 때 AI를 정말 많이 사용합니다.
01:05:33AI 이전에는 별다른 선호도가 없었습니다.
01:05:36굳이 말하자면, Vue의 문법과 사용 편의성을 좋아했을 겁니다. 특히 Vue 2요.
01:05:42하지만 네, 그런 시절은 다 지났죠.
01:05:44뭐가 됐든 상관없습니다.
01:05:46새로운 프레임워크 패러다임 개념을 배울 때 뭐가 중요하다고 생각하시나요?
01:05:51저에게는 깊이 파고드는 게 정말 중요합니다.
01:05:54내부적으로 어떻게 작동하는지 이해하고 싶거든요.
01:05:57그냥 표면적인 대답만 얻고 싶지는 않습니다.
01:06:03어떻게 연결되어 있는지, 왜 특정 방식을 사용하는지, 언제 어떤 접근 방식을 취해야 하는지 이해하고 싶습니다.
01:06:10계속 질문을 던지고, 더 깊이 들어가 보려고 정말 노력합니다.
01:06:16그럼 이제 만들어 봅시다.
01:06:19아도니스 하이퍼미디어로 시작하고 있습니다.
01:06:22그래서 이너시아를 사용 중입니다.
01:06:23작동하게 할 수 있을지 지켜보죠.
01:06:27네, 경로들이 있습니다.
01:06:29제 여기에도 아마 있는 것 같네요.
01:06:34어디에 있죠?
01:06:35start 폴더에 있습니다.
01:06:36네, start 폴더 경로요.
01:06:39네, 여기도 있습니다.
01:06:40똑같아 보이네요.
01:06:43스타터 키트가 가입, 로그인, 로그아웃 경로를 제공하네요.
01:06:45게스트 미들웨어가 로그아웃한 사용자만 가입/로그인에 접근하게 하고, 인증 미들웨어가 로그아웃 경로를 보호하는 걸 확인하세요.
01:06:53이미 파악했습니다.
01:06:55컨트롤러 작동 방식.
01:06:56가입 컨트롤러를 보고 요청이 애플리케이션을 통해 어떻게 흐르는지 확인해 보죠.
01:07:07네, app 컨트롤러에 있는 이 새 계정 컨트롤러를 살펴봅시다.
01:07:12물론 Edge가 아니라 이너시아를 사용 중이지만, 그래도 확인해 봅시다.
01:07:19각 컨트롤러 메서드는 첫 번째 매개변수로 HTTP 컨텍스트 객체를 받습니다.
01:07:26바로 이거죠.
01:07:28컨텍스트에는 현재 요청에 대한 모든 것, 요청 데이터, 응답 객체, 인증 상태, 뷰 렌더러 등이 포함되어 있습니다.
01:07:34우리는 필요한 속성만 구조 분해합니다.
01:07:39create 메서드는 단순히 가입 폼을 보여줍니다.
01:07:42네, 이해했어요.
01:07:44우리의 경우 이너시아를 사용 중이라 이 이너시아 객체를 얻는 거죠.
01:07:48여기에는 더 많은 것들이 있습니다.
01:07:50요청을 통해 URL 같은 걸 알아낼 수도 있겠죠.
01:07:57하지만 여기서는 뷰를 렌더링하기 위해 이 이너시아 객체를 사용합니다.
01:08:01이 포스트 경로의 경우 요청 본문을 검증하기 위해 요청의 validate using 메서드를 사용하는 것 같네요.
01:08:12네.
01:08:17컨트롤러가 사용자 모델과 가입 검증기를 참조하는 걸 보셨을 겁니다.
01:08:21스타터 키트에 이미 포함되어 있죠.
01:08:23나중에 다뤄볼 겁니다.
01:08:27알겠습니다.
01:08:30컨트롤러가 뷰 렌더러를 호출하면 템플릿 파일을 찾아 렌더링합니다.
01:08:34네, 이해했습니다.
01:08:35뷰는 resources 폴더에 있습니다.
01:08:38계정을 만들어 보세요.
01:08:39이미 했습니다.
01:08:40명령줄과 REPL.
01:08:42기능을 바로 만들기 시작하지 않고 왜 CLI와 REPL을 다루는지 궁금하실 겁니다.
01:08:46이유는 이렇습니다.
01:08:46이 튜토리얼을 진행하면서 컨트롤러, 모델 및 기타 파일을 만들기 위해 계속 ACE 명령어를 사용하게 될 겁니다.
01:08:51지금 CLI에 익숙해져야 나중에 흐름이 끊기지 않습니다.
01:08:54좋습니다.
01:08:55node ace list 명령어로 사용 가능한 명령들을 볼 수 있습니다.
01:08:59해보죠.
01:09:02안녕하세요.
01:09:05알겠습니다.
01:09:06네, 실행할 수 있는 내장 명령어들이 많이 있네요.
01:09:11하나 이상의 아도니스 패키지를 설치하고 구성하기.
01:09:14빌드, 꺼내기, 시더를 실행하기 위한 데이터베이스 명령어들.
01:09:19키 생성.
01:09:21경로 나열하기.
01:09:23리스너를 설정할 이벤트를 만드는 것 같은 생성 명령어들.
01:09:29아니면 새로운 미들웨어나 모델 만들기.
01:09:32좋습니다.
01:09:32네.
01:09:38REPL.
01:09:39네.
01:09:40먼저 앞으로 좀 나가겠습니다.
01:09:42모험 좀 해보죠.
01:09:54이 챕터에서는 포스트와 댓글 리소스를 위한 모델과 마이그레이션을 만들 겁니다.
01:09:59관계 설정하기.
01:10:01더미 데이터를 생성합니다.
01:10:01네.
01:10:02이 장에서는 AdonisJS의 SQL ORM인 Lucid를 소개합니다.
01:10:06원시 SQL 쿼리를 작성하는 대신, 자바스크립트 클래스인 모델을 사용하여 데이터베이스 테이블을 표현하게 됩니다.
01:10:11이미 이전에 말씀드린 내용이죠.
01:10:14중요한 차이점이 있습니다.
01:10:15모델은 데이터와 상호작용하는 방식을 정의하지만, 데이터베이스 구조를 수정하지는 않습니다.
01:10:20그건 마이그레이션이 할 일이죠.
01:10:21네.
01:10:21모델이 있고,
01:10:22코드에서 그 모델을 사용합니다.
01:10:24데이터를 다루기 위해서요.
01:10:25하지만 그러려면 데이터베이스 테이블이 필요합니다.
01:10:27그리고 테이블을 만들기 위해서는 마이그레이션이 필요합니다.
01:10:31일종의 작은 스크립트라고 할 수 있죠.
01:10:33우리가 필요한 올바른 테이블을 갖추도록 데이터베이스를 조정하는 청사진 같은 겁니다.
01:10:37그리고 마이그레이션은 모델에서 파생됩니다.
01:10:40모델 클래스에서요.
01:10:42라라벨에서는 그렇게 작동합니다.
01:10:43아도니스(Adonis)에서도 마찬가지로 작동한다는 것을 이해했습니다.
01:10:49자, 그럼 포스트 모델을 추가해 봅시다.
01:10:54node ace make:model post 명령어로요.
01:11:01그럼 모델즈 포스트 TS 파일이 생성됩니다.
01:11:05그리고 새로운 마이그레이션 파일도 이미 만들어졌죠.
01:11:09말했듯이 모델과 마이그레이션 둘 다 필요하니까요.
01:11:11이제 여기에 포스트 모델이 생겼습니다.
01:11:13지금은 빈 클래스 상태네요.
01:11:19그건 아마 제 IDE의 타입스크립트 오류일 수도 있어요.
01:11:26아니면, 아뇨.
01:11:27아직 하나도 없다고 생각해요.
01:11:28왜냐면 아직 마이그레이션을 설정하지 않았으니까요.
01:11:33스키마 말이에요.
01:11:34테이블 형태를 아직 정의 안 했어요.
01:11:41마이그레이션에서 테이블 구조를 정의해야 합니다.
01:11:43맞아요.
01:11:43그래서 그 작업을 해야 합니다.
01:11:45자, 이걸 복사할게요.
01:11:48그리고 이 포스트 파일로 갑시다.
01:11:53마이그레이션 파일이죠.
01:11:54베이스 스키마.
01:11:56네.
01:11:56이게 맞네요.
01:11:59처음에는 posts라는 테이블 이름으로 기본적인 테이블을 설정합니다.
01:12:07그리고 ID와 타임스탬프를 부여하죠.
01:12:10우리가 지금 추가하려는 건 이 세 줄입니다.
01:12:14이걸 복사할 수 있어요.
01:12:16여기에 붙여넣죠.
01:12:18모든 포스트에 제목, URL, 요약을 추가합니다.
01:12:24그런 것 같네요.
01:12:25그리고 값이 들어가야 하니 not nullable로 설정합니다.
01:12:28null이면 안 됩니다.
01:12:30좋습니다.
01:12:31이제 이걸 실행해야 할 것 같네요.
01:12:34네.
01:12:34업(up) 부분은 생성하는 역할을 합니다.
01:12:36다운(down) 부분은 테이블을 삭제하죠.
01:12:39댓글 모델 생성.
01:12:40댓글 모델을 만들어 봅시다.
01:12:43자, 그럼.
01:12:45개발 서버를 중지할게요.
01:12:47변경 사항을 적용하려면 재시작해야 할 테니까요.
01:12:51다시 모델을 생성하겠습니다.
01:12:53댓글 모델이요.
01:12:54전과 똑같이요.
01:12:56새 마이그레이션 파일이 생겼네요.
01:12:57새로운...
01:13:01어디 있지?
01:13:02새 모델.
01:13:03여기 댓글 모델이 있네요.
01:13:04그리고 마이그레이션 파일에요.
01:13:06다시 기본 뼈대입니다.
01:13:09여기에 뭘 추가하죠?
01:13:10내용을 위한 한 줄인 것 같네요.
01:13:13내용요.
01:13:18좋습니다.
01:13:21이제 테이블을 추가하기 위해 실행할 수 있습니다.
01:13:27잘 작동하는군요.
01:13:29한번 봅시다.
01:13:31개발 서버를 다시 시작하니 잘 되네요.
01:13:35이제 그 에러도 사라졌습니다.
01:13:36마이그레이션을 적용하니 뒤에서 타입을 생성했나 봅니다.
01:13:47네.
01:13:48데이터베이스 스키마 TS 파일이 업데이트되었습니다.
01:13:51여기 데이터베이스 폴더 안의 스키마 TS 파일이요.
01:13:56이 파일은 기본적으로 관리되는 거죠.
01:13:58아도니스가 생성한 스키마가 들어 있습니다.
01:14:02결국 에이스 명령어가 만든 거죠.
01:14:04답변 감사합니다, Max.
01:14:11당신 강의를 여러 개 샀어요.
01:14:12소프트웨어 개발자로 성장하는 데 큰 도움이 됐습니다.
01:14:16네.
01:14:17정말 감사합니다.
01:14:18강의를 들어주셔서 감사하고 좋은 말씀도 감사합니다.
01:14:21도움이 되었다니 정말 기쁩니다.
01:14:24당신의 커리어에 작은 부분이라도 기여할 수 있어 영광입니다.
01:14:27정말 감사합니다.
01:14:31자, 이제 관계를 설정해 봅시다.
01:14:33댓글과 포스트 사이의 관계를 만들고 싶으니까요.
01:14:37모든 포스트는 하나 이상의 댓글을 가질 수 있죠.
01:14:44그리고 모든 댓글은 딱 하나의 포스트에 속합니다.
01:14:47즉, 일대다 관계입니다.
01:14:54댓글은 포스트에 속하고, 포스트는 사용자에게 속하죠.
01:14:57맞아요.
01:14:57그것도 필요합니다.
01:14:58외래 키를 위한 마이그레이션을 생성합시다.
01:15:01다음 명령어로 기존 테이블을 수정하는 새로운 마이그레이션 파일을 만듭니다.
01:15:04한번 보죠.
01:15:06무슨 동작을 하죠?
01:15:09외래 키 추가 마이그레이션을 생성합니다.
01:15:11그냥 추가적인 마이그레이션 파일이네요.
01:15:13전에는 모델과 마이그레이션 파일이 같이 나왔는데.
01:15:16이제는 마이그레이션 파일만 사용하네요.
01:15:22모델이나 클래스가 필요 없으니까요.
01:15:25하지만 데이터베이스 설정을 조정하고 몇 개의 테이블에 새로운 컬럼을 추가하기 위해 마이그레이션이 필요합니다.
01:15:40관계 설정을 위해 컬럼을 추가하려는 건데, SQL 데이터베이스에서의 관계는 단순히 컬럼을 추가해 이 댓글은 이 사용자 ID와 포스트 ID를 가진다고 말하는 것입니다.
01:15:53복사할게요.
01:15:55복사하겠습니다.
01:15:56이게 포스트에 대한 외래 키들입니다.
01:16:00내가 만든 게 맞나?
01:16:05외래 키 추가.
01:16:11잠시만요.
01:16:22아, 이제 실행할 거예요.
01:16:23실행 안 했었나?
01:16:25아니요, 이거예요.
01:16:28파일 이름이 좀 다르네요.
01:16:31뭐, 상관없어요.
01:16:34붙여넣죠.
01:16:35무슨 작업을 하죠?
01:16:37포스트 테이블에 양수 정수 타입의 not null인 사용자 ID 컬럼을 추가합니다.
01:16:45null이 아니고요.
01:16:45그리고 외래 키 관계를 설정합니다.
01:16:48사용자가 삭제되면 포스트도 삭제되도록요.
01:16:51댓글의 경우 사용자뿐 아니라 포스트와도 연결하는데, 댓글은 포스트에 속하기 때문입니다.
01:16:58그리고 변경 사항을 되돌리는 다운 마이그레이션이 있습니다.
01:17:01좋아요.
01:17:03실행해 봅시다.
01:17:07실행합니다.
01:17:11개발 서버가 시작됩니다.
01:17:13포스트 모델에서 관계를 정의합시다.
01:17:15데이터베이스에 외래 키 컬럼이 생겼으니 모델을 업데이트해 관계를 정의할 겁니다.
01:17:20복사할게요.
01:17:22지금은 비어 있는 포스트 모델로 가서 붙여넣습니다.
01:17:27이제 그 클래스 안에서 댓글 프로퍼티를 추가해 관계를 선언합니다.
01:17:43아도니스에서 제공하는 데코레이터를 사용해 포스트가 많은 댓글을 가지고 있고 사용자에 속한다고 명시합니다.
01:17:57라라벨과 거의 같은 방식이네요.
01:18:02읽고 이해하기 꽤 쉽네요.
01:18:05단순히 프로퍼티를 선언만 한다는 게 좀 이상할 수도 있겠네요.
01:18:11초기값이 없으면 타입스크립트에서 문제가 생기기에 declare가 필요합니다.
01:18:18declare를 쓰면 문제가 안 생겨요.
01:18:20그게 답니다.
01:18:22댓글 모델에도 관계가 필요합니다.
01:18:26거기에도 붙여넣죠.
01:18:28댓글은 포스트에 속하고 사용자에게 속한다고 정의합니다.
01:18:31어디서 보느냐에 따라 has와 belong 관계가 결정되죠.
01:18:36둘 다 설정하는 겁니다.
01:18:39알겠습니다.
01:18:40이제 됐습니다.
01:18:41이 튜토리얼에서는 필요 없으니 사용자 모델에는 역방향 has many를 추가하지 않았습니다.
01:18:46나중에 애플리케이션에서 사용자의 포스트나 댓글을 조회할 필요가 생기면 추가할 수 있습니다.
01:18:51네.
01:18:52이 튜토리얼에서는 사용자가 쓴 모든 포스트를 찾을 일은 없을 것 같네요.
01:18:58그래서 관계를 설정할 필요는 없지만, 사용자의 모든 포스트를 조회해야 한다면 당연히 설정해야 하겠죠.
01:19:04하지만 여기서는 모든 포스트를 조회하고 포스트가 어떤 사용자의 것인지 표시만 하면 됩니다.
01:19:16세상에, 이 프레임워크는 앵귤러와 네스트가 아이를 낳은 것 같네요.
01:19:20크고 복잡한 프레임워크도 여전히 관련이 있나 보네요.
01:19:24이 프레임워크는 이론상 꽤 훌륭할 수 있어요. 많은 것이 내장되어 있으니까요.
01:19:30처음에는 압도적일 수 있지만요.
01:19:33큰 장점은 따로 뭘 추가할 필요가 없다는 겁니다.
01:19:39전혀 안 넣는 건 아니지만, 많은 경우에 추가할 게 거의 없이 다양한 애플리케이션에 작동하게 만들 수 있죠.
01:19:48저는 Next.js, Tanstack, Start의 큰 팬이지만 아도니스는 써본 적이 없거든요.
01:19:54그러니 최고니까 써보세요라고 말할 수는 없죠.
01:19:56저 스스로 써보지는 않았으니까요.
01:19:58하지만 Next.js나 Tanstack, 앵귤러 같은 걸 쓸 때는 인증을 위해 항상 라이브러리를 추가해야 하죠.
01:20:07데이터베이스를 위해서도 추가적인 라이브러리나 ORM, 프리즈마 같은 걸 더해야 하고요.
01:20:14공급망 공격 위협이 있는 요즘 같은 때에, 그런 라이브러리를 다 꿰어 맞추는 건 꽤 골치 아픈 일일 수 있습니다.
01:20:21유지보수 문제도 있고요.
01:20:23이론적으로는 훌륭할 것 같네요.
01:20:26AI 없이 작업하시니 기분 좋으면서도 향수가 느껴지시나요?
01:20:30아, 네.
01:20:31향수를 불러일으키는 느낌이네요.
01:20:33작동 방식을 이해하고 싶어서 AI를 안 쓰고 있습니다.
01:20:38요즘 같은 시대에도 무언가 배울 땐 그게 중요하다고 생각해요.
01:20:42그냥 AI로만 코딩하면 재미있는 라이브 방송도 안 될 거고요.
01:20:47그리고 Vibe coding으로는 한계가 분명히 있습니다.
01:20:52모델과 테이블이 준비되었으니 개발과 테스트를 위해 더미 데이터를 채워야 합니다.
01:20:57팩토리는 실제 같은 가짜 데이터로 모델 인스턴스를 만드는 청사진 역할을 합니다.
01:21:03청사진을 한 번만 정의하면 되죠.
01:21:04좋습니다.
01:21:05포스트 팩토리를 만들어 가짜 포스트를 생성해 봅시다.
01:21:10팩토리 만들기 명령어를 실행합니다.
01:21:14포스트 팩토리 파일이 생기는데, 여기서 포스트 생성 방식을 정의합니다.
01:21:21복사해서 살펴볼게요.
01:21:25가짜 포스트를 만드는 겁니다.
01:21:30Faker 도구가 포스트를 생성할 때 선택할 수 있는 제목 리스트가 있습니다.
01:21:37가짜 URL과 Lorem Ipsum 단락도 추가하고요.
01:21:45프로그래밍 방식으로 빠르게 가짜 데이터를 만드는 거죠.
01:21:48요즘은 AI로도 할 수 있겠죠.
01:21:51하지만 토큰 비용도 안 드는 옛날 방식을 쓰겠습니다.
01:21:56댓글 팩토리도 만들어 봅시다.
01:22:02여기 있습니다.
01:22:03그리고 그 코드를 여기에 복사해 넣죠.
01:22:06여기서는 그냥 더미용 로렘 입숨 문단 몇 개를 출력합니다.
01:22:11이제 시더가 필요합니다.
01:22:12자, 이제 가짜 데이터를 만들어낼 팩토리가 생겼습니다.
01:22:15그런데 이 가짜 데이터로 뭘 하려고 할까요?
01:22:17데이터베이스에 넣어야겠죠.
01:22:19그럴 때 시더가 필요한 겁니다.
01:22:23그래서 하나 만들어 보려고요.
01:22:24이건 일반적인 개념이죠.
01:22:26팩토리 시더요.
01:22:27아도니스에서만 쓰는 게 아닙니다.
01:22:28라라벨에서도 볼 수 있죠.
01:22:29아니면 어떤 환경에서든 이런 개념을 활용할 수 있습니다.
01:22:37또한, XJS 애플리케이션에서도 데이터를 채워 넣고 싶은 데이터베이스가 있을 수 있고요.
01:22:41물론 'node ace' 명령어는 아도니스 전용이긴 합니다.
01:22:45이제 시더를 만들어 보겠습니다.
01:22:47포스트 시더를 한번 살펴보죠.
01:22:49이 파일은 초기 데이터를 데이터베이스에 밀어 넣을 때 실행할 수 있습니다.
01:22:54그러니 여기서 무엇을 할지 정의해야 합니다.
01:22:57제 생각엔 여기서 더미 게시물과 댓글을 만들고, 연결한 다음, 데이터베이스에 넣는 작업을 수행해야 할 것 같습니다.
01:23:07아도니스에선 어떻게 하는지 볼까요.
01:23:10붙여넣고 한번 살펴보죠.
01:23:13찾거나 아니면 실패하게 만들고 있네요.
01:23:17사용자를 찾으려는 중입니다.
01:23:19그리고 실패해야겠죠.
01:23:21만든다는 말은 없고, 아직 그 사용자가 없으니까요.
01:23:25그래서 일단 사용자를 찾으려고 합니다.
01:23:26만들어야겠죠.
01:23:28그다음 이 사용자를 병합하고요.
01:23:33새 게시물을 여러 개 만들어서 이 명령어로 해당 사용자에게 연결합니다.
01:23:37그리고 각 게시물마다 더미 댓글을 생성하고, 그 댓글들 또한 게시물과 사용자에게 연결합니다.
01:23:46댓글 개수는 랜덤으로 설정하고 3을 더하고요.
01:23:51즉, 게시물 하나당 최소 3개에서 최대 6개의 댓글이 생성되는 거죠.
01:24:02댓글이 3개에서 6개 사이입니다.
01:24:06우선, 이 이메일로 사용자를 가져옵니다.
01:24:09이건 지난 챕터에서 O로 만들었던 바로 그 사용자입니다.
01:24:12제가 직접 사용자를 만들게요.
01:24:15빨리 처리하겠습니다.
01:24:19서버를 실행하죠.
01:24:23아직 시더를 실행해 보진 않았거든요.
01:24:26그건 잘 될 겁니다.
01:24:27그런데 그건 틀렸어요.
01:24:28빨리 회원가입을 할게요.
01:24:34네, 네, 네.
01:24:36아니, 이건 아니고요.
01:24:37자.
01:24:39저는 이걸 사용할 겁니다.
01:24:44좋아요.
01:24:45다른 이메일 주소를 사용하겠습니다.
01:24:47당연히 저는...
01:24:50test@example.com을 쓸게요.
01:24:52네.
01:24:53자, 됐습니다.
01:25:02네, 계속 진행해 주세요.
01:25:03이런 스트림이라.
01:25:03마음에 듭니다.
01:25:04네, 당연히 계속할 겁니다.
01:25:06참고로, 매주 목요일마다 이런 스트림을 진행할 계획입니다.
01:25:13다음 주에는 아마 못 할 것 같아요.
01:25:16다른 약속들이 잡혀 있거든요.
01:25:18하지만 기본적으로는 매주 목요일, 오후 5시(중앙 유럽 여름 시간 기준)에 시작할 계획입니다.
01:25:26제 생각에 Anthropic은 정말로 자사 도구들을 밀어주려는 것 같아요.
01:25:40Claude Code 외에는 아무것도 안 밀어주려고 하죠.
01:25:42사용자들을 묶어두려는 겁니다.
01:25:43어떻게 될지 지켜보죠.
01:25:45Claude를 다른 모든 도구에서 사용할 수 있게 될지는 잘 모르겠어요.
01:25:51적어도 토큰 비용을 지불하는 구독 모델로는 아니겠죠.
01:25:55물론 API를 쓰면 가능하겠지만.
01:25:58그건 물론 엄청나게 비쌀 거고요.
01:26:02자, 이제 시더를 실행해 보겠습니다.
01:26:06서버를 중지하고요.
01:26:09실행합니다.
01:26:10그럼 이제 더미 데이터가 만들어졌습니다.
01:26:12앱이 완전히 준비되지 않았어도 이미 확인할 수 있을 겁니다.
01:26:17데이터베이스를 보면 posts와 comments 테이블이 보일 거예요.
01:26:21users 테이블에는 제가 만든 사용자가 있네요.
01:26:23posts 테이블에는 더미 게시물들이 들어 있습니다.
01:26:27comments 테이블에도 더미 댓글들이 있네요.
01:26:33각 댓글은 특정 사용자 및 게시물 ID와 연결되어 있습니다.
01:26:36사용자는 하나뿐이니까요.
01:26:38그래서 모두 한 명의 사용자에 연결된 겁니다.
01:26:40시더에 그렇게 썼으니까요.
01:26:41게시물을 보면, 여기 댓글이 5개 달린 게시물이 있네요.
01:26:47여기에는 댓글이 3개 달려 있고요.
01:26:50우리가 작성한 대로 잘 됐습니다.
01:26:52네.
01:26:53이제 여기서 뭘 했는지 이해가 갑니다.
01:26:55REPL로 데이터를 쿼리할 필요는 없겠네요.
01:26:57이미 데이터가 있는 걸 봤으니까요.
01:27:00하지만,
01:27:01코드를 좀 살펴보죠.
01:27:02재미있는 점은, 이런 모델 기반 접근 방식에서는 SQL 쿼리를 직접 작성할 필요가 없다는 겁니다.
01:27:10대신 모델을 사용하거나 전체 모델에 접근하죠.
01:27:17모델에 그 이름을 등록했기 때문에 이 모델이 존재하는 겁니다.
01:27:20그리고 'all' 같은 메서드를 써서 게시물을 전부 가져올 수 있습니다.
01:27:24아니면 여기 보는 것처럼 where 절을 사용해 게시물 개수를 제한하는 쿼리를 작성할 수도 있고요.
01:27:30이게 바로 ORM이 작동하는 방식입니다.
01:27:32SQL 문을 직접 쓰지 않고도 프로그래밍 방식으로 데이터를 쿼리하는 거죠.
01:27:37사실 전 ORM의 열렬한 팬은 아닙니다. 싫어하는 건 아니지만 평소에 잘 안 써요.
01:27:46특히 요즘은 AI 덕분에 원시 SQL 쿼리 작성이 그 어느 때보다 쉬워졌으니까요.
01:27:52그래서 저는 보통 애플리케이션에서 원시 SQL 쿼리를 사용합니다.
01:27:58ORM을 안 쓰는 거죠.
01:28:00원시 쿼리를 작성하면 모든 성능을 온전히 활용할 수 있으니까요.
01:28:06사실 AI가 나오기 전에도 쿼리가 그렇게 어렵지는 않았습니다.
01:28:10조인이 포함되어도 별로 어렵지 않거든요.
01:28:13물론 SQL 쿼리가 꽤 복잡해질 때도 있고 AI가 틀릴 때도 있습니다.
01:28:18하지만 제 경험상 꽤 복잡한 쿼리도 꽤 잘 작성합니다.
01:28:22그건 그냥 제 의견일 뿐이고요.
01:28:24어쨌든 여기선 ORM을 쓰니 저도 그대로 따르겠습니다.
01:28:29라우트, 컨트롤러, 그리고 뷰.
01:28:32지난 챕터에서 저희는 데이터베이스 테이블과 관계를 갖춘 포스트 및 댓글 모델을 만들었죠.
01:28:37이제 사용자가 게시물을 볼 수 있는 페이지를 구축해 그 모델들에 생명력을 불어넣을 겁니다.
01:28:46게시물과 댓글은 데이터베이스에만 존재하니까요.
01:28:49서버는 이미 켜져 있습니다.
01:28:52자, 이제 새로운 컨트롤러를 만들어 봅시다.
01:28:54제가 이해하기로 이 프레임워크의 개념은 라우트, 컨트롤러, 뷰를 갖추는 것입니다.
01:29:02그러니 아주 예전부터 있었던 MVC 방식이죠.
01:29:07모델 뷰 컨트롤러요.
01:29:09웹 애플리케이션뿐만 아니라 다양한 애플리케이션을 구조화하는 아주 오래된 방식입니다.
01:29:18오래됐다고 나쁘다는 건 아닙니다. 확실히 말씀드리고 싶네요.
01:29:24하지만 요즘 Next.js 같은 애플리케이션들에서는 잘 안 보이죠.
01:29:30그래서요.
01:29:31다른 탭에서 새로운 포스트 컨트롤러를 만들어 실행하겠습니다.
01:29:38빈 파일이 생겼고, 여기서 4개의 서로 다른 라우트에서 수행할 작업을 정의하는 메서드들을 등록할 겁니다.
01:29:44시간을 절약하기 위해 이 코드도 복사해 넣겠습니다.
01:29:47여기에 인덱스 메서드가 있습니다.
01:29:52HTTP 컨텍스트를 가져오는데, 이건 다양한 데이터를 제공해 주는 녀석이죠.
01:29:57사실 이걸 수정해야 합니다. 왜냐하면 저는 Inertia를 사용해야 하거든요.
01:30:05Inertia를 써야 하니 당연히 그 컴포넌트도 추가해야 합니다.
01:30:09우리가 여기서 하는 건 모델 파일에서 정의했던 포스트 클래스를 사용하는 겁니다.
01:30:16앞서 정의했던 바로 그 포스트 클래스 말이죠.
01:30:20ORM이 작동하는 방식인데, 쿼리를 생성 중입니다.
01:30:24사용자 정보를 미리 로딩(preloading)하면, 게시물을 가져올 때마다 다시 가져오지 않아도 될 겁니다.
01:30:32그리고 게시물을 생성 날짜 내림차순으로 정렬하고요.
01:30:38그러면 가장 최신 게시물이 첫 번째로 오게 되겠죠.
01:30:45그리고 렌더링을 할 건데, 추가가 필요할 겁니다.
01:30:53라우트를 정의하죠.
01:30:56자, 이제 'start routes' 파일로 이동합니다.
01:31:03여기에 추가했어요.
01:31:07물론 어디에나 추가할 수 있죠.
01:31:10그런데 왜 안 되는 거죠?
01:31:12왜 작동을 안 하지?
01:31:13개발 서버를 다시 시작해야 하나요?
01:31:16아, 잘못했네요.
01:31:18아, 개발 서버를 안 켰었군요.
01:31:21제 실수입니다.
01:31:22자, 이제 다시 켜겠습니다. 그러면 되겠죠.
01:31:25이제 자동으로 생성되었습니다.
01:31:26아도니스가 즉석에서 여러 타입 정의를 만들고 있는 겁니다.
01:31:31이제 됐습니다.
01:31:34아도니스에게 '/posts'로 들어오는 GET 요청을 처리하라고 알려줍니다.
01:31:40PostsController의 인덱스 메서드를 실행하라고요.
01:31:43그게 바로 이 메서드입니다.
01:31:47이제 뷰가 필요합니다.
01:31:50새 뷰를 만들어 보죠.
01:31:53이 명령어가 Inertia 뷰를 만드는 게 맞는지는 모르겠네요.
01:31:56어디 봅시다.
01:31:59'node ace list'를 입력해서 무엇을 만들 수 있는지 확인할 수 있습니다.
01:32:04뷰를 만들 순 있는데 그건 Edge.js 템플릿 파일이거든요.
01:32:08그건 아니에요.
01:32:11직접 만들어야 하나 봅니다.
01:32:20직접 만들어야겠네요. 그리 어렵진 않을 겁니다.
01:32:24자, Inertia 페이지로 이동하죠.
01:32:29여기에 'posts'를 추가할 겁니다.
01:32:31그 안에 'index.js' 파일을 만들면 되겠죠?
01:32:34그리고 기본 함수를 export할 거고요.
01:32:38이름은 'Posts'라고 짓겠습니다.
01:32:41그리고 '내 게시물' 같은 내용을 넣죠.
01:32:44그냥 평범한 React 컴포넌트입니다.
01:32:50자, 에러가 없어졌네요.
01:32:51방금 그 파일을 추가했으니까요, 맞죠?
01:32:55'posts' 폴더와 'index.js' 파일을 추가했습니다.
01:32:58제가 말한 게 바로 그거예요.
01:32:59이렇게 연결되는 겁니다.
01:33:02이제 개발 서버가 돌아가고 있으니까,
01:33:05여기로 가서 '/posts'를 치면 게시물들이 보일 겁니다.
01:33:09잘 작동하네요.
01:33:10이제 컨트롤러에서 데이터를 가져와 컴포넌트로 전달해야 합니다.
01:33:20사실 props로 벌써 전달하고 있다고 생각합니다.
01:33:23문제는 여기서 이걸 받을 수 있느냐는 거죠.
01:33:30어떻게 해야...
01:33:33아, children을 써야 하나 봅니다.
01:33:36다른 파일에선 어떻게 하고 있죠?
01:33:40데이터를 전달하는 파일이 있나요?
01:33:45없네요.
01:33:46없어요, 없어요.
01:33:50레이아웃에 있죠?
01:33:52children.
01:33:54이게 제가 필요한 거라고 생각합니다.
01:33:58이렇게 해본 적이 없어서,
01:34:00알아봐야겠네요.
01:34:19여기에 있는 게 아닌가요?
01:34:23아, 맞다. 제 잘못입니다.
01:34:25이건 올바른 TypeScript 코드가 아니죠.
01:34:27이렇게 해야 합니다.
01:34:30좋아요.
01:34:30이제 import들을 추가해야 합니다.
01:34:36import 추가요.
01:34:38이게 맞다고 봅니다.
01:34:40이게 우리가 가진 건가요?
01:34:41데이터, 생성된 데이터.
01:34:42네.
01:34:43좋아요.
01:34:45좋아요.
01:34:45자, 이제 한번 봅시다.
01:34:46여기에 프래그먼트를 추가할 수 있을까요?
01:34:50그리고 이런 식으로 하는 거죠.
01:34:54Children이요.
01:34:57Props.
01:34:59음.
01:35:02사용자요.
01:35:03아니, 공유 프롭이 아닐 수도 있어요.
01:35:04어떻게 가져와야 하죠?
01:35:06아마도 제가 파고들어야 할 것 같아요.
01:35:10어디 봅시다.
01:35:11아마도 Inertia 문서를 좀 살펴봐야겠네요.
01:35:15가이드.
01:35:17Inertia가 어디 있지?
01:35:19컴포넌트에 프롭을 어떻게 전달하더라?
01:35:24필요한데.
01:35:25트랜스포머가 필요한가?
01:35:29모델 인스턴스를 일반 객체로 직렬화하려면 트랜스포머를 사용하세요.
01:35:33알겠어요.
01:35:34알겠어요.
01:35:35알겠어요.
01:35:37좋아요.
01:35:37그래서 여기서는 조금 편법을 쓸 겁니다.
01:35:40AI를 좀 가져오죠.
01:35:44음.
01:35:48Adonis JS 앱을 빌드 중인데.
01:35:51JS 앱.
01:35:53게시물을 가져와야 해요.
01:35:56보세요.
01:35:57포스트 컨트롤러.
01:36:02제 포스트 Inertia로요.
01:36:04이런.
01:36:05이게 당신에게 읽기 좋게 안 보인다는 걸 알아요.
01:36:10좋아요.
01:36:10좋아요.
01:36:10잠시만요.
01:36:18좋아요.
01:36:18Adonis JS 앱을 빌드 중인데.
01:36:20JS 앱.
01:36:21게시물을 가져와야 해요.
01:36:24제 포스트 컨트롤러에서요.
01:36:27추가.
01:36:28이런.
01:36:28포스트 컨트롤러 추가.
01:36:30컨트롤러.
01:36:32제 게시물로.
01:36:35뷰.
01:36:35Inertia.
01:36:37뷰.
01:36:39그러니까, 그건 여기 posts 폴더의 index예요.
01:36:45이 페이지들로 연결할 겁니다.
01:36:48확인 부탁드려요.
01:36:50그리고.
01:36:56그걸 하도록 도와줘.
01:36:59그걸 알아낼 수 있는지 봅시다.
01:37:03음.
01:37:03ORM은 스키마 변환과 협업에 좋죠.
01:37:07음.
01:37:08네.
01:37:09또 말하지만.
01:37:09전 말 안 해요.
01:37:10ORM은 나쁘다.
01:37:11단지.
01:37:11제 프로젝트에는 딱히 필요가 없을 뿐이죠.
01:37:14하지만 또.
01:37:14대규모 팀에서 일하거나 하는 건 아니라서요.
01:37:18음.
01:37:18전.
01:37:19분명히.
01:37:20말하죠.
01:37:21마이그레이션은 사용한다고 말이죠.
01:37:23그러니까.
01:37:23딱히.
01:37:24안 하는 건.
01:37:25마이그레이션을 안 쓰는 게 아니에요.
01:37:26그런 거랑은 다르죠.
01:37:27음.
01:37:28그냥 저도.
01:37:29직접 작성합니다.
01:37:30아니면.
01:37:31LLM이 작성하게 하죠.
01:37:32그래서 마이그레이션은 정말 유용해요.
01:37:34전 그냥 ORM 부분이 필요 없는 것뿐이에요.
01:37:36궁금했거든요.
01:37:36와이프 코딩에 대해 물어보는 게.
01:37:37좋은지 아닌지.
01:37:38전 생각 안 해요.
01:37:39와이프 코딩이.
01:37:40와이프 코딩이.
01:37:41좋다고 생각하지 않아요.
01:37:42심각한 작업을 하기에는요.
01:37:43하지만.
01:37:44와이프 코딩은.
01:37:44분명히 아주 좋죠.
01:37:45그저 필요한 거라면.
01:37:46빠른.
01:37:47유틸리티 도구.
01:37:48아니면 그저.
01:37:48일 처리를 빠르게 해야 한다면요.
01:37:50맞아요.
01:37:50소프트웨어를 만들고 있다면.
01:37:51판매할 거라면.
01:37:52만약에.
01:37:53심각한 작업을 하고 있다면.
01:37:55배포할 계획이 있거나.
01:37:56아니면 직장에서라면.
01:37:57와이프 코딩은.
01:37:58그냥 놓치게 되죠.
01:37:59모든 흐름을요.
01:38:00이해를 못 하는 거예요.
01:38:01코드베이스에서 무슨 일이 일어나는지를요.
01:38:02결국엔.
01:38:03벽에 부딪힐 거예요.
01:38:04그리고.
01:38:04어떻게 계속할지 모를 거고요.
01:38:06그러니까.
01:38:07코드에 신경 쓰지 않는 건.
01:38:08좋은 해결책이 아닙니다.
01:38:09그런.
01:38:09그런 상황에서는요.
01:38:11하지만 또.
01:38:11그저 필요한 거라면.
01:38:13음.
01:38:13빠른.
01:38:15도구라면.
01:38:16내 컴퓨터에서 돌릴.
01:38:17아니면 그런 비슷한 거라면요.
01:38:18신경 안 써도 될지도 모르죠.
01:38:19음.
01:38:20세세한 것까지.
01:38:21모든 디테일.
01:38:23그런 것들요.
01:38:24그러니까 네.
01:38:25와이프 코딩이 거기선 좋을 수 있죠.
01:38:26그리고 네.
01:38:26라이브 코딩은 언제나.
01:38:28언제나 도전적이죠.
01:38:29하지만 AI가 해결할 수 있을지 봅시다.
01:38:31여기서 린팅 오류와 씨름하고 있는 것 같네요.
01:38:36하지만 네.
01:38:38전 그냥 AI를 쓰고 있어요.
01:38:40그나저나.
01:38:40평소라면 제가 직접 들어가서.
01:38:41제 손으로 빌드했을 거예요.
01:38:44하지만 20분 안에 나가야 해서요.
01:38:47차라리 완성된 코드를 지금 받고.
01:38:49그걸 검토하며 작업하는 게 나아요.
01:38:51그리고 지금.
01:38:52그 후에 여기에서 계속할 수 있게 말이죠.
01:38:54그게 주된 이유예요.
01:38:56그래서 네.
01:38:56지금 뭔가 했네요.
01:38:58먼저 이게 작동하는지 봅시다.
01:39:00제가 설명하기 전에요.
01:39:02그리고 얘가 뭘 했는지 보죠.
01:39:04그런데 좋아 보이네요.
01:39:05스타일링은 완전히 엉망이지만.
01:39:07보다시피.
01:39:10여기 게시물들이 렌더링되고 있어요.
01:39:12제 사용자와 연결된 것도 볼 수 있고요.
01:39:16그러니까.
01:39:17컨트롤러에서 데이터를 보내는 게.
01:39:19작동하는 것 같네요.
01:39:19자 이제 봅시다.
01:39:20어떻게 작동하는지.
01:39:22그리고 또.
01:39:22공식 문서 링크를 줬었어요.
01:39:24그러니까 그건 그냥.
01:39:28그냥.
01:39:31문서가 가르쳐 줬을 법한 내용이죠.
01:39:34그러니까 포스트 컨트롤러에서.
01:39:36게시물을 가져오고.
01:39:38여기서 바뀐 유일한 것은.
01:39:39본질적으로.
01:39:40우리가.
01:39:41게시물을 전달한다는 거죠.
01:39:42하지만 이렇게 날것 그대로가 아니라.
01:39:43대신.
01:39:44포스트 트랜스포머의 도움을 받아.
01:39:45그게 새로 추가된 거예요.
01:39:47그러니까 이 파일은 새로 생긴 거죠.
01:39:48포스트 트랜스포머.
01:39:50그리고 그건 클래스예요.
01:39:51베이스 트랜스포머를 상속받은.
01:39:53좋아요.
01:39:53그 안에서.
01:39:54우리는 그냥 설명하는 거예요.
01:39:55게시물을 직렬화하는 방법을.
01:39:56그러니까 말하자면.
01:39:57헤이.
01:39:58이 속성들을 전부 다 골라.
01:40:01그리고.
01:40:02사용자에 대해서도.
01:40:03사용자도 변환해 줘.
01:40:04그러니까 본질적으로.
01:40:05제 말은, 이런 경우엔.
01:40:06변환은 꽤 간단할 겁니다.
01:40:08아마 그저 취하는 거겠죠.
01:40:11ISO 형식을요.
01:40:12날짜 형식이요.
01:40:13여기에 있는 날짜들이요.
01:40:14그리고 다른 원시 데이터는,
01:40:15담을 수 있죠.
01:40:16자바스크립트 객체 안에요.
01:40:17이렇게 말이죠.
01:40:18그러니까 기본적으로는,
01:40:19설명하는 겁니다.
01:40:20변환 방법을요.
01:40:21클래스를요.
01:40:21내용물을 포함하고 있을 수 있는,
01:40:23쉽게 변환되지 않을 수도 있는 내용을요.
01:40:25JSON으로요.
01:40:26어떻게 변환할지 말이죠.
01:40:27그걸 JSON으로요.
01:40:28그게 바로,
01:40:28트랜스포머가 할 일입니다.
01:40:30제가 이해하기로는요.
01:40:33네.
01:40:33그럼 여기서 포스트들을 설정하고,
01:40:34이제,
01:40:35뷰에서요.
01:40:40뷰에서요.
01:40:41페이지를 가져옵니다.
01:40:42좋아요.
01:40:43그냥 설정하는 겁니다.
01:40:43이런 식으로 페이지 속성을요.
01:40:44네.
01:40:45그냥 설정하는 거죠.
01:40:46속성 타입을요.
01:40:47타입스크립트 타입을요.
01:40:48Inertia 속성을 사용해서요.
01:40:51대신에요.
01:40:51일부 생성된 타입들 대신에요.
01:40:54아니면,
01:40:55AI가,
01:40:56그걸 추가했나요?
01:40:57제 생각엔,
01:40:58그건,
01:40:58표준 타입들인 것 같네요.
01:41:00아니,
01:41:00AI가 생성한 건 아니고요.
01:41:02그리고,
01:41:02그냥 이렇게 말하는 거죠.
01:41:03네.
01:41:03여기요.
01:41:04여기에,
01:41:04포스트 키가 있을 겁니다.
01:41:06그리고,
01:41:06그건,
01:41:07타입이죠.
01:41:08네.
01:41:08그러니까 그건,
01:41:09자동 생성된,
01:41:10타입입니다.
01:41:10우리의,
01:41:11포스트에 대한 타입이죠.
01:41:12그리고 제 생각에는요.
01:41:13이 타입은,
01:41:14생성되는 겁니다.
01:41:15우리가 어떻게,
01:41:15변환하느냐에 따라서요.
01:41:16포스트를요.
01:41:17그러니까 여기 포스트는,
01:41:20이건요.
01:41:23네.
01:41:24포스트 트랜스포머에서 오고 있죠.
01:41:25맞아요.
01:41:27좋아요.
01:41:28그리고 나서 그냥,
01:41:29여기서 렌더링하면 됩니다.
01:41:30그렇게 어렵지 않아요.
01:41:32알겠습니다.
01:41:35네.
01:41:36자 다시,
01:41:36공식 튜토리얼은 여기,
01:41:38엣지 뷰를 사용합니다.
01:41:39그래서요.
01:41:39저는 관성을 사용하고 있고요.
01:41:40그리고,
01:41:41보시다시피요.
01:41:41결국엔 그냥 리액트 앱입니다.
01:41:43결국엔요.
01:41:44거기서 우리는 또한,
01:41:46변환하고,
01:41:46우리의,
01:41:48속성을 보냅니다.
01:41:50네.
01:41:53단일 포스트를 표시하는 건,
01:41:54네.
01:41:55물론이죠.
01:41:55그러니까 이제,
01:41:55추가할 수 있습니다.
01:41:56다른,
01:41:56메서드를요.
01:41:58여기 메서드를요.
01:42:00우리의,
01:42:00컨트롤러에,
01:42:01왜냐하면,
01:42:02우리의,
01:42:02포스트,
01:42:03컨트롤러에,
01:42:03현재로서는,
01:42:04하나가 있거든요.
01:42:05인덱스,
01:42:05메서드가요.
01:42:05모든,
01:42:06포스트를,
01:42:07표시하는 거요.
01:42:08하지만 이제,
01:42:08우리는 원합니다.
01:42:08또한,
01:42:09메서드를 추가하길요.
01:42:09단일,
01:42:10포스트를,
01:42:10표시하는,
01:42:10방법을요.
01:42:11그래서,
01:42:11추가하는 겁니다.
01:42:12쇼,
01:42:12메서드를요.
01:42:12여기요.
01:42:13보이는 것처럼요.
01:42:14그리고 다시,
01:42:14이 이름들은,
01:42:16여러분이 정하기 나름입니다.
01:42:16나중에,
01:42:17연결할 때요.
01:42:18그것들을요.
01:42:18라우트,
01:42:19파일에서요.
01:42:19꼭,
01:42:19확인하셔야 합니다.
01:42:20그것들이 일치하는지,
01:42:20확인해야 합니다.
01:42:21하지만 잠시 후에,
01:42:21보게 될 겁니다.
01:42:23그래서 여기,
01:42:23파라미터들을,
01:42:24받고 있죠.
01:42:25왜냐하면 이제,
01:42:25우리는,
01:42:26동적,
01:42:26라우트를,
01:42:26가지고 있으니까요.
01:42:27그리고 다시,
01:42:28아실지도 모르겠네요.
01:42:28리액트나,
01:42:28뭐 그런 것들에서요.
01:42:29그게,
01:42:29라우트들이죠.
01:42:30콜론,
01:42:30콜론을 가진,
01:42:31콜론 파라미터요.
01:42:31파라미터요.
01:42:32라우트,
01:42:32이름에서,
01:42:33예를 들어,
01:42:33예를 들면요.
01:42:34혹은,
01:42:34달러,
01:42:35사인이요.
01:42:35파일,
01:42:35이름에서,
01:42:36그렇죠.
01:42:37그래서 여기,
01:42:38우리도 또한,
01:42:38받고 있습니다.
01:42:39동적,
01:42:39파라미터들을요.
01:42:40그리고 어떻게,
01:42:40등록하는지,
01:42:41보게 될 겁니다.
01:42:42그 라우트들을요.
01:42:43그리고 나서,
01:42:43예상합니다.
01:42:44가질 것을요.
01:42:44ID를,
01:42:45파라미터를요.
01:42:46그러니까 찾고 있는,
01:42:46포스트를요.
01:42:46포스트를요.
01:42:47특정,
01:42:48ID를 가진 포스트를요.
01:42:49원합니다.
01:42:49실패하길요.
01:42:50만약,
01:42:50못 찾는다면요.
01:42:51그래야 우리가,
01:42:52404 에러를 보여줄 수 있거든요.
01:42:53아니면 다른 에러라도요.
01:42:54제 생각에는요.
01:42:55원합니다.
01:42:55렌더링하는 것을요.
01:42:57뷰가 아니라요.
01:42:58대신에,
01:42:58우리는 원합니다.
01:42:59렌더링하려고 합니다.
01:43:05우리는
01:43:05가져오길
01:43:06Inertia를 원합니다.
01:43:09그리고 재사용하죠.
01:43:10포스트
01:43:11변환기를요.
01:43:12전달하기 위해
01:43:13우리 포스트를
01:43:14그
01:43:17쇼 컴포넌트로
01:43:18예를 들면
01:43:18말이죠.
01:43:19그래서
01:43:20이제
01:43:20Inertia
01:43:21폴더 내의
01:43:21포스트
01:43:22폴더에
01:43:22우린
01:43:23가지고 있어야
01:43:23합니다.
01:43:24show.tsx나
01:43:24아니면
01:43:25detail.tsx
01:43:26같은 게 필요하죠.
01:43:26혹은
01:43:26그런 거면
01:43:27뭐든요.
01:43:28그리고
01:43:29이제
01:43:29그 안에
01:43:31우린
01:43:35우리
01:43:35우리
01:43:35포스트
01:43:36컴포넌트를
01:43:36가집니다.
01:43:38사실
01:43:40이름을 정하죠.
01:43:42Post라고.
01:43:45Post.
01:43:47이런 식으로요.
01:43:48그런 다음
01:43:49전과 마찬가지로
01:43:50제가
01:43:50재빨리
01:43:51가져오겠습니다.
01:43:55단일
01:43:55포스트를 얻었죠.
01:43:56여기요.
01:43:56배열이 아닙니다.
01:44:00이걸 선택하고
01:44:01그럼
01:44:01우린
01:44:02반환할 수
01:44:05있죠.
01:44:05물론이죠.
01:44:06포스트
01:44:06제목을요.
01:44:07이런 식으로요.
01:44:11안녕하세요.
01:44:12네,
01:44:12이런 식으로요.
01:44:13좋아요.
01:44:16여기서 뭘 하고 있는 거죠?
01:44:17그러니까
01:44:19그리고
01:44:19물론
01:44:19또한
01:44:20그
01:44:21포스트
01:44:21요약도
01:44:21예를 들어서요.
01:44:22네,
01:44:23좋아요.
01:44:23이걸 가져오면
01:44:24음,
01:44:25잘 작동할 겁니다.
01:44:26이제
01:44:27라우트 폴더에 등록해야 합니다.
01:44:28그러니 이제
01:44:30추가할 수 있죠.
01:44:30새로운
01:44:31어,
01:44:32GET 라우트를요.
01:44:33슬래시
01:44:34슬래시
01:44:35포스트요.
01:44:35그런 다음
01:44:36제 생각엔
01:44:37이렇게 동적 라우트를
01:44:38등록하는 것 같아요.
01:44:39어디 봅시다.
01:44:41네,
01:44:42콜론 ID로요.
01:44:44아주 전형적이죠.
01:44:45이제
01:44:46말하자면
01:44:46있잖아요.
01:44:47우리 포스트 컨트롤러의
01:44:48show 메서드에
01:44:49관심이 있는 겁니다.
01:44:51왜냐면
01:44:52그 컨트롤러에서
01:44:53이 메서드 이름을
01:44:54show라고
01:44:54지었으니까요. 여기서 다른
01:44:56이름을 선택하면 여기도 바꿔야
01:44:58합니다. 하지만 전 show를
01:44:59쓰고 있으니까 잘 될 겁니다.
01:45:02그러니까
01:45:05어떤 링크가 있죠?
01:45:08오,
01:45:08상세 링크가 아니네요.
01:45:10하지만 posts/1을 더하면
01:45:13네,
01:45:14불러와지네요.
01:45:15스타일링은 엉망이지만요.
01:45:16여기 맨 아래를 보면
01:45:17그
01:45:18콘텐츠를
01:45:19볼 수 있죠.
01:45:20그리고
01:45:21제목도요.
01:45:22마크다운 블로그 엔진이
01:45:24여기 있네요.
01:45:25스타일링은 완전히 깨졌지만요.
01:45:26그래도
01:45:27작동은 하네요.
01:45:28그 라우트를 볼 수 있어요.
01:45:31물론 스타일링은 고칠 수 있지만
01:45:32지금 당장 제일 중요한 건 아니죠.
01:45:35네, 그래요.
01:45:36뷰를 얻었네요.
01:45:37이미 다 해결된 거죠.
01:45:39명명된 라우트를 써서요.
01:45:40오, 재밌네요.
01:45:40네,
01:45:41지금은 URL을 하드코딩 중이에요.
01:45:44링크는 하나도 설정 안 했거든요.
01:45:47그래서
01:45:49라우트 정의에서 컨트롤러를 사용하면
01:45:51Adonis.js가 라우트 이름을 자동으로
01:45:54컨트롤러와 메서드 명을 기반으로
01:45:56생성해 줍니다. 그러니까 controllers.posts.index가
01:45:58있다면
01:45:59자동으로 posts.index라는 이름을 갖게 돼요.
01:46:02그러니 제 생각엔 가볼 수 있을 것 같아요.
01:46:05모든 포스트가 있는 포스트 인덱스 페이지로요.
01:46:08그리고 이런 앵커 태그 대신에
01:46:11사용할 수 있을 거예요.
01:46:12Link 컴포넌트를요.
01:46:13inertia.js react에서 오는 거죠.
01:46:17여기도요.
01:46:18그리고 잘 모르겠는데
01:46:19to 프로퍼티가 있나?
01:46:21아니면
01:46:21ref인가?
01:46:23그럼 이렇게 말할 수 있겠죠.
01:46:26routes.
01:46:29posts.show.
01:46:34이 방식은 아닌 것 같네요.
01:46:42posts.show.
01:46:49네,
01:46:49전 다른 접근 방식을 쓰고 있어요.
01:46:50이 Link 컴포넌트를 쓰고 싶거든요.
01:46:53다시.
01:46:55여기 어디에 이게 있나요?
01:46:57Link route.
01:46:59아, 알겠어요.
01:46:59그냥
01:47:01좋아요.
01:47:02그러니까 Link죠.
01:47:04Route.
01:47:08왜 route에서 에러가 나는 거죠?
01:47:11링크 생성.
01:47:12Link 컴포넌트는 내비게이션 링크를 만듭니다.
01:47:14아,
01:47:15임포트가 틀렸네요.
01:47:16어디서 가져와야 하는 건데.
01:47:20여기서요.
01:47:20Adonis 패키지요.
01:47:22이제 Route 지원을 받을 수 있죠.
01:47:24이제 posts뿐이네요.
01:47:33그냥 문자열입니다.
01:47:34그냥 문자열이에요.
01:47:35알겠어요.
01:47:35그러니까 그냥
01:47:37Route.
01:47:38알겠어요.
01:47:38이제 자동 완성이 좀 되네요.
01:47:40이제 params를 설정해야겠네요.
01:47:43Route params.
01:47:45posts.id요.
01:47:48아니요.
01:47:49post.id요.
01:47:53그럼 이건 객체여야겠네요.
01:47:57id는 post.id로 설정하고요.
01:48:00그러면 이제 모든 포스트마다 동적으로 다른 라우트가 생성될 겁니다.
01:48:03그리고 그 동적 자리 표시자를 포스트 ID로 채울 것이라고 생각합니다.
01:48:07그러니 이제 여기를 새로고침하면.
01:48:09여기가 아니고요.
01:48:10바로 여기죠.
01:48:14왜 업데이트가 안 됐죠?
01:48:16개발 서버를 재시작해야 하나요?
01:48:20아.
01:48:21파일을 저장하는 것도 아마 도움이 될 겁니다.
01:48:24네.
01:48:24이제 여기를 클릭해서 포스트로 이동할 수 있습니다.
01:48:28물론 스타일은 여전히 끔찍하지만요.
01:48:30그래도 작동은 합니다.
01:48:33그리고 당연히.
01:48:34여기서 라우트 이름을 사용하는 것의 장점은 경로를 변경하더라도
01:48:38링크를 변경할 필요가 없다는 것입니다.
01:48:40라우트 이름이 바뀌지 않는 한 말이죠.
01:48:42그래서 물론 아주 좋은 기능입니다.
01:48:44자.
01:48:45경로를 그렇게 자주 바꾸지는 않을 수도 있지만요.
01:48:47그래도.
01:48:48꽤 괜찮습니다.
01:48:52안녕하세요.
01:48:52키디 미(kiddie me)군요.
01:48:53네.
01:48:55라라벨에서 영감을 받은 것이 맞습니다.
01:48:57분명합니다.
01:48:58제 생각에 그들은 스스로를 '자바스크립트를 위한 라라벨'이라고 브랜드화하고 있는 것 같아요.
01:49:07직접 손으로 코딩해야 하나요?
01:49:09마치 어린아이 장난감 같네요.
01:49:12음.
01:49:17그래서.
01:49:18무언가를 배울 때는.
01:49:19확실히 직접 해봐야 합니다.
01:49:21손으로 직접 코드를 작성해 보는 것이죠.
01:49:23그냥 읽기만 해서는...
01:49:26저는 혼합해서 하는 편입니다.
01:49:28하지만 물론 라이브 스트림에서는.
01:49:29AI에게 다 맡겨버리면 별로 재미가 없죠.
01:49:30그래도 방금 전에 잠깐 사용하긴 했습니다.
01:49:33하지만 네.
01:49:36그렇지만요.
01:49:37배울 때는 확실히.
01:49:39직접 해봐야 합니다.
01:49:40읽기만 해서는.
01:49:44읽기만 하는 것으로는 학습이 잘 안 되거든요.
01:49:46이제.
01:49:474년 전처럼 코드를 전부 직접 짜야 한다고 말하려는 건 아닙니다.
01:49:50전혀 그렇지 않죠.
01:49:52하지만 최소한 기본적인 것들은요.
01:49:54느낌을 익히려면 말이죠.
01:49:56여기를 보면요.
01:49:56방금 들어오셨잖아요.
01:49:57저는 그냥 제가 쓴 것을
01:49:58그대로 복사하고 있었던 거죠.
01:49:59아니, 아니에요.
01:50:01음.
01:50:03코드.
01:50:03네.
01:50:03네.
01:50:03알아요.
01:50:04무슨 뜻인지 이해했어요.
01:50:05기분 나쁘지 않습니다.
01:50:06그냥.
01:50:07저는 코드를 작성하는 것이
01:50:09일반적으로 좋은 지점이라고 생각합니다.
01:50:10그래서 이에 대해 의견을 드리는 거예요.
01:50:12제 생각엔.
01:50:14코드를 작성하는 것은 여전히 학습에 좋습니다.
01:50:18하지만.
01:50:19비록 농담이었지만요.
01:50:21혹은 인용구였더라도.
01:50:24분명.
01:50:26이건.
01:50:26확실히 변하고 있습니다.
01:50:28그리고 아까 질문을 받았었는데.
01:50:32새로운 강좌에 대한 질문이었죠.
01:50:33한 가지 문제는.
01:50:34제가 알아내려고 하는 것은
01:50:35어떻게 하면
01:50:37지금 이 시점에 기술을 가장 잘 배울 수 있는가 하는 것입니다.
01:50:41여전히 중요한가에 대해서요.
01:50:42네, 그렇다고 말하고 싶네요.
01:50:43분명 여전히 중요합니다.
01:50:45하지만 네.
01:50:46바로 그 점이죠.
01:50:47얼마나 직접 손으로 작성하는가?
01:50:48얼마나 복사해서 붙여넣는가?
01:50:50또 얼마나 AI에게 설명하거나 생성하게 할 것인가?
01:50:52그게.
01:50:53그냥 두서없이 말하고 있네요.
01:50:54그냥 주절거리고 있어요.
01:50:54하지만 이건 확실히 변하고 있는 부분입니다.
01:50:57이것은 아도니스 JS(Adonis JS)입니다.
01:51:00그러니까.
01:51:00한마디로 자바스크립트용 라라벨(Laravel) 같은 거죠.
01:51:09좋아요.
01:51:09그래서.
01:51:14네.
01:51:15댓글.
01:51:16그건 하지 않을 것 같네요.
01:51:1810분 뒤에 가봐야 해서요.
01:51:20그러니 여기는 일단 이대로 놔두고.
01:51:22남은 몇 가지를 잠깐 살펴볼게요.
01:51:28여기 페이지들이요.
01:51:29어쨌든 이 가이드에는 별로 남은 게 없어요.
01:51:31꽤 잘 진행해 왔으니까요.
01:51:33폼과 유효성 검사.
01:51:35자, 여기 아이디어는 이겁니다.
01:51:37물론 컨트롤러 함수도 가질 수 있다는 것이죠.
01:51:40호출되는 컨트롤러 메서드 말입니다.
01:51:43POST 요청 시에 말이죠.
01:51:45그리고 그건 여기에서 볼 수 있습니다.
01:51:48사용자 컨트롤러가 없나요?
01:51:52사용자.
01:51:54이거.
01:51:54새로운 계정 컨트롤러요.
01:51:56여기요.
01:51:57스토어(store).
01:51:57그게.
01:51:59컨트롤러 메서드죠.
01:52:00호출되는 메서드요.
01:52:02POST 요청 시에요.
01:52:04이거요.
01:52:05그리고.
01:52:06따라서.
01:52:07그냥 일반적인 메서드입니다.
01:52:08하지만 그 안에서 벌써 볼 수 있죠.
01:52:10validateUsing 메서드를 사용할 수 있습니다.
01:52:13메서드요.
01:52:13그리고 유효성 검사기를 정의하죠.
01:52:14결국.
01:52:16작은 유틸리티 객체일 뿐입니다.
01:52:18여기 있는 바인(vine) 도구로 생성된 거요.
01:52:21받아들일 데이터의 규칙을 정의할 수 있죠.
01:52:22어떤 종류의 데이터를 수락할지 말이에요.
01:52:24그리고 나서.
01:52:24오류가 자동으로 생성될 겁니다.
01:52:26만약.
01:52:27유효성 검사 기준이 충족되지 않으면요.
01:52:29그러니까 라라벨의 전체 아이디어는.
01:52:30그리고 아도니스의 아이디어는.
01:52:30그들이 많은 일을
01:52:31당신을 대신해서 해준다는 겁니다.
01:52:33그래서 당신은.
01:52:33논리만 정의하면 되죠.
01:52:34꽤 높은 수준에서 말이죠.
01:52:36반면에.
01:52:37넥스트.
01:52:37JS.
01:52:37등에서는.
01:52:38종종 정말 구체적인 것까지 직접 해야 합니다.
01:52:41당연히.
01:52:41직접 유효성 검사 라이브러리를 가져와야 하고요.
01:52:43그런 모든 재미있는 일들을요.
01:52:52그래서 여기서 우리가 하고 있는 것은.
01:52:54라우트를 등록하는 것입니다.
01:52:56이미 봤던 내용이죠.
01:52:59이 경우 새로운 뷰를 만들고요.
01:53:00그리고 여기서는 포럼을 만들고 있습니다.
01:53:02이건 다들 특정 에지(Edge) 문법입니다.
01:53:05코드 조각들이죠.
01:53:06하지만 물론.
01:53:08여기서도 확인할 수 있습니다.
01:53:12어디 있죠?
01:53:13로그인.
01:53:14네.
01:53:14Inertia를 사용하고 있다면 확인할 수 있죠.
01:53:17여기 이 폼 컴포넌트가 있습니다.
01:53:19이건 Adonis.js Inertia 패키지에서 오는 것입니다.
01:53:22또한 라우트와도 연결되어 있죠.
01:53:24트리거되어야 하는.
01:53:25폼이 제출되면요.
01:53:26바로 그 스토어 라우트입니다.
01:53:27방금 본 것이요.
01:53:28아니면 그 스토어 컨트롤러 액션 말이죠.
01:53:30결국.
01:53:31그 라우트에 의해 호출되는 것이죠.
01:53:33그리고 데이터는.
01:53:34아마도.
01:53:36요청에 담겨서.
01:53:37자동으로 백엔드에 제출될 겁니다.
01:53:39물론 아주 편리한 거죠.
01:53:40그 코드를 직접 작성할 필요가 없으니까요.
01:53:42아니면 AI에게 작성해 달라고 할 필요도 없고요.
01:53:45에지를 사용하고 있다면요.
01:53:46폼 입력을 이렇게 렌더링할 수 있습니다.
01:53:48그리고 아마도.
01:53:50이게 이해하기가 좀 더 쉽고.
01:53:51읽기도 더 편하다고 봅니다.
01:53:56그리고 유효성 검사기를 만들 수 있습니다.
01:53:57아까 전에 하나 봤었죠.
01:53:58그 바인(vine) 도구를 이용해서요.
01:54:00단순히 정의만 하면 됩니다.
01:54:01받으려는 데이터에 대해
01:54:02어떤 규칙을 가질지 말이에요.
01:54:04그러니까 최소 길이,
01:54:05최대 길이,
01:54:06데이터 타입,
01:54:07그런 것들을요.
01:54:08등등이요.
01:54:10스토어 메서드를 가져오고,
01:54:11그다음에 다시,
01:54:11ORM을 사용할 수 있죠.
01:54:13우리 클래스를 사용해서,
01:54:14데이터를 저장하기 위해 정적 create 메서드를 호출합니다.
01:54:16데이터를 저장하려면 말이죠.
01:54:19댓글도,
01:54:20똑같이 하면 됩니다.
01:54:23사용자와 연결할 수도 있죠.
01:54:24ID를 통해서요.
01:54:26그리고 사용자를 얻게 됩니다.
01:54:28인증을 통해서요.
01:54:30속성이죠.
01:54:31자동으로 얻게 되는 속성입니다.
01:54:32다시 말하지만,
01:54:33이건 마치,
01:54:33Adonis가 자기 할 일을 하는 거죠.
01:54:35알아서 인증을 처리해 주는 겁니다.
01:54:37미들웨어 덕분이죠.
01:54:39등록되어 있는,
01:54:40그렇죠.
01:54:40그래서 라우트에서,
01:54:40몇 가지,
01:54:41인증 미들웨어를 가져옵니다.
01:54:42예를 들어서요.
01:54:43여기에 있는 모든 라우트는,
01:54:44인증이 필요합니다.
01:54:46그리고 저기에 있는 라우트들도,
01:54:48그러므로,
01:54:48역시 마찬가지로,
01:54:51이 인증 속성도 얻게 됩니다.
01:54:53속성 말이죠.
01:54:54사용할 수 있는,
01:54:55데이터를 얻기 위해,
01:54:56현재,
01:54:57인증된 사용자에 대한 정보를요.
01:54:58아니면,
01:54:59사용자를 로그아웃시킬 때도,
01:55:00이런 경우처럼요.
01:55:01기타 등등.
01:55:02그게 다입니다.
01:55:03꽤 편리하죠,
01:55:04일단 설정만 되면요.
01:55:06최소한 제 생각에는요.
01:55:07이전에,
01:55:08제가 이걸 다뤄본 건 아니지만요.
01:55:09그래도요.
01:55:11배웠습니다.
01:55:11당신으로부터 많은 걸요.
01:55:12그리고 그 원칙들을,
01:55:14코드에 전달했죠.
01:55:14코드 같은,
01:55:15고품질의,
01:55:16그래서 당신의 강의는,
01:55:16여전히 가치가 있어요.
01:55:17좋은 프롬프팅을 위해서요.
01:55:18네.
01:55:18그리고 제가 탐구 중인 한 가지는,
01:55:20어떻게,
01:55:20할 수 있을지,
01:55:22향후 강좌들에,
01:55:23요소를 넣는 거죠,
01:55:24에이전트 기술 같은,
01:55:25혹은 추가 문서들을요.
01:55:26제공할 수 있는,
01:55:27에이전트에게,
01:55:28도움이 되도록,
01:55:31더 나은 코드를 작성하도록요.
01:55:32물론 물론,
01:55:33보장할 수는 없겠지만요.
01:55:34왜냐하면 에이전트들은,
01:55:37항상 제멋대로,
01:55:38자기 마음대로 할 수 있으니까요.
01:55:39기타 등등.
01:55:40하지만 그건,
01:55:40저도 탐구 중인,
01:55:41분야죠.
01:55:42그리고 제가 선호하는 건,
01:55:43Adonis인가 View 3인가?
01:55:45Adonis는,
01:55:46방금 시작했을 뿐이고,
01:55:47이제 막 시작했으니까요.
01:55:48전에는 전혀 사용해 본 적이,
01:55:49없었고요.
01:55:50그리고 View 3는,
01:55:52진정한 대안은,
01:55:52아니에요.
01:55:53Adonis는,
01:55:54풀스택이니까요.
01:55:55반면 View는,
01:55:55클라이언트 사이드,
01:55:57프런트엔드니까요.
01:55:58Nuxt와 함께라면,
01:55:59풀스택이 될 수도 있죠.
01:56:00다시 말하지만,
01:56:00하지만,
01:56:01그래도 여전히,
01:56:02철학이 다릅니다.
01:56:03Adonis는,
01:56:04모든 기능을 포함하고 있으니까요.
01:56:06그래서,
01:56:06그런 것들,
01:56:07인증 같은 건,
01:56:08내장되어 있죠.
01:56:09반면 Nuxt는,
01:56:11Next와,
01:56:11Next와 마찬가지로,
01:56:12직접,
01:56:13라이브러리를,
01:56:14가져와야 하죠.
01:56:15결국,
01:56:16잘 모르겠네요.
01:56:17제가 뭘 선호하는지,
01:56:17전,
01:56:18Adonis 방식이 좋고,
01:56:19분명히,
01:56:21가치가 있다고,
01:56:22생각합니다,
01:56:23만약 당신이,
01:56:25풀스택 애플리케이션을,
01:56:27구축한다면요.
01:56:28이제,
01:56:28저는,
01:56:29너무 익숙해져서,
01:56:30Next JS에,
01:56:31그러니까,
01:56:31T3 스택에,
01:56:32그리고 그런 것들에,
01:56:33너무 익숙해서,
01:56:34글쎄요,
01:56:35잘 모르겠네요,
01:56:36Adonis로 바꿀지,
01:56:37단지,
01:56:37아마도,
01:56:38더 빠를 테니까요,
01:56:39다른,
01:56:40기술 스택들보다,
01:56:41하지만,
01:56:41그래도 다시 말하지만,
01:56:43좋은 이유들이,
01:56:44있어요,
01:56:45가지는 것 같은,
01:56:46그럼,
01:56:46더 적은,
01:56:47외부,
01:56:48의존성을요,
01:56:49Adonis 외에도요,
01:56:50뭐 이런 것들 말이죠,
01:56:51그래서,
01:56:51아마 계속,
01:56:52가지고 놀면서,
01:56:53계속,
01:56:54해볼 것 같네요,
01:56:55그리고,
01:56:55평가해 봐야죠,
01:56:56어디가 유용한지,
01:56:57제게,
01:56:58어디가 그렇지 않은지,
01:56:58더 많이 만들고 싶다면요,
01:57:00그걸로요,
01:57:02네,
01:57:03그게,
01:57:03본질적으로는,
01:57:04계획입니다,
01:57:05그리고 제 생각에,
01:57:07글쎄,
01:57:07아니,
01:57:08아니에요,
01:57:08그래도,
01:57:09스타일링은 딱히,
01:57:10신경 안 쓰여요,
01:57:10그건 그냥 CSS니까,
01:57:12하지만 권한 부여는,
01:57:13한번 살펴보고 싶네요,
01:57:16또 다른 패키지가 있거든요,
01:57:18설치할 수 있는,
01:57:19Adonis의,
01:57:20생태계 일부분이죠,
01:57:21밸런서 패키지요,
01:57:22그게 있어서,
01:57:24이름을 정하는 거죠,
01:57:25이 챕터의 이름은,
01:57:27제 생각엔,
01:57:27그건,
01:57:28책임이 있어요,
01:57:29사람들을 차단하는,
01:57:30허용되지 않은,
01:57:31뭔가를 하도록,
01:57:33물론,
01:57:35권한 부여는,
01:57:36인증과는 다르게,
01:57:37이것은,
01:57:39사용자를 차단하는,
01:57:40특정 행동을 못 하게요,
01:57:41허용되지 않은,
01:57:42할 수 없는,
01:57:43예를 들어,
01:57:44사용자가 로그인되어 있을 순 있지만,
01:57:46물론,
01:57:46수정할 순 없어야 하죠,
01:57:47게시물을 수정하는 것과 같은
01:57:48다른 사용자의 게시물을
01:57:49말이죠.
01:57:51그러니
01:57:52인증만으로는
01:57:52충분하지 않습니다.
01:57:53종종 필요한 것은
01:57:54인가입니다.
01:57:55게다가
01:57:57바로 그 지점에서
01:57:57이 Bouncer 패키지가
01:57:58유용해 보입니다.
01:58:01왜냐하면
01:58:01이른바
01:58:02정책을 만들 수
01:58:03있기 때문입니다.
01:58:04살펴보자면,
01:58:05정책은 하나의 클래스입니다.
01:58:07확장하는 클래스죠.
01:58:07클래스인데,
01:58:08Adonis의
01:58:09Bouncer
01:58:10패키지에서 가져온 것이죠.
01:58:11그리고 나서 정의할 수 있습니다.
01:58:13자,
01:58:13기본적으로
01:58:15권한을 여기서 정의할 수 있어요.
01:58:16예를 들어
01:58:17사용자 ID가
01:58:18수정을 허용하는지
01:58:20일치하는지를 보는 거죠.
01:58:21게시물 작성자의
01:58:22ID와 말이죠.
01:58:23수정하려는 게시물의요.
01:58:24삭제도 마찬가지고요.
01:58:26그리고 그런 다음에는 아마
01:58:27해당 정책을 적용할 수 있겠죠.
01:58:29한번 봅시다.
01:58:30우리...
01:58:30우리에겐 정책이 있습니다.
01:58:34컨트롤러 메서드를 추가하는 것 말이죠.
01:58:43어디에 적용하는지 볼까요?
01:58:44아, 그래요.
01:58:45여기네요.
01:58:45자,
01:58:46우리 컨트롤러에서
01:58:48우리는
01:58:48여기,
01:58:49새로운 메서드를 추가했어요.
01:58:50편집(edit) 메서드죠.
01:58:51이건 분명히 실행되어야 합니다.
01:58:52만약 당신이
01:58:52뭔가를,
01:58:53폼을 제출하려고 하거나
01:58:54게시물을 수정하고 싶을 때 말이죠.
01:58:56아니면
01:58:57페이지를 불러오고 싶을 때,
01:58:58게시물 수정 페이지를 말이죠.
01:58:59이제 보니까 그렇네요.
01:59:01이 메서드에서 우리는
01:59:02수정하고 싶은
01:59:03게시물을 찾고 있습니다.
01:59:04수정하려는 게시물을요.
01:59:05그런데,
01:59:06뷰를 반환하기 전에,
01:59:08이 Bouncer 패키지가
01:59:09우리에게 기능을 제공합니다.
01:59:11정책을 불러올 수 있는,
01:59:12우리가 적용하려는
01:59:13정책을 말이죠.
01:59:14그리고 기본적으로
01:59:15정책을 통해 확인합니다.
01:59:16사용자가,
01:59:17이것을 수정하려는 사용자가
01:59:19허용되는지 확인하는 거죠.
01:59:23이해되시죠?
01:59:25좋습니다.
01:59:27자, 한번 보죠.
01:59:29챗.
01:59:30AI는 앱을 만들 수 있어요.
01:59:31같은 라이브러리 내에서도
01:59:3210가지 방식으로요.
01:59:33그러니 아마
01:59:34프로그래밍 패러다임에,
01:59:35코드를 구성하는 방법에 집중하세요.
01:59:37네.
01:59:38물론입니다.
01:59:38저는 생각합니다.
01:59:39이것들이 중요한 기술이라고요.
01:59:41개발자들에게나
01:59:42AI에게나 말이죠.
01:59:44문서를 통해서,
01:59:45기술을 통해서,
01:59:46당신이 가르치는
01:59:47특정한 패턴을 통해서요.
01:59:48당신이 알고 있는
01:59:49기본기 같은 것들이요.
01:59:50그런 거 말입니다.
01:59:51그래서 제가
01:59:52계획하고 있는 겁니다.
01:59:53프로그래밍 기초,
01:59:54시스템 설계,
01:59:55그리고 그 모든
01:59:55재미있는 것들에 대한 강좌를요.
01:59:57더 나은 선택이 있을 때,
01:59:58백엔드 웹 API를 할 때는
02:00:00C# 같은
02:00:01강타입 언어가 더 낫죠.
02:00:02그리고
02:00:03잘 모르겠네요.
02:00:03왜 여기서 검열됐는지 말이죠.
02:00:05아니면 Node.js에 의존하거나,
02:00:06TypeScript를 쓰죠.
02:00:07타입이 삭제되기도 하고요.
02:00:08NPM 패키지에는 수많은 취약점이 있죠.
02:00:09그러니까 결국,
02:00:12백엔드 언어에 관해서라면
02:00:13그것만으로도 아마 한 시간은
02:00:15이야기할 수 있을 거예요.
02:00:16그럴 시간은 없지만요.
02:00:17하지만
02:00:18Node.js의
02:00:20큰 장점은
02:00:21그리고 전체 JavaScript
02:00:22생태계의 장점은
02:00:23물론
02:00:24AI가 정말 잘 안다는 것이죠.
02:00:24개발에 AI를 사용할 계획이라면
02:00:26사용할 수 있는 패키지가 정말 많죠.
02:00:28하지만 물론
02:00:28공급망 공격 같은
02:00:30거대한 단점이 있죠.
02:00:31그리고 다른 것들도요.
02:00:32물론이죠.
02:00:33다른 언어들도
02:00:34더 나은 성능을
02:00:35제공할 수 있습니다.
02:00:36저는 분명히
02:00:38사용을 고려할 거예요.
02:00:39Go나 Rust, 혹은
02:00:41C# 같은 것들을요.
02:00:41관심 있는 게 뭐든
02:00:42백엔드 개발에
02:00:42쓰면 좋겠죠.
02:00:44하지만 말하고 싶은 건
02:00:45제 경험상
02:00:46TypeScript를 쓰면
02:00:47높은 속도를
02:00:48낼 수 있다는 겁니다.
02:00:49왜냐하면 AI가
02:00:50타입스크립트를 쓸 때입니다.
02:00:51물론 저도
02:00:52잘 알고 있고요.
02:00:53그래서 저는
02:00:55AI가 잘못된 방향으로
02:00:56나아가는 부분을
02:00:56빨리 캐치할 수 있죠.
02:00:57그런 면에서
02:00:58분명히 장점이 있습니다.
02:00:59다른 백엔드 언어를
02:01:01사용하는 것도요.
02:01:02전부 JavaScript일
02:01:02필요는 없죠.
02:01:04왜 NestJS가
02:01:05더 인기 있는지
02:01:06정말 모르겠네요.
02:01:06절대 완전히
02:01:06이해하지 못했어요.
02:01:07왜 Adonis가
02:01:08그렇게 니치한(틈새) 시장에
02:01:09머물러 있는지 말이죠.
02:01:10이렇다 할
02:01:11설명은 없습니다.
02:01:12모든 걸 자바스크립트로 할 필요는 없죠.
02:01:14왜 NestJS가 더 인기가 많을까요?
02:01:16흥미로운 시간이었습니다.
02:01:17정말 재미있었어요.
02:01:19Adonis를
02:01:19깊이 파보는 것도
02:01:22정말 흥미로웠어요.
02:01:23여러분도 즐거우셨길 바랍니다.
02:01:24그게,
02:01:24음.
02:01:25돌아오려 합니다.
02:01:26다음 주는
02:01:28참석하지 못할 것 같네요.
02:01:29그다음 주는
02:01:30상황을 봐야겠어요.
02:01:31하지만
02:01:32항상 Discord에
02:01:32공지합니다.
02:01:34아직 멤버가 아니라면
02:01:35[akadamind.com/community에](https://www.google.com/search?q=https://akadamind.com/community%EC%97%90)
02:01:36방문해서
02:01:37Discord에 참여하세요.
02:01:39거기에 공지사항을 올립니다.
02:01:40아니면 물론
02:01:40그냥 구독하고
02:01:41팔로우하시면
02:01:42소식을 들을 수 있을 겁니다.
02:01:43그럼 목요일에 뵙죠.
02:01:45오후 5시,
02:01:46중앙 유럽
02:01:47서머타임 기준으로요.
02:01:48보통 지금처럼
02:01:48방송을 마칩니다.
02:01:49그럼 모두
02:01:50감사드리고요.
02:01:51좋은 하루 되세요.
02:01:51저녁이든,
02:01:53아침이든,
02:01:54지금 어디에 계시든 말이죠.
02:01:54앞으로도 계속 뵙길 바랍니다.
02:01:56그럼,
02:01:56다들 함께해 주셔서 감사합니다.
02:01:57모두
02:01:58감사합니다.
02:01:59아,
02:02:00잠시만요,
02:02:01몇 가지
02:02:03더 말하고 싶은 게 있었는데,
02:02:04어쨌든
02:02:05함께해 주셔서 정말 고마워요.
02:02:06다들 좋은 시간 보내시고
02:02:07다음에 또 뵙죠.
02:02:09진짜로,
02:02:09정말 고마워요.
02:02:11다들 행복하세요.
02:02:13안녕!
02:02:13안녕!
02:02:14다들 안녕!
02:02:15다음에 또 봐요.
02:02:17안녕!
02:02:17정말 감사합니다.
Community Posts
No posts yet. Be the first to write about this video!
Write about this video