https://www.youtube.com/watch?v=KRsoBLzpJPk
음, 이제 다음 프레젠테이션을 시작하겠습니다. 다음 프레젠테이션에 앞서 먼저 Martin을 환영합니다. 안녕하세요, Martin. 안녕하세요. 안녕하세요, MOS. 안녕하세요. 안녕하세요. 펀알 스웨덴에 오신 것을 환영합니다. 감사합니다. 감사합니다. 초대해 주셔서 감사합니다. Magnus. 저를 초대해 주셔서 감사합니다. 보통 저는 BP와 저희가 하는 일에 대해 자주 이야기하는데, 주로 웹 개발 쪽입니다. 그래서 오늘은 함수형 프로그래밍, 특히 Haskell에 대해 좀 더 이야기하게 되어 매우 기쁩니다. Peter, 프레젠테이션 잘 들었습니다. 정말 독특했어요. 사실 Hosc를 사용하고 있음에도 불구하고, 어떻게 만들어졌는지 잘 몰랐거든요. 반대편에서 어떻게 만들어졌는지 말이죠. 그래서 정말 멋졌습니다. 좋았습니다. 바로 시작할까요? 네, 시작하세요! 좋아요.
어, 제목이 좀 모호하죠? 웹 개발의 미래를 재정의한다니... 곧 무슨 말인지 아시게 될 겁니다. 재밌는 사실은, Peter의 발표와 마찬가지로 저도 AI에 대해 조금 이야기합니다. 언어를 개발하고 유지 관리하는 것에 대해서 말이죠. 하지만 완전히 다른 종류의 언어입니다. 어떤 종류의 언어인지 곧 아시게 될 겁니다. Peter는 제가 코드, 아마도 라이브 코딩을 더 많이 보여주길 바랐지만, 아마 그렇게는 안 될 것 같습니다. 하지만 코드를 좀 보여드릴 테니 도움이 되실 겁니다. 아시잖아요, 라이브 코딩은 너무 위험해요. 항상 위험 부담이 따르죠.
저에 대해 간략히 소개하겠습니다. 저는 크로아티아 자그레브에서 컴퓨터 과학 석사 학위를 받았습니다. 그리고 주로 제 열정은 처음에는 수학이었고, 이후에는 경시대회에 참가하는 것이었습니다. 그러다가 프로그래밍을 접하게 되어 알고리즘 쪽으로 더 많이 경쟁하게 되었죠. 싱가포르 같은 흥미로운 곳에서 인턴십을 했습니다. 바이오인포매틱스, 머신러닝, C++, R, 데이터 과학을 사용하는 일을 했죠. 더블린의 Google에서도 인턴십을 했습니다. 거기서는 데이터 과학, C++, Python을 사용했죠. 더블린은 완전히 달랐습니다. 웹 개발을 했거든요. 이 부분이 오늘 프레젠테이션과 관련이 있습니다. 그런 다음 삶이 저를 스타트업 쪽으로 이끌었습니다. 그래서 Techstars, Workit, 또 다른 스타트업인 Livebit 등 여러 스타트업을 기술적으로 돕고 있었습니다. 그리고 지금은 Wasp를 개발하고 있습니다. 오늘 발표의 주제이기도 합니다. 제 회사인데, 형제와 몇몇 훌륭한 팀원들과 함께 만들고 있습니다. 직업적으로는 주로 Java, C, C++, Python을 사용했습니다. Python은 좀 덜 사용했지만, 여전히 사용하고 있습니다. 최근에는 웹, JS, Javascript, Haskell을 주로 사용하고 있습니다. 그리고 다른 것들도 좀 하지만 규모는 작습니다. 요즘 저는 Wasp에 대해 이야기하는 데 가장 큰 흥미를 느끼고, Wasp가 제 머릿속을 가득 채우고 있습니다. Wasp는 제 회사인데, 형제와 몇몇 훌륭한 팀원들과 함께 만들고 있습니다. 웹 개발과 JS, Javascript에 관한 회사입니다. 그래서 저는 스타트업, 제품 개발, 함수형 프로그래밍, 특히 Haskell에 큰 흥미를 느낍니다. 저희가 Wasp에 많이 사용하고 있기 때문입니다. 깨끗한 코드를 매우 중요하게 생각합니다. 대학 때부터 그랬던 것 같습니다. 그리고 이건 제 위시리스트입니다. 항상 게임 개발을 해보고 싶다고 생각했습니다. Haskell로도 해볼 수 있겠죠. 물론 실제로 무언가를 만들기보다는 재미로 하는 거지만요. 매년 여름마다 며칠씩 게임 개발을 하다가 다음 여름까지 보관해두곤 합니다. 하지만 그 이야기를 하고 싶으시면 저도 즐겁게 이야기할 수 있습니다. 이제 Haskell에 대해 좀 더 집중해서 이야기해 보겠습니다. 제가 Haskell을 어떻게 접하게 되었는지 기억하는 게 재밌었습니다. 14년 전이었더군요. 갑자기 물어보면 6년 전쯤이라고 했을 텐데, 시간이 정말 빨리 갑니다. 14년 전, 대학교 1학년 때였습니다. 저는 운 좋게도 Haskell 강좌가 개설된 몇 안 되는 대학교에 다니고 있었습니다. Haskell에 열정적인 교수님 한 분이 추가 활동으로 강좌를 개설하셨죠. 그분은 자신의 열정을 전달하는 데도 뛰어나셨습니다. 그분의 열정은 전염성이 강했죠. 쌍둥이 형제가 있다는 걸 아실 겁니다. 아마 여러 번 언급하게 될 텐데, 저는 형제와 함께 많은 일을 합니다. 여름 방학 때 형이 저에게 이런 이상한 언어가 있다고 말했습니다. 수학처럼 보이는데 재밌을 것 같다고, 매우 어렵다고 하니 해보자고 했죠. 다음 해에 신청하려면 며칠밖에 남지 않았었습니다. 처음에는 하기 싫었습니다. 이미 너무 많은 일을 하고 있었거든요. Java로 진행되는 매우 어렵다는 강좌를 이미 신청했기 때문에 너무 벅찰 거라고 생각했습니다. 하지만 형이 강하게 밀어붙였고, 결국 좋은 결정이 되었습니다. 그렇게 시작되었습니다. 한 학기 동안 비교적 집중적인 Haskell 강좌였습니다. 모나드까지는 다뤘던 것 같습니다. 모나드 변환기 같은 것들 말이죠. 하지만 충분히 멀리 나아갔습니다. 그 이후로 저는 할 수 있는 한 Haskell을 사용하기 시작했습니다. Haskell을 배우기 전에는 대학교 프로젝트에 주로 C++ 또는 Java를 사용했지만, 그 이후에는 할 수 있는 한 Haskell을 사용하기 시작했습니다. 아마 세 배는 더 오래 걸렸을 겁니다. 하지만 훨씬 더 재밌었고, 좋은 점은 작동만 하면 실습 조교나 코드를 확인하는 사람들이 코드를 확인하고 Haskell인 것을 보고 멋지다고 하면서 아무것도 이해하지 못하고 작동하는 것처럼 보이면 만점을 주었다는 것입니다. 그래서 꽤 좋았습니다. 저는 Haskell을 계속 사용했고, 형제와 함께 모든 종류의 사이드 프로젝트와 작은 작업, 잡다한 일에 사용했습니다. 할 수 있는 한 Haskell을 사용했지만 4년 전에 형과 함께 회사를 설립하기 전까지는 큰 규모의 프로젝트는 없었습니다. Magnus가 Haskell을 사용하기 좋은 방법은 자신의 회사를 시작하는 것이라고 말했던 것 같은데, 저희는 실제로 그렇게 했습니다. 회사를 설립하고 지난 4년 동안 Haskell을 사용해 왔습니다. 사실, 처음 들었던 강좌는 "Learn You a Haskell for Great Good!"라는 책을 기반으로 했습니다. 꽤 인기 있는 책인데, 저는 그 책이 정말 좋았습니다. 처음 Haskell을 배울 때는 주로 그 책을 참고했지만, "Real World Haskell"과 "Haskell Programming from First Principles"도 읽었습니다. 전부 다 읽지는 않았지만 상당 부분을 읽었습니다. 그래서 누군가 Haskell 책을 추천해 달라고 하면 저는 "Learn You a Haskell for Great Good!"를 추천합니다. 좀 오래된 책이긴 하지만 여전히 유용하다고 생각합니다.
이제 제가 그렇게 많이 언급했던 Wasp에 대해 자세히 이야기해 보겠습니다. Wasp는 무엇일까요? Wasp는 오픈 소스 프로젝트이자 풀스택 웹 앱을 구축하기 위한 프레임워크입니다. 하지만 고유한 DSL(Domain Specific Language)을 가지고 있다는 점에서 조금 독특합니다. 여기 DSL의 일부를 볼 수 있습니다. 저희만의 .wasp 파일이 있습니다. 완전한 언어는 아니고 꽤 간단한 선언형 언어입니다. 정적으로 타입을 검사하며, 사용자가 직접 타입을 정의할 수는 없지만 타입이 지정되어 있습니다. 웹 앱의 고수준 구조를 정의하는 데 사용됩니다. 모든 고수준 요소를 DSL로 정의한 다음, React, Node.js, Prisma와 같은 인기 있는 기술을 사용하여 세부 사항을 구현합니다. Prisma는 Javascript 생태계에서 ORM 같은 역할을 합니다. 현재는 Javascript 생태계에 중점을 두고 있지만, Wasp는 미래에 다중 언어를 지원하도록 설계되었습니다. 따라서 Python으로 작업하거나 React 이외의 라이브러리를 사용할 수도 있습니다. 이것이 Wasp의 큰 비전이며, 저희가 Wasp를 만드는 이유 중 하나는 이 독특한 DSL 때문입니다. Wasp에 대해 언급해야 할 몇 가지 중요한 사항이 있습니다. Wasp는 아직 베타 버전이지만 이미 일부 프로덕션 환경에서 사용되고 있습니다. Discord 커뮤니티를 운영하고 있으며, 스타트업입니다. 이런 것을 처음부터 개발하려면 많은 R&D가 필요합니다. 처음에는 Y Combinator의 지원을 받았고, 현재는 유럽 및 미국 투자자들의 지원을 받고 있습니다. 최근에 투자 라운드를 마무리했는데, 향후 몇 년 동안 Wasp 개발을 지속할 수 있을 만큼 충분한 자금을 확보했습니다. 정말 멋진 일입니다. 팀 사진을 잠깐 보여드리겠습니다. 현재 저희 팀은 다섯 명으로 구성되어 있습니다. 여기는 제 쌍둥이 형제 마테이고, 저는 여기 있습니다. 똑같은 티셔츠를 입고 있죠. 형제라는 걸 강조하기 위해서입니다. 그리고 필립, 엠, 비니가 있습니다. 꽤 작은 팀이지만 정말 강력하다고 생각합니다. Haskell을 사용하는 것도 그 이유 중 하나입니다. 저희는 원격 팀이며, 대부분 크로아티아에 있지만 필수 조건은 아닙니다.
프로젝트 진행 상황을 간략히 보여드리겠습니다. 최근에 Wasp는 빠르게 성장하고 있습니다. 처음에는 R&D와 실험 때문에 속도가 느렸습니다. 하지만 최근에 핵심 개념과 기본 원리를 파악했고, 이제는 무엇을 어떻게 만들어야 할지 잘 알고 있습니다. 그래서 이제는 최대한 빨리 개발하는 단계입니다. 이미 GitHub에서 두 저장소에 걸쳐 7,000개의 스타를 받았고, 베타 버전임에도 불구하고 매일 Wasp를 사용하는 사람들이 꽤 많습니다. 이제 Wasp의 기원에 대해 이야기해 보겠습니다. 왜 Wasp를 만들었을까요? 제 이력을 이야기할 때 웹 개발에 대해 많이 언급하지 않았다는 걸 눈치채셨을 겁니다. 재밌는 점은 사실 저는 AI나 바이오인포매틱스 분야에서 박사 학위를 받는 것을 목표로 하고 있었다는 것입니다. 알고리즘 쪽으로 말이죠. 저는 CPU에서 작업을 빠르게 하는 것을 좋아했고, 형제는 GPU에서 작업을 빠르게 하는 것을 좋아했습니다. CUDA 같은 것들 말이죠. 하지만 어떻게 된 일인지, 저희는 항상 사이드 프로젝트나 회사 업무를 위해 웹 앱을 만들고 있었습니다. 저는 핀테크 스타트업에서 일했는데, 옵션 분석을 위한 멋진 계산을 했습니다. 하지만 그 결과를 보여주기 위한 웹 앱도 필요했습니다. 바이오인포매틱스 스타트업에서도 웹 앱이 필요했습니다. 그래서 어떻게 된 일인지, 저희는 항상 웹 앱을 만들고 있었습니다. 처음에는 PHP와 jQuery, Javascript를 사용했고, Backbone, Angular, Redux를 사용하는 React, Redux를 사용하지 않는 React 등 다양한 기술을 사용했습니다. 재밌는 점은 형제와 저는 항상 웹 개발이 컴퓨터 과학보다 어렵다고 생각했다는 것입니다. 물론 범위가 넓기 때문이기도 하지만, 매년 또는 2년마다 새로운 기술이 등장해서 새로운 기술을 배워야 했기 때문입니다. 하지만 대부분 같은 일을 반복해서 구현하고 있었습니다. 페이지를 만들고, 서버에서 클라이언트로 데이터를 가져오고, 실시간 기능을 구현하는 등의 작업을 말이죠. 물론 재미가 없었던 것은 아니지만, 항상 같은 문제를 해결하는 것처럼 느껴졌습니다.
그러다가 구현과 명세를 분리하는 아이디어를 떠올렸습니다. 저희가 생각한 해결책은 DSL을 만드는 것이었습니다. 웹 앱의 고수준 구조를 기술하는 DSL을 만들면 저수준 기술과 분리할 수 있고, 웹 개발자들이 익숙한 용어를 사용할 수 있습니다. 페이지, 데이터베이스, 모델 같은 것들 말이죠. 구현 세부 사항은 React와 같은 기술을 사용하여 작성할 수 있습니다. 그러면 상위 계층은 일관성을 유지하면서 하위 계층의 기술을 쉽게 변경할 수 있습니다. 참고로, Wasp는 "Web Application Specification"의 약자입니다. 구현과 명세를 분리하는 아이디어에서 비롯된 이름입니다. 이상적으로는 이러한 설정을 통해 코드를 덜 작성하고, 기술 변화에 덜 영향을 받고, 최상의 방법을 쉽게 적용할 수 있을 것이라고 생각했습니다. 이것이 Wasp를 만든 동기입니다. 이제 Wasp에서 Haskell을 사용하는 이유에 대해 이야기해 보겠습니다. 여러 가지 이유가 있습니다. 첫째, 빠르게 개발할 수 있는 고성능 언어가 필요했습니다. C++ 수준의 최적화는 필요하지 않았기 때문에 성능 최적화는 Haskell 자체로도 충분했습니다. 매우 빡빡한 작업이라면 물론 C++ 또는 Rust를 사용하는 것이 좋지만, 저희는 그럴 필요가 없었습니다. 또한, 특별한 메모리 관리 기능도 필요하지 않았기 때문에 고수준의 가비지 컬렉션 언어를 원했습니다. 그리고 DSL을 구축하려면 컴파일러 백엔드 구현에 대한 좋은 지원이 필요했습니다. Haskell은 이 분야에서 꽤 인기가 있습니다. 물론 Haskell에도 단점이 있습니다. Haskell 생태계가 크지 않기 때문에 라이브러리가 부족할 수 있습니다. Azure, GCP 또는 특정 서비스와 인터페이스하기 위한 강력한 SDK가 필요할 수 있는데, Haskell에서는 쉽게 찾을 수 없거나 오래되었을 수 있습니다. AWS용 SDK는 훌륭합니다. 하지만 이는 언어를 선택할 때 중요한 요소가 될 수 있습니다. 하지만 저희는 클라우드 컴퓨팅, 데이터 과학 또는 특정 라이브러리가 필요하지 않을 것이라는 것을 알고 있었습니다. 그래서 Haskell은 좋은 선택이었습니다. 또한, 저희는 Haskell을 매우 잘 알고 있었습니다. 저는 Haskell을 주로 사이드 프로젝트에 사용했지만, 많이 사용해 봤고, 그 당시에는 Java만큼 잘 알고 있었습니다. 또 다른 강력한 대안은 Typescript였습니다. 저희는 웹 개발 솔루션을 만들고 있었기 때문에 사용자들이 대부분 Typescript를 사용할 것이라는 것을 알고 있었습니다. 그래서 왜 Typescript를 선택하지 않았는지 궁금해하실 수도 있습니다. 솔직히 말해서, 그 당시에는 Haskell을 Typescript보다 더 잘 알고 있었고, Haskell이 더 좋았습니다. 그리고 경험상 Haskell로 작성할 핵심 부분은 주로 컴파일러 관련 작업이었기 때문에 Typescript를 선택할 이유가 없었습니다. 어쨌든 컴파일러에 대한 특별한 지식이 필요했기 때문에 일반적인 기여자들이 쉽게 기여할 수 없을 것이라고 생각했습니다. 반면에 Haskell을 아는 사람들은 대부분 컴파일러에 대해서도 잘 알고 있었기 때문에 Haskell이 좋은 선택이라고 생각했습니다. 물론 Typescript도 괜찮았겠지만, 저희는 Haskell을 정말 좋아했습니다.
Wasp의 작동 방식에 대해 간략히 설명하겠습니다. Wasp의 핵심은 Wasp 컴파일러입니다. Haskell로 작성된 CLI 바이너리입니다. 이전 슬라이드에서 보았듯이 .wasp 파일과 소스 디렉토리에 있는 다른 모든 파일(JS, React, Node 등)을 입력받습니다. Wasp 컴파일러는 분석기와 생성기 두 부분으로 구성됩니다. 주요 중간 표현은 AppSpec이라고 합니다. .wasp 파일의 메모리 내 표현이라고 할 수 있습니다. AppSpec은 분석기와 생성기를 분리하는 역할을 합니다. 따라서 미래에 여러 개의 프론트엔드(분석기)와 백엔드(생성기)를 가질 수 있습니다. 실제로 현재 대체 분석기를 구현하고 있습니다. 즉, 대체 프론트엔드를 구현하고 있는데, 이는 분석기와 생성기를 분리했기 때문에 가능한 일입니다. 분석기는 꽤 일반적인 컴파일러 아키텍처를 따릅니다. 파서, 타입 검사기, 그리고 AppSpec을 생성하는 부분으로 구성됩니다. AppSpec은 생성기로 전달되어 클라이언트, 서버, 데이터베이스 등의 코드를 생성합니다. 생성기는 Mustache 템플릿을 많이 사용합니다. Haskell에는 Mustache 템플릿을 처리하기 위한 훌륭한 라이브러리가 있습니다. 생성기는 파일을 직접 디스크에 쓰지 않고 파일 초안을 생성합니다. 파일 초안은 메모리 내 파일 표현입니다. 그런 다음 최적화 함수가 실제로 쓸 내용과 이미 써 있는 내용을 파악하여 Javascript, HTML, CSS 등으로 구성된 웹 앱을 디스크에 생성합니다. 한 가지 분명히 해야 할 점은 Wasp 사용자, 즉 Wasp 개발자는 이 부분에 대해 신경 쓸 필요가 없다는 것입니다. 물론 원한다면 코드를 확인할 수 있지만, 이 코드를 변경할 필요는 없습니다. 이것은 단지 컴파일러의 산물일 뿐입니다. C++가 어셈블리로 컴파일되는 것과 마찬가지로, Wasp도 Javascript 등으로 컴파일됩니다. 물론 정말 필요하다면 코드를 확인하고 일부를 가져다가 사용할 수도 있지만, 그럴 필요는 없습니다. 한 가지 중요한 점은, 저희가 이 모든 것을 직접 구현했지만, 저는 일반적인 컴파일러 개발자보다 컴파일러에 대해 덜 알고 있을 수도 있다는 것입니다. Wasp는 꽤 간단한 언어이기 때문입니다. Turing 완전하지 않으며, for 루프 최적화, 퓨전 등을 수행하지 않습니다. 그래서 비교적 간단합니다. 물론 템플릿 Haskell 등을 사용하여 흥미롭고 복잡한 부분도 있지만요. Wasp 컴파일러 외에도 Haskell로 작성된 몇 가지 흥미로운 부분이 있습니다. Wasp 언어 서버와 VS Code 확장이 있습니다. 아직 Vim 및 Emacs 확장은 없지만, 팀원들은 대부분 Emacs와 Vim을 사용합니다. 하지만 Wasp 언어 서버가 있기 때문에 이러한 확장을 구현하는 것은 꽤 쉽습니다. Haskell 언어 서버를 구현하는 데 사용되는 오픈 소스 LSP 라이브러리가 Hackage에 있습니다. 따라서 Wasp 지원을 구현하는 데 동일한 LSP를 사용할 수 있었습니다. 정말 좋았습니다. 또 다른 재미있는 점은, 이것은 Haskell을 사용한 사이드 프로젝트였는데, 아마 한 달 정도 걸렸을 겁니다. GPT 래퍼를 구현했습니다. 웹 앱의 제목을 입력하고 몇 문장으로 웹 앱을 설명하면 Wasp 프로젝트를 생성해 줍니다. 예를 들어, 할 일 목록 앱이 있습니다. 모든 작업을 나열하고, 각 작업에는 설명이 있으며, 완료 또는 미완료로 전환할 수 있으며, 사용자는 새 작업을 추가할 수 있습니다. 꽤 간단하죠. 어떤 GPT 모델을 사용할지, 온도를 어떻게 설정할지 물어봅니다. 그리고 Wasp 프로젝트를 생성합니다. 이 모든 것이 Haskell로 작성되었습니다. 매우 복잡한 프로젝트는 아니지만 사소한 프로젝트도 아닙니다. 구현하는 것이 정말 즐거웠습니다. OpenAI API를 사용하기 때문에 OpenAI API와의 통신을 모델링하고, 응답이 올바른지 확인하고, 생성된 코드가 올바른지 확인하고, 그렇지 않으면 GPT에 다시 요청하는 등의 작업을 수행합니다. GPT의 비결정적 동작을 제거하거나 줄이려는 시도입니다. 그리고 실제로 Haskell이 얼마나 빠르게 프로토타입을 제작할 수 있는지 다시 한번 확인할 수 있었습니다. 정말 좋은 결과를 얻었습니다. 여기서 볼 수 있듯이, GPT는 Wasp 파일을 생성하고, 데이터 모델, 작업, 페이지 등을 생성합니다. 정말 재밌었습니다. 이 모든 것과 몇 가지 추가 기능을 Wasp라는 하나의 바이너리로 제공합니다. 가장 편리한 방법이라고 생각했고, 현재까지는 잘 작동하고 있습니다. 버전 관리에도 도움이 됩니다. Wasp를 설치하면 새 프로젝트를 만들 수 있습니다. AI를 사용하여 만들 수도 있습니다. 이 바이너리는 Wasp 언어 서버를 실행하는 데도 사용되며, 개발에도 사용됩니다. 생성된 앱을 실행하고, React 코드, 데이터베이스 등을 실행합니다. 텔레메트리를 수행하고, 배포를 위해 빌드하고 등등... 하나의 큰 Cabal 프로젝트로 제공되며, 하나의 바이너리로 제공됩니다.
Haskell 측면에 대해 좀 더 자세히 이야기해 보겠습니다. 저희는 Boring Haskell 선언문을 따르고 있습니다. 아마 들어보셨을 겁니다. Chris Done인지 Snowman인지 기억나지 않지만, Haskell 커뮤니티의 저명한 인물들이 얼마 전에 Boring Haskell에 대해 이야기했습니다. 코드베이스를 작성할 때 템플릿 Haskell, 렌즈, 복잡한 효과 시스템 등을 과도하게 사용하지 말자는 것입니다. 물론 필요하다면 사용해도 되지만, 가능하면 국지적으로 사용하고, 필요하지 않다면 사용하지 말자는 것입니다. 그러면 주니어 개발자나 중급 개발자, 새로운 팀원들이 빠르게 적응하고 생산성을 높일 수 있으며, 코드를 유지 관리하기가 더 쉬워집니다. 저희도 그렇게 하고 있습니다. 팀 전체가 Haskell로 코딩하고 Javascript, React로도 코딩하고 있습니다. 모든 개발자가 여러 가지 기술을 다루고 있습니다. 배포, 배포 공급자 등 많은 것들을 다루고 있습니다. 그래서 Haskell만 사용하는 것이 아닙니다. 따라서 Haskell 코드를 간단하게 유지하면 컨텍스트 전환과 이 모든 작업에 도움이 됩니다. 가능한 한 Boring Haskell 선언문을 따르고 있습니다. 처음에는 Stack을 프로젝트 관리자로 사용했습니다. GHC 버전 관리 등 많은 도움이 되었습니다. 얼마 전에 Cabal로 전환했습니다. GHCup과 Cabal의 개선 덕분에 Cabal이 더 간단한 선택이 되었고, Stack만큼 잘 작동합니다. 그래서 지금은 Cabal을 사용하고 있으며, 다른 사이드 프로젝트에도 Cabal을 사용하고 있습니다. 컴파일러 측면에서 재미있는 경험은 Parsec으로 시작했다는 것입니다. 처음에는 임시 파서를 사용했지만, 미국에서 온 훌륭한 기여자가 몇 번의 인턴십을 통해 가장 복잡한 Haskell 코드를 작성했습니다. 정말 멋진 코드였습니다. 그는 Alex와 Happy를 사용하여 적절한 문법을 구현했습니다. 모든 형식적 요소를 갖춘 문법을 말이죠. 정말 좋았습니다. 하지만 나중에 Alex와 Parsec으로 다시 전환했습니다. Happy는 훌륭하지만 에러 처리, 에러 보고, 에러 복구 측면에서 유연성이 부족했습니다. 저희는 언어 서버 때문에 세밀한 제어가 필요했고, 두 가지 다른 파서를 구현하고 싶지 않았습니다. 그래서 Parsec을 기반으로 하되 이전보다 더 높은 수준으로 추상화된 파서를 만들었습니다. 지금은 잘 작동하고 있습니다. 또 다른 재미있는 경험은 파일 경로를 처리하는 것이었습니다. Wasp에서는 사용자가 자신의 파일을 가져오기 때문에 파일을 처리하고 일부 파일을 파싱하고 생성된 프로젝트로 전송하고 연결하는 작업을 많이 합니다. 파일이 여기 있고 저기 있으며 여기로 가져와야 하는 등의 작업을 많이 합니다. 또한, Javascript 코드에서 JS import 문을 생성하는데, 이것도 올바르게 작동해야 합니다. Linux, Mac, Windows에서 모두 작동해야 하기 때문에 작업 중인 플랫폼과 사용자의 플랫폼을 모두 고려해야 합니다. 파일 경로에 대한 세부 사항이 많고, 처음에는 Wasp가 파일 경로에 너무 많이 의존하는 문제가 있었습니다. Haskell을 사용할 때 항상 드는 생각은 "왜 이걸 타입 시스템에 캡처하지 않았을까?"입니다. Chris Done이 작성한 훌륭한 라이브러리인 Pet을 찾았고, 잠시 사용해 보았지만 더 강력한 타입 안전성이 필요하다는 것을 깨달았습니다. 그래서 Pet에서 영감을 받아 StrongPath라는 라이브러리를 직접 구현했습니다. 지금은 StrongPath를 사용하고 있으며 매우 만족합니다. 물론 주관적인 의견일 수도 있지만, 팀원들도 StrongPath를 좋아한다고 말했습니다. 물론 그냥 예의상 그렇게 말했을 수도 있지만요. 어쨌든 정말 좋은 경험이었습니다. 놀랍게도 Wasp는 꽤 큰 Haskell 프로젝트이지만 아직 렌즈를 사용하지 않습니다. LSP에서 몇 군데 작은 부분에만 렌즈를 사용합니다. 아마 사용할 수도 있겠지만, 필요성이 크지 않았던 것 같습니다. 다행히도 깊게 중첩된 데이터 구조를 다루지 않았기 때문입니다. 언젠가는 렌즈를 사용하게 될 수도 있지만, 현재는 Boring Haskell 선언문을 따르고 있습니다. 즉, 렌즈를 피하고 있습니다. MTL과 Transformers를 사용하고 있으며, 주목할 만한 라이브러리로는 LSP, optparse-applicative, QuickCheck, Hspec 등이 있습니다. optparse-applicative는 CLI 인수를 파싱하고 도움말 지침을 생성하는 데 사용됩니다. 정말 훌륭한 소프트웨어입니다. QuickCheck와 Hspec는 테스트에 사용됩니다. 골든 테스트, 스냅샷 테스트 등도 사용합니다. StrongPath에 대해 좀 더 자세히 설명하겠습니다. StrongPath는 어떻게 작동할까요? 모든 프로젝트에 StrongPath가 필요한지는 잘 모르겠습니다. 저는 이제 모든 프로젝트에 StrongPath를 사용하지 않으면 불편하지만, 아마 파일 경로 관련 문제를 좀 더 많이 겪어봐야 StrongPath의 필요성을 느낄 수 있을 겁니다. 하지만 Wasp에서는 StrongPath가 매우 필요합니다. StrongPath는 Chris Done이 구현하고 그의 팀원들이 유지 관리하는 Pet 라이브러리를 기반으로 합니다. StrongPath의 작동 방식을 간략히 설명하겠습니다. StrongPath나 Pet을 사용하지 않으면 getBashProfile과 같은 함수를 작성할 때 IO를 수행하고 Haskell에서 FilePath를 반환합니다. FilePath는 단순히 String의 타입 별칭이기 때문에 타입 안전성이 없습니다. StrongPath를 사용하면 좀 더 정교하게 작업할 수 있습니다. StrongPath를 사용하면 파일 경로가 System, Windows 또는 Posix 중 하나임을 지정할 수 있습니다. 저는 이전에는 이런 선택지가 있다는 것도 몰랐습니다. Windows에서는 구분 기호가 이쪽에 있고 Posix에서는 저쪽에 있는지, 아니면 실행 중인 시스템에 따라 달라지는지, 즉 Mac 또는 Linux에서는 Posix이고 Windows에서는 Windows인지, 시스템에 따라 적응해야 하는지 등을 고려해야 했습니다. StrongPath는 System을 사용합니다. StrongPath는 HomeDir이라는 홈 디렉토리에 대한 상대 경로이며, .bashProfile이라는 파일에 대한 경로입니다. Pet 라이브러리도 이러한 기능을 일부 제공하지만, 제 기억이 맞다면 StrongPath처럼 이름을 지정할 수는 없습니다. 저희에게는 이름을 지정할 수 있는 것이 중요했습니다. 실수로 경로를 혼합하는 것을 방지하기 위해서입니다. StrongPath에서는 HomeDir와 .bashProfile이라는 이름을 사용할 수 없습니다. StrongPath는 Pet보다 몇 가지 기능을 더 제공합니다. StrongPath를 구현하는 동안 Pet에 표준을 구분하는 방식에 버그가 있다는 것을 알게 되었습니다. 좋은 기회였습니다. GitHub에서 Pet 유지 관리자들과 소통하고 협업하여 Pet에 수정 사항을 병합했습니다. StrongPath를 개선하는 데에도 도움이 되었습니다. 좀 더 완전한 예제를 보여드리겠습니다. 예를 들어, getHomeDir과 같은 함수를 작성할 수 있습니다. 이 함수는 IO를 수행하고 HomeDir를 반환합니다. 이 경우 절대 경로일 수 있습니다. AbsDir을 사용하여 절대 경로임을 지정하고, homeDir라는 디렉토리를 가리키도록 할 수 있습니다. 이름 없는 타입을 사용할 수 있습니다. 이 타입은 단순히 단일 값을 나타냅니다. StrongPath에 대한 자세한 내용은 Hackage 페이지를 참조하십시오.
저희는 Haskell 커뮤니티에 기여하기 위해 노력하고 있습니다. 물론 더 많은 기여를 할 수 있겠지만, 다른 작업과 병행하여 최대한 노력하고 있습니다. 가장 큰 기여는 대학교 Haskell 강좌를 운영하는 것입니다. 제가 처음 Haskell을 접하게 된 강좌입니다. 팀원들 대부분이 그 강좌를 수강했습니다. 몇 년 전, 교수님께서 오랫동안 강좌를 이끌어 오셨지만, 너무 많은 일이었고 더 이상 시간을 낼 수 없게 되셨습니다. 그래서 저희가 적절한 시기에 강좌를 이어받았습니다. 그래서 강좌는 계속 이어지고 있으며, 저희는 지난 몇 년 동안 강좌를 이끌고 있습니다. 즉, 매 학기마다 20~30명의 야심 찬 컴퓨터 과학 전공 학생들에게 Haskell을 가르치고 있습니다. 저는 이 강좌를 정말 좋아합니다. 실제 업무에서는 폴드, 리스트 내포 등을 예상만큼 많이 사용하지 않습니다. 비즈니스 로직을 다루고 타입을 다룰 때 더 많이 사용합니다. 그래서 매년 Haskell을 다시 배우는 좋은 기회가 되고, 다른 사람들에게 Haskell을 가르치는 것은 매우 보람 있는 일입니다. 팀 전체가 매년 이 강좌에 적극적으로 참여하고 있습니다. 저는 Haskell.org의 새로운 시작 페이지를 만드는 데 기여할 기회를 얻었습니다. 눈치채셨는지 모르겠지만, 1년 전쯤에 저와 Haskell 커뮤니티의 다른 몇몇 사람들이 새로운 시작 페이지를 만들었습니다. 솔직히 말해서, Haskell에 어떻게 기여할지에 대한 아이디어는 대부분 대학교 강좌에서 얻었습니다. 학생들과 소통할 수 있는 특별한 기회가 있기 때문입니다. 그러면 Haskell을 배우는 사람들이 어려움을 겪는 부분을 알 수 있습니다. 문서, 쉬운 사용성 등 Haskell이 부족한 부분을 말이죠. 저는 첫인상이 중요하다고 생각했고, Haskell.org를 처음 방문했을 때의 인상을 개선하고 싶었습니다. 그래서 시작 페이지를 개선하는 데 기여했습니다. Haskell 커뮤니티의 핵심적인 부분에 기여할 수 있어서 정말 좋았습니다. 저는 Haskell 생태계에 큰 기여를 한 적이 없었기 때문에 더욱 특별했습니다. Haskell 커뮤니티가 작기 때문에 가능한 일이라고 생각합니다. 저희는 GitHub에 Haskell 핸드북도 만들었습니다. 저희를 위한 팁과 트릭을 모아놓은 것입니다. 잊어버리지 않도록 짧은 형식으로 작성했습니다. 다른 사람들에게도 유용할 수 있을 것이라고 생각합니다. 천천히 개발되고 있지만, GitHub에서 꽤 많은 스타를 받았기 때문에 사람들이 유용하다고 생각하는 것 같습니다. 저는 Haskell 핸드북을 자주 사용합니다. 예를 들어, 템플릿 Haskell을 사용할 때 핸드북을 참고하여 코드를 작성합니다. 또한, 가능하면 블로그 게시물, 튜토리얼 등을 작성하려고 노력합니다. 저는 Haskell로 알고리즘 경쟁 문제를 풀고 Haskell과 C++의 성능을 비교하는 게시물을 작성했습니다. 다른 팀원들도 블로그 게시물을 작성하고 있습니다.
마지막 슬라이드입니다. 미래와 교훈에 대해 이야기해 보겠습니다. 새로운 언어를 배우면, 새로운 언어를 배우면 모든 문제와 단점을 알게 됩니다. Haskell은 완벽하지 않지만, 저는 여전히 Haskell을 정말 좋아합니다. 다른 많은 언어를 사용해 봤지만, 여전히 Haskell이 좋습니다. 현재도 Javascript, Typescript 등을 사용하고 있지만, 프로젝트에 적합하다면 항상 Haskell을 선택할 것입니다. Haskell에서 새로운 데이터 타입을 정의하는 방법은 정말 간단하지만, 제가 가장 좋아하는 Haskell 기능 입니다. 정말 간단한 기능이지만, 누군가 제게 Haskell에서 가장 좋아하는 기능이 무엇이냐고 물으면 항상 데이터 타입 정의라고 대답합니다. 너무 간단해서 문제를 쉽게 정의할 수 있습니다. 제 머리가 좋아하는 방식입니다. Rust에도 비슷한 기능이 있지만, Rust는 고수준 언어가 아니고 가비지 컬렉션을 지원하지 않습니다. 그래서 이런 것들을 생각하고 싶지 않다면 Haskell이 완벽합니다.
Haskell을 사용하면서 얻은 교훈 중 하나는 몇 가지 언어를 경험한 중급 이상의 개발자들이 Haskell을 매우 빠르게 배운다는 것입니다. Haskell을 전혀 경험해 보지 못한 사람들이 회사에 합류했는데, 3개월 만에 완전히 생산성을 갖추었습니다. 다른 일도 하면서 Haskell을 조금씩 배웠는데, 3개월 만에 매우 높은 수준에 도달했습니다. 그래서 Haskell을 배우는 데 어려움을 겪지 않았습니다. 주니어 개발자는 다를 수도 있지만, 아직 경험해 보지 못했습니다. 아마 미래에 경험하게 될 것입니다. 사람들이 Haskell을 두려워한다는 것을 알게 되었습니다. 대학교 강좌에서 학생들을 보면 Haskell에 대한 잘못된 생각을 많이 가지고 있습니다. Turing 완전하지 않다거나, 특정 작업을 할 수 없다거나, 범주론을 알아야 한다거나, 너무 어렵다거나, 아무도 사용하지 않는다거나, 생태계가 없다거나 하는 생각들 말이죠. Haskell로 웹 개발을 할 수 있는데도 말입니다. 많은 오해가 있습니다. 재밌는 점은 사람들이 Wasp도 두려워한다는 것입니다. Wasp는 Haskell 개발자가 아닌 웹 개발자를 위한 솔루션입니다. 주로 Typescript와 Javascript를 사용하는 웹 개발자를 위한 솔루션입니다. 그런데 Wasp가 Haskell로 만들어졌다는 사실만으로도 사람들은 Wasp를 멀리합니다. Haskell로 만들어졌다는 것은 Haskell을 알아야 한다는 뜻이고, 이 사람들은 뭔가 매우 특이한 일을 하고 있을 것이라고 생각하는 것 같습니다. 그래서 Haskell의 평판이 좋지 않은 것은 때때로 문제가 됩니다. Haskell 측면에서 앞으로 개선되었으면 하는 점은 홍보와 마케팅입니다. Haskell에 대한 잘못된 생각을 불식시키는 것이 Haskell에 큰 도움이 될 것입니다. 또 한 가지 배운 점은 언어 도구를 만드는 것이 정말 어렵다는 것입니다. 컴파일러를 만드는 것도 어렵지만, 언어 서버, 다양한 에디터와의 통합 등 컴파일러 주변의 모든 도구를 만드는 것은 정말 어렵습니다. 이것은 Haskell에만 국한된 문제가 아니라, 어려운 문제입니다. Wasp에서도 이 문제를 해결하기 위해 노력하고 있습니다. 앞서 말했듯이, DSL을 정의하는 다른 방법을 도입할 수도 있습니다. Typescript를 사용하는 방법도 고려하고 있습니다. 그러면 유지 관리가 훨씬 쉬워질 것입니다. 자세한 내용은 Wasp Discord에서 확인할 수 있습니다. 이상입니다. 감사합니다.
감사합니다, Martin. 좋은 발표였습니다. 채팅창에 질문이 몇 가지 있습니다. React 또는 다른 Javascript 프레임워크로 컴파일할 수 있나요?
좋은 질문입니다. Wasp는 여러 개의 생성기를 지원하도록 설계되었습니다. React용 생성기, Vue용 생성기, Svelte용 생성기 등을 만들 수 있습니다. 하지만 현재는 작은 팀이기 때문에 한 가지에 집중하고 있습니다. 그래서 현재는 React, Node, Prisma만 지원합니다. 하지만 다른 프론트엔드 언어, 다른 백엔드 등을 추가할 수 있도록 설계되었습니다. 아마 Python 백엔드를 먼저 추가하게 될 것 같습니다. 요청이 좀 있었거든요. 그리고 프론트엔드에는 Vue를 추가할 수도 있겠죠. 네, Wasp를 널리 보급하려면 합리적인 선택인 것 같습니다. 정확히 그렇습니다.
사용자 프로그램의 동적 부분을 유지하나요? 즉, 컴파일 후에도 동적 부분이 남아 있나요? 다시 한번 말씀해 주시겠어요? 컴파일 후에도 사용자 프로그램의 동적 부분을 유지하나요? 어떤 부분을 말씀하시는지에 따라 다릅니다. 무슨 말씀인지 잘 모르겠지만, 어쨌든 답변을 드리겠습니다. Wasp는 복잡한 컴파일을 수행하지 않습니다. Wasp 파일은 매우 간단한 선언형 정적 언어이며, 사용자는 Javascript 파일(React, Node 등)로 실제 구현을 정의합니다. 저희는 사용자가 제공한 Javascript 코드를 그대로 사용합니다. 아무것도 제거하지 않습니다. 정적이며, 단지 다른 Javascript 코드를 조율하는 데 사용됩니다. 그래서 사용자 프로그램의 동적 부분을 유지하는지 여부는 사용자가 작성한 Javascript 코드에 따라 다릅니다. Wasp 코드에는 동적 부분이 없습니다. 네, 이해했습니다. 질문은 컴파일 후에 런타임에 실행되는 부분이 남아 있느냐는 것이었습니다. 네, 흥미로운 질문입니다. Wasp는 모든 것을 컴파일 타임에 처리합니다. 전체 프로젝트를 생성하고, 그 프로젝트를 실행합니다. 일반적인 언어처럼 런타임이 없습니다. 네, 맞습니다.
개발 중 UX는 어떤가요? 핫 리로드를 지원하고 로컬 상태를 유지하나요? UX는 훌륭합니다. 물론 농담입니다. 하지만 UX를 개선하기 위해 최선을 다하고 있습니다. Peter가 말했듯이, 무언가를 만들다 보면 모든 단점을 알게 됩니다. 그래서 UX의 단점을 알고 싶다면 저나 팀원들에게 물어보세요. 하지만 UX는 많은 면에서 훌륭하다고 생각합니다. 핫 리로드도 지원합니다. 물론 기본적인 기능입니다. 몇 가지 부족한 부분도 있습니다. 예를 들어, 아직 지연 로딩 라우트, 정적 서버, 서버 측 렌더링 등을 지원하지 않습니다. 하지만 이러한 기능은 곧 추가될 예정입니다. Wasp는 아직 베타 버전이기 때문에 현재는 혁신적인 기능을 완벽하게 구현하는 데 집중하고 있습니다. 그런 다음 좀 더 기대되는 기능을 추가할 예정입니다.
마지막 질문입니다. 진행 중인 강좌에 대한 링크가 있나요? 흥미로운 질문입니다. 프레젠테이션 자료에는 링크가 있지만 아직 아무에게도 공유하지 않았습니다. 나중에 Discord에 링크를 공유하겠습니다. 강좌는 스트리밍이나 녹화를 하지 않으며, "Learn You a Haskell for Great Good!"라는 책을 기반으로 진행됩니다. 그 책에서 많은 것을 배울 수 있지만, 저희 강좌의 가장 큰 장점은 학생들과 직접 소통하고 코드 리뷰를 하고 숙제를 내주고 시험을 본다는 것입니다. 또한, 실시간 수업을 통해 학생들을 돕고 있습니다. 작년에 강좌를 실시간으로 스트리밍할지에 대한 논의가 있었습니다. 관심이 있다면 다시 논의해 볼 수 있습니다. 다른 팀원들과 상의해서 실시간 스트리밍을 하거나 녹화해서 어딘가에 올릴 수도 있을 것 같습니다.
네, 다시 한번 감사합니다, Martin. 감사합니다, Magnus. 천만에요. 오늘 참여해 주신 모든 분들께 감사드립니다. 채팅창에 활발하게 참여해 주셔서 감사합니다. 발표자들에게도 큰 힘이 됩니다. 저희에게도 큰 힘이 됩니다. 오늘 모임은 여기까지입니다. Discord 서버에서 더 자세한 질문을 하고 토론을 이어갈 수 있습니다. Martin이 강좌 링크 등을 공유할 예정입니다. 감사합니다. Discord에서 다시 만나요! 오늘은 여기까지입니다.