요약
Haskell과 GTK 4, Adwaita로 할 일 목록 앱을 만드는 연재가 시작됐습니다.
플로레알 테크놀로지스의 페리엘 슈트리 드 타를레가 쓴 튜토리얼입니다. Haskell을 써 본 중급 개발자를 대상으로, 네이티브 데스크톱 앱을 처음부터 만드는 과정을 단계별로 보여 줍니다.
왜 중요한가
- 웹 기술 없이 Haskell만으로 GNOME 스타일의 네이티브 앱을 만드는 구체적인 방법을 보여 줍니다.
- Elm 아키텍처(상태, 화면, 갱신을 나누는 구조)를 적용해 갱신 로직을 화면 없이 GHCi에서 확인할 수 있습니다.
- Adwaita를 쓰면 GNOME의 접근성 기준과 디자인 지침을 직접 구현하지 않고 그대로 물려받습니다.
핵심 내용
- haskell-gi가 GTK 라이브러리에서 Haskell 바인딩(C 라이브러리를 불러 쓰는 연결 코드)을 자동으로 만들어 줍니다.
- 모델은 할 일 목록과 다음 ID로 이루어지고, update 함수는 새 상태와 부수 효과(디스크 저장 등)를 함께 돌려줍니다.
- 상태가 바뀔 때마다 화면 전체를 새로 만들어 창의 내용을 통째로 바꿉니다.
- 메시지는 GLib.idleAdd로 메인 루프에 넘겨 처리하므로 UI가 멈추지 않습니다.
- 화면은 Adwaita의 EntryRow, ActionRow, Clamp와 GTK의 ListBox, ScrolledWindow를 조합해 만듭니다.
HN 반응
- GTK4가 GNOME 중심으로 바뀌어 창 위치 지정 같은 기능이 빠졌다는 불만에, 여전히 많이 쓰인다는 반박이 맞섰습니다.
- Haskell 패키지가 리눅스에서 의존성 문제를 일으킨다는 지적에는 Arch Linux의 동적 링크 방식 탓이라는 답이 많았습니다.
위젯(widget)이 모나드(monad)인가요? 어쨌든 이 튜토리얼의 예제들만 봐도 Haskell이 최고의 명령형 언어라는 게 또 한 번 증명되네요!
정말로 훌륭한 명령형 언어예요! FFI를 다룰 줄 알면 IO 모나드는 사실상 더 나은 C입니다.
Widget은 엄밀히 말하면 모나드가 아닙니다. 이 경우에는 포인터를 감싼 newtype이고, GTK 자체의 클래스 계층을 흉내 내는 클래스들이 붙어 있는 구조입니다.
.backdrop::after에 걸린backdrop-filter를.backdrop picture의filter로 바꿔 보세요. 공짜로 스크롤 성능이 좋아집니다.맞아요, 스크롤 성능이 형편없어서 글 읽는 맛이 확 떨어져요. 하필 주제가 GUI인데 말이죠!
데스크톱 브라우저와 모바일 브라우저에는 읽기 모드 아이콘이 있잖아요. 1) 이런 경우 2) 다 로드된 콘텐츠를 페이월 팝업으로 가려 버리는 사이트 3) 그 밖의 여러 경우에 유용해요!
눌러 보세요, 훨씬 편해집니다.
"훨씬 편해진다"가 syntax highlighting은 사라지고 코드는 고정폭 글꼴도 아니게 된다는 뜻인가요?
어쨌든 사이트가 이제 고쳐진 것 같네요, 잘됐어요!
아직도 gtk를 쓰는 사람이 있나요?
저는 예전에 ruby-gtk2로 gtk를 배우기 시작했습니다. 경험이 썩 좋지는 않았지만 위젯과 UI에 관한 핵심적인 것들을 몇 가지 배웠습니다. 그 뒤에 gtk3가 나왔는데, 어떤 면에서는 GTK2보다 나빴지만 부분적인 CSS 지원 같은 개선점도 몇 가지 있었습니다. wxwidget 같은 걸 쓸 때면 늘 그게 아쉽습니다.
그러다 GTK4가 나오면서 상황이 바뀌었습니다. 옛날 것들이 잔뜩 깨지거나 더는 동작하지 않게 됐습니다. 왼쪽 위에 위치시키려고 main_window_widget.move(0, 0)을 쓰는 것 같은 단순한 기능도 그랬습니다(저는 ruby에서 이걸 .top_left라는 별칭으로 만들어 두었고 잘 동작했습니다). 예전 동작을 얻는 우회책이 있기는 하지만, 이건 없어진 수많은 것들 가운데 하나의 예일 뿐입니다. GTK4는 GNOME 지향 툴킷이고, GTK5는 Wayland 전용이 될 테니 더 나빠질 겁니다.
GNOME 계열 GTK 개발자들과 "소통"하는 건 완전히 시간 낭비이고, 그런 경험을 한 사람이 저뿐만도 아닙니다. GNOME 사용자에게는 쓸 만한 플랫폼일지 몰라도, 현 GTK 개발자들이 아니라고 주장하는 것과 달리 GTK는 더 이상 범용 툴킷이 아닙니다. GNOME 사용자가 아닌 우리가 왜 GTK를 연명시켜야 합니까? 훨씬 더 분산된 방식으로 굴러갈 수 있는 툴킷이 정말 필요합니다. 안타깝게도 저도 좋은 아이디어는 없습니다. 자금 문제가 있고, 월드 와이드 웹이 지배적이 된 이후로 GUI가 큰 타격을 입은 것 같기 때문입니다.
글쎄요, GTK는 늘 기본 툴킷으로 여겨져 온 물건이잖습니까. 저도 Qt를 좋아하고 Qt로 만든 앱을 더 선호하지만, 어차피 GTK는 깔려 있어야 합니다. 수십 개의 의존성에 기대야 하고 Qt처럼 배포할 수 있는 덩치 큰 라이브러리가 아니라 라이브러리 모음이다 보니, 이걸로 범용 툴킷을 만들기는 늘 어려웠습니다.
그런데 GTK4는 많이 바뀌었습니다. 이제는 노력조차 안 하는 수준이에요. 글꼴 대화상자는 XDG 포털로 하는 게 더 낫다며 deprecated 시켰는데, 그런 포털은 존재하지도 않습니다. macOS와 윈도에서는 그게 어떻게 동작하겠습니까? 안 되죠. 메뉴 쪽에서 한 짓도 마찬가지입니다. 툴킷은 사용자 중심이어야지 비전을 가지면 안 됩니다. 컨트롤과 이벤트 등을 제공하면서 그냥 동작하기만 하면 되는데, GTK4로는 macOS와 윈도에서 창 위치조차 지정할 수 없습니다. 그건 사용자를 위해 동작하는 툴킷이 아닙니다.
저는 여기서 IUP 포크를 작업하고 있습니다. https://github.com/gen2brain/iup-go 모든 걸 하나로 처리하는 툴킷이고, GTK4 백엔드에도 최선을 다했지만 제가 작업한 14개 드라이버/백엔드 가운데 가장 최악의 경험이었고 계속 싸워야 했습니다.
GTK2는 좀 더 범용을 지향했던 반면, GTK4는 플랫폼으로서의 GNOME이 가진 비전을 받드는 데 더 치중합니다.
데스크톱/노트북이라는 플랫폼이 계속 남는다면, Tk나 QML 같은 계통이되 HTML+CSS보다 훨씬 가벼운, GUI 전용의 인터프리터식 플랫폼 독립 툴킷/언어가 나왔으면 좋겠습니다.
보다시피 쓰고 있습니다. GTK4/Adwaita 앱 목록도 여기 있습니다. https://arewelibadwaitayet.com/
McCLIM이 더 낫습니다.
GTK3는 전형적이고 보기 좋은 인터페이스를 만들어 줍니다. 개발하는 건 늘 미친 짓 같았는데, AI가 등장하면서 그 불편이 완전히 사라졌어요. 그래서 Claude한테 GTK3로 앱을 꽤 여러 개 만들게 했습니다. 모양이 마음에 들고 조작하기도 쉬우니까요.
제발 오타라고 말해 줘요.
LSP 때문에 그렇게 됐을 수도 있어요(Adw.foo -> "GI.Awd에 foo가 있습니다, 쓰신 이름으로 import 할까요?").
네, 오타 맞네요. "Awd"가 아니라 "Adw"예요. 휴, 다행이다.
https://hackage.haskell.org/package/gi-adwaita
저는 몇 년째 Haskell로 GUI를 만들고 있는데, gtk-gi 시그널을 수동으로 연결하다 보면 금방 지저분해져서 대부분 react-banana나 reflex를 씁니다. 여기 나온 Elm 아키텍처 패턴은 서류상으로는 깔끔해 보이는데, 위젯 트리에서 올라오는 비동기 이벤트를 콜백 지옥에 빠지지 않고 어떻게 처리하셨는지 궁금합니다. GI 콜백을 전부 채널로 감싸서 업데이트 루프로 흘려보내셨나요?
이 경우 Haskell이 그냥 로컬 HTTP 포트를 열고 사용자가 브라우저로 접속하게 하는 건가요? 아니면 Tauri/Electron 같은 건가요?
네이티브 데스크톱 앱이라서 둘 다 아닙니다.
와, 할 일 목록 하나 만드는 데 2년이나 걸렸네요.
저처럼 Haskell을 피하는 사람들도 있다는 점은 알아 두세요. Haskell이 리눅스에서 일으키는 엄청난 패키지 난장판 때문입니다. Pandoc이 그걸로 악명 높죠. 그냥 C++를 쓰세요.
NixOS에서 제 Haskell 경험은 아주 훌륭합니다!
배포판에 따라 다르다고 생각해요. 일부 배포판(Arch, 당신 얘기예요!)에서는 GHCup을 쓰고 시스템 패키지 관리자에서 떼어 /home 안에 두는 쪽이 더 낫다고 봅니다.
그렇긴 해도 저는 어떤 배포판에서도 Pandoc 때문에 문제를 겪은 적이 없습니다. 다만 NixOS(그리고 flake)를 쓰기 전에는 Pandoc 확장 때문에 고생했습니다.
쓰시는 배포판은 Haskell 라이브러리를 원래 의도대로 정적 링크하지 않나요? pandoc을 설치하는 데 필요한 건 libgmp뿐입니다.
그건 전적으로 배포판 탓입니다. ArchLinux는 사용자에게 적대적인 패키징 방식을 쓰는데, Fedora에서는 그런 걸 겪지 못했습니다.
Arch가 구체적으로 뭘 하길래 난장판이 되는 건가요? 마지막으로 써 본 지 꽤 오래됐고, 그때는 pandoc도 안 썼거든요.
Arch의 Haskell 패키지는 정적 링크가 아니라 동적 링크라서, 전이 의존성이 엄청나게 딸려 옵니다(들리는 말로는 1기가바이트 안팎이라고 합니다). 메인테이너가 그렇게 하는 이유를 나름 합리적이라고 생각되는(제 눈에는요) 설명[1]으로 밝혀 두었지만, 솔직히 제가 Arch 사용자라면 좀 짜증스러울 것 같습니다.
[1] https://www.reddit.com/r/linux/comments/9emwtu/comment/e5qssdz/
Haskell 라이브러리를 전부 동적으로 빌드하고 링크합니다.
저는 Arch에서는 Haskell 패키지를 아예 안 쓰고 Stack으로 직접 빌드합니다. 대개 간단해요.
Arch Linux의 python/haskell 패키징 방식은 '하지 말아야 할 것'의 훌륭한 사례 연구죠...
맞는 말씀입니다, 정말로요.