HaskellでWebを作るframeworkのIHPの概要
2021/12/20
HaskellのモダンなWeb frameworkにIHPというものがある 最近ちょっと触っているので現時点での概要や感想をまとめる
2021/12/16現在の最新versionは0.16.0です
前提
mrsekut.iconはHaskellの実装の経験は少なめ
IHPは触り始めているが、まだ序盤なのでそこまで深い話はできない
今後も触る予定ではあるので、気が向けば追記するかも
IHPとは何か
IHPはHaskellでWebを作るfullstackなframework
別の、似た立ち位置のものにBlitz.jsやRuby on Railsがある
これらのHaskell版だとイメージするとわかりやすいmrsekut.icon
backendからviewまで、全てをHaskellで書く
IHPの何が嬉しいのか
backendからviewまで、全てをHaskellで書ける
全てを、型安全な言語で書ける安心感は大きい
意図せず健全性が破壊されない
チーム間で型の大事さを問わなくても、自然に型の能力を享受できる
これは普通にHaskellという言語の良さであるmrsekut.icon
それを感じつつWebを作れるのが嬉しい
Nixを使うので環境構築がめちゃくちゃ楽
(Haskellとは関係なく)Nixというpackage managerがあるが、IHPはこれを使って環境構築をする
ここで、IHPのinstall方法のページを見てみよう
つまり、以下のコマンドを実行するだけ
これだけで、無の状態から、Haskellが入り、IHPの設定が入り、環境構築が終わる
Haskellは環境構築が大変なイメージが(mrsekut.iconに)あったが、Nixのおかげで全てがコマンド一発で揃う
package管理もNixを使う
環境構築だけでなく、例えば「hlintを使いたい」とか「hxtを使いたい」のようなpackage管理もNixを使用する
そのため自分で.cabalファイルは編集しない
全てdefault.nixに追記していく
IHP自身のversion管理もここで行う
Viewも型安全
ViewはHSXというJSXやHTMLに似た文法で記述できる code:hs
instance View IndexView where
html IndexView { .. } = [hsx|
<div class="py-10">
<h1 class="text-4xl font-semibold mb-5">Feeds</h1>
<div>
<div>{forEach feeds renderFeed}</div>
</div>
</div>
|]
[hsx|と|]で囲った中にHSXを記述する(Template Haskell)
{}で囲った中にHaskell式を埋め込める
関数型指向の言語でViewを書くframeworkは他にもあるが、HTML風に書けるものは珍しい
例えば、ElmやPureScript Halogenなどでは、View部分もその言語の関数記法で書く
code:purs(hs)
render :: State -> H.ComponentHTML Action () m
render {flg1, flg2} = HH.div_ [
HH.div
]
好みは人によりけりだが、
馴染みあるHTML記法で書けるとHaskeller以外の人もスッと入れるだろう
嬉しいのが、HSXも型チェックが効くことである
例えば、
タグ名が間違っているとtype errror
閉じタグが無いとtype error
属性名が間違っているとtype error
例えば、aタグのhrefをhreのようにtypoするとtype error
{}内のHaskell式が間違っていても当然type error
defaultでは使えないが、documentの通りに設定すれば使えるようになる 導入手順はやや多いが、documentが丁寧なので書いている通りにやれば1回も詰まらなかった
これで、styleを別ファイルに書かずにやっていける
code:hs
renderFeed :: Feed -> Html
renderFeed feed = [hsx|
<div class="flex bg-green-100 p-2 mb-2">
<div class="flex-none w-60">
</div>
<div class="pl-2">
<a target="_blank" rel="noopener norefferer" href={get #link feed}> <h2 class="font-semibold mb-2.5">{get #title feed}</h2> </a>
</div>
</div>
|]
他にも、frontend側の嬉しさとして以下のようなものがある
Component駆動で作れる
1つ1つのComponentはただの関数なので、使い回しができる
Reactを書いているときと同じ思考でViewの設計ができる
HSXが嫌ならば、ElmやPureScript Halogenでも書ける
らしいmrsekut.icon
試してないので、どんなものかはわからない
backendとfrontendの言語がズレる問題はあるが、選択肢があるというのは良い
GUIでtable設計をできる
IHPを起動すると、管理画面とアプリケーションの2つが立ち上がる
https://gyazo.com/e15d30baf4458c94e155ebc8828bd650
ここのDXも高くて良いmrsekut.icon
命名を見て、チェック項目が変わっている
https://i.gyazo.com/2e71d443c72065727d21995dc01b3edc.gif
column名に、_idが含まれているとチェック項目がID系のものに変わるっぽい
Code Generatorがあるので枠にハマれば一瞬で色々なものを生成できる
上記で作ったtableを元に、Controller、Action、Viewなどを一発で生成できる
https://gyazo.com/fa0fb25be15ee1318933eeae843e41e0
Controllerでは基本的なCRUDの関数が生成され、Viewも簡単なものが生成される
ボイラープレートを殆ど書かなくて住む
作りたいものがIHPとマッチしているならめちゃくちゃ楽mrsekut.icon
例えば、tutorialでは、編集ページなども含めた簡単なblogサイトを作るが、必要なものをポンポン作れるので簡単だったmrsekut.icon 他にも色々嬉しさがある
live reloadされるのでDXが良い
Documentが親切
英語も読みやすく、言われたとおりにやっていけば詰まることはない
Longterm Roadmapがあるので、今後もちゃんとメンテされるよ、とのこと
etc.
IHPのノリとか、触ってみた感想とか
アーキテクチャはMVCで、DBはPostgresSQL
mrsekut.iconはMVCに対して言語化できていない懐疑があるので、それの検証も込みで触っている
code:hs
projectsByUser :: UserId -> IO Project projectsByUser userId = do
projects <- query @Project
|> filterWhere (#userId, userId)
|> filterWhere (#deleted, False)
|> fetch
pure projects
もちろん型安全
(まだぶつかってないが)ORMが用意した以上のことをしたい時に大変になる可能性はある
DSL感は強い
基本的に、IHPの用意したPreuldeを使う
headが型安全になっていたりはする
pipeline operator(|>)を使って、流れで書いていくのが普通っぽい
Controllerのコード例を見るとこんな感じ
code:hs
action CreatePostAction = do
let post = newRecord @Post -- reqからPostを作成
post
|> ifValid \case
Left post -> render NewView { .. }
Right post -> do -- validならDBに登録
post <- post |> createRecord
setSuccessMessage "Post created"
redirectTo PostsAction
これらの関数はHoogle上で探せない
枠にハマらないとめんどいかも知れない
tutorialで例に出されているblogサービスのようなIHPの思想に合致しているものはパパっと作れる
しかし、cliendでの処理が複雑なものは、ちょっと大変かもしれない
Entityと、DB tableが1対1対応するのは渋い
この制限の下で良いDomain Modelingを実践できるかどうかまだ見えていないmrsekut.icon
defaultで多くのGHC拡張が有効になっている
40個ほどのGHC拡張が有効になっている
Documentでは、GHC拡張の説明なしに、その記法を使っている
例えば、RecordWildCardsとかLambdaCaseとか
説明がないので摩擦がなく気にせず書けるのは良い
が、調べたい時にちょっと困ると思う
「HaskellにNewView { .. }みたいな書き方あったっけ??何てググれば出てくるの?」になる
defaultで有効になっているので、ファイルの上部に{-# LANGUAGE RecordWildCards #-}と書かれていない
拡張だとわかっていても、特定するのが難しい
Haskell入門に良いのか?TypeScript利用者に向いているのか?
documentには
We try to offer a solution which can be used by developers who have not worked with haskell yet. ref とか
If you like TypeScript, you will love IHP. ref とか書いている
触ってみた感じ、実際のところはわからないmrsekut.icon
mrsekut.iconは業務でTypeScriptを書いているが、そもそもHaskellの方が好き
Haskell入門としては良い気がする
Haskell何も知らない状態ではさすがにきついと思う
基本を知った状態で、「Haskell使って何か作ってみるか」の題材として良いと思う
枠にハマったものなら簡単に作れると思う
GHC拡張などの勉強にもなる
あまり気に留めずに少しずつ知っていくのが良い
じゃないとGHC拡張の(面白さの)沼にハマ(ってIHPが進まなくな)るmrsekut.icon
ただし、良くも悪くもアーキテクチャにHaskell感はない
他のHaskell設計をしたことがないので何ともだけどmrsekut.icon
2021/12/16現在のIHPのversionはv0.16.0で、使用しているGHCのversionはv8.10.7である
そのため、まだ新しいRecordの記法などは使えない
だから現状はこう書く
code:hs
GHCv9.2.1が入ればこう書けるはず
code:hs
<h5>{comment.author}</h5>
どこから始めるか?
あとはDocumentのサイドバーを眺めて興味ある箇所のカスタマイズをしていけば楽しめる
終わりに
全体的に開発者体験がすごく良い
環境構築の簡単さは感動したmrsekut.icon
まだversionもv0なので、今後も大きな変更がされていくはず
今のところ作りたいものがあるので、今後も触り続けていく気ではあるmrsekut.icon