リニューアル第一弾となる新しいWeb UIのおしらせ

こんにちは、技術書典のWeb担当 @vvakame です。
そしてこの記事の編集を担当した技術書典代表 @mhidaka です。

一年の大半という長きに渡り、燻っていましたが遂にアーキテクチャを刷新した新しいWeb UIをリリースしました!
大規模変更となるためOpt-Inでの公開です。一週間くらい様子を見て問題がなさそうであれば移行Stepを進め、Opt-Outに切り替えます。

ここまで大きな変化が技術書典WebのUIに起こったことはありません。不安に感じるかもしれませんが、
ユーザーにとっては変化がないことのほうが改善が行われないリスクだと判断しました。今後もやきもきさせてしまうことがあるかもしれませんが、暖かく見守ってください。

今回は何もかもを作り直しており、さらなる前進のための基盤を整えました。
アーキテクチャの刷新は大変に大きな変更なのでUIの構造自体は旧来のものを維持しています。少しでもインパクトを小さくするためです。
今回の変更では特に何も変わっていないなぁ、と皆さんに思ってもらえれば成功かもしれません。
これからどういう変化が加えられていくのか、随時発信していく予定です。今後の更新・技術書典の新しい姿を楽しみにお待ちください。

どこが変わったのかの話

変更点をいくつか紹介したいと思いますが、UI的にはどこも変わっていません。

旧UIの技術書典08イベントページ
新UIの技術書典08イベントページ

ほぼ変わってない!はずです。だいたいの画面は今までと同じ場所にありますし、表示されているデータも変わりないはずです。
コンポーネント単位で見るとデザインの変化など細かい違いを見て取れるかもしれません。

ユーザー設定から新UIを利用するにチェックを入れ送信すると新UIに切り替わります。
旧UIに戻したいときも、同じ位置に設定項目があります。

新UIを利用する

なぜ変えたのかの話

開発リソースの集約のため、というのが当初からある目的のひとつです。いままではWeb UIはAngularで作っていました。
そして、イベント当日用アプリ(主にかんたん後払いに使われている)のAndroid/iOS版は現在はReact Nativeで作られています。
これらを個別に開発し続け双方を充実させていくには深刻にリソースが足りません。
よって、どちらかに集約したいという要求が生じます。

かんたん後払いで必要な、QRコードの軽量かつ連続した読み取りをサポートするためには、ネイティブの実装が現時点では不可欠です。
よって、開発をReact NativeとReact Native for Webに寄せることにしました。これは @Nkzn という他に考えられないレベルの仲間が得られたためです。

おれたちはReactに全振りしたらぁ…!!やったらぁよ…!!

といったかもしれませんし、言ってないかもしれません。しかし心の声は確かに聞こえました!この変更によって今後の計画も前に進むでしょう。詳細についてはまだ秘密です!
公開できる日が楽しみです。

使っている技術や設計思想的な話

1年間弱、がんばってきたプロジェクトなので、どういう構成になったか技術的なところに触れておきたいと思います。

React Native + React Native for Web

どうも、@Nkznです。フロントエンドの実装を担当しました。
以前からかんたん後払いシステムのモバイルアプリ担当として関わらせてもらっています。そこで使っていたReact Nativeの周辺エコシステムが技術書典のロードマップと上手く噛み合ったため、技術書典Webのリアーキテクチャにも携わる運びとなりました。

ざっくりと次のようなツール構成で作っています。

こだわりの点として、すべてのコンポーネントを関数コンポーネント(Function Component)として実装しました。状態管理もReact 16.8で導入されたHooksを利用しています。これは大成功で、従来のクラスコンポーネントと比べて見通しがよくなりました。

また、後述のとおり、今回はGraphQLをAPIサーバーのプロトコルとして採用しているのですが、React向けのGraphQLクライアントである、Apollo ClientのHooks拡張がとても良かったので言及しておきます。

GraphQLサーバーと通信するコンポーネントは、次のように定義できます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import React from 'react';
import { View, Text } from 'react-native';
import { useQuery } from '@apollo/react-hooks';
import gql from 'graphql-tag';
import { LoadingView, ErrorView } from './utils';

// (2)クエリ文字列を静的解析して生成されたTypeScript型定義
import { EventPageQuery } from './path/to/EventPageQuery';

// (1)クエリ文字列を定義
const query = gql`
query EventPageQuery {
event {
id
name
}
# any other data structure
}
`;

// コンポーネント定義
export const EventPage: React.FC = () => {
// (3)型安全なリクエスト(dataはEventPageQuery型になる)
const { data, loading, error } = useQuery<EventPageQuery>(query);

if (loading) {
// 通信待ちの間は読み込み中のUIを表示
return <LoadingView />;
}

if (error) {
// エラーがあった場合は内容を表示
return <ErrorView error={error} />;
}

return (
<View>
<Text>イベント名: {data.event.name}</Text>
</View>
);
}

これを実行すると、読み込み中に LoadingView が一瞬表示された後に、イベント名: 技術書典8 のような表示が画面に出ます。

(1)でGraphQLリクエストのためのクエリ文字列を作成するわけですが、これは別途用意したCLIツールによって静的解析され、(2)のTypeScript型定義ファイルを生成します。これを(3)の useQuery にジェネリクスの型パラメータとして渡すと、戻り値の data がリクエスト時に指定したデータ構造を型として持てるようになるのです。これには型安全教徒の私もvvakameさんもニッコリです。

この方式だとUI更新と通信の実装が隣り合ってしまう感じがして、最初は少し抵抗がありましたが、よく見るとUIから関心がある範囲に限定されたデータをインターフェースとして持っているので、とても使いやすいものだと思えるようになりました。

さて、話は変わりますが、将来React Nativeのモバイルアプリとソースコードの統合を予定しているということで、できる限りネイティブ版でも利用できるソースコードを多く用意する必要がありました。実際どのくらいになったでしょうか。

手元でざっくり数えてみたところ、だいたいコードベースの70%くらいが共通で利用できる状態になっているようです。コンポーネント(UI)が45%、それ以外(主に自動生成した型定義)が25%という内訳でした。モバイルアプリ版を作り始めるとネイティブ専用コンポーネントが増えていくので、将来は共通部分の比率は下がると思われますが、現時点ではこんなところです。

React NativeやFlutterといったクロスプラットフォーム系のテクノロジは、人の手が足りない組織で多くのプラットフォームに向けてサービスを提供したい場合に上手くマッチします。その中でもReactという「本来ブラウザのために作られたフレームワーク」を軸にしているReact Nativeは、ブラウザに手を広げた場合にも、里帰りしたかのような安心感を伴うことがわかってきました。

この挑戦的なプロジェクトは今後も続いてきます。今後の機能追加にご期待ください!

Fastly

CDNにFastlyを導入しました。すでに去年の終わり頃からリクエストをFastlyでさばくようになっています。
製作者のvvakameは5年ぶりくらいにVCL書きました。その柔軟な表現力でもって、新UIと旧UIの出し分けなどはFastly上で行っています。

設定の管理はTerraformで記述し、GitHub Actionsで反映させています。
慣れるとめっちゃ便利ですね。

GraphQL

APIがOpen API v2(Swagger)ベースのものからGraphQLベースのものになりました。
サーバが動いている場所は以前と変わらずAppEngine+Goなので、vvakameもコミッタを務めるgqlgenを利用しています。

GraphQLのおかげでサーバ側のコードを書くときに煩わしいパートが少なくなりましたし、クライアント側もSwagger時代以上に強固に型が付き、開発が楽しくなりました。

クライアント側をTypeScriptで書く場合、GraphQLがアプリにとって最良の選択肢であると思います。おすすめです!
それ以外の言語でもわりと高い割合で満足できる選択です。今後はGraphQLベースで開発を進めていきます。

フィードバックについて

今回は見た目は変わっていませんが、おかしなところがあるかもしれません。技術書典のWebサイトは豊かなサークル活動を支えるためにたくさんの機能を持っています。
テストカバー率100%でリリースすることを涙が出るほど望んでいましたが我々は完璧ながら遅いリリースより素早くリリースし、ユーザーからのフィードバックをもらうことを望みました(すでにすごい時間かかったし!)。

もし何かあったらお問い合わせ窓口にご連絡ください。
すべてに返信することは難しいですが、スタッフで共有します。もしかしたら追加情報をお願いするかもしれませんので、その際は修正にご協力いただければと思います。

それでは、よい執筆を!

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×