🎄

続・一人アドベントカレンダーのススメ

2024/12/28に公開

こんにちは、クレスウェア株式会社の奥野賢太郎 (@okunokentaro) です。本記事は、2024年12月に掲載されたTypeScript 一人 Advent Calendar 2024の25記事を執筆した筆者によって、2度に渡り一人アドベントカレンダーをやる意義を、そしてなぜ今回この企画を実施したのかという裏話的な側面をお話します。

なぜ二度目の一人アドベントカレンダーを?

筆者は2年前の2022年にもTypeScript 一人 Advent Calendar 2022として一人アドベントカレンダーを完走した経験があります。 2年前に25記事を書き切ったときのことを振り返ると、当時は私生活を犠牲にしてひたすら執筆を続けるという、かなりハードな挑戦でした。その結果、翌年の2023年はもういいかなという気持ちが強くなり、結局はやらずに過ごしてしまいました。2年前の記事執筆直後の振り返り記事を掲載しています。

そうして1年が空いたあと、今になって改めて2022年に書いた記事を読み返すと、一部で内容が古くなっている部分が徐々に気になってきました。自分で掲載しておきながら、まったく実践しなくなってしまったテクニックもあります。そのため、そろそろ「2年前の記事にどんな問題があり、この2年でどのように改善してきたか」をまとめ直すのも良さそうだと考えるようになりました。

しかし、25本ものネタを一新して記事化するのは簡単なことではありません。2年前の25記事の1つ1つに対して続編を書くほどの新情報があるわけでもなければ、25記事すべてを2年前とまったく被らないようにすることも難しそうでした。TypeScript自体の進化は早いとはいえ、2年で25本分のネタが積み上がるほどではありませんでしたし、筆者の実力の向上が2年で25本分の記事に相当してもおらず、2年前の記事群の延長線上に留まっていました。

そのため色々と考えながら2024年10月に一度ネタの棚卸しをしつつ、そのメモを残したまま今年のカレンダーも見送ろうと判断していました。

アドベンドカレンダーはささやかでいい

そんな気持ちのまま12月も半ばを迎えたころ『技術系アドベントカレンダーの歴史に思うこと』という記事を偶然読んだのが、今回の一人アドベントカレンダー開催のきっかけに繋がりました。

もともとアドベントカレンダーとは、クリスマスを楽しみに待ちつつ、毎日ちょっとしたお菓子やおもちゃを引く、小さなワクワクを味わうもの、そんな初歩的なことに気付かされたのです。

ネタ被りや記事の長さなどを必要以上に気にせず、出せるものを出して楽しめばいいのではないかという考え方に至り、10月にまとめていたネタのメモに加えて、さらに追加で10個ほどネタを絞り出して、最終的に25本を用意。結果として、12月16日から12月25日までの10日間で25記事を書くというタイムアタックを決行することにしました。

AIの活用

今回は、少し前からChatGPT Proの課金を始めていたこともあり、AIの力を活用すれば執筆が一気に楽になるかもしれない、という淡い期待がありました。しかし、OpenAI o1で試してみても、まったく使い物になりませんでした。さらにGPT-4oだとそれ以上に残念な内容になってしまいます。たとえば、タイトルだけ与えて記事を書かせてみても、まったく面白みに欠ける文章ばかりが出てきてしまう。これはAIの活用は難しいかという諦めがありました。

そこで、文意を一度すべて箇条書きでまとめてから与えるようにしました。この箇条書きは体言止めや助詞なしの状態で、日本語記事としての成立よりも、どんな内容を伝えたいかだけを残すようにしています。

そして、その箇条書きや筆者の過去の記事をOpenAI o1 Pro modeのプロンプトとして与えて文体を似させた上で、そこから記事を生成させる方法を試しました。そうすると、丸投げに比べるとだいぶ読める記事として返ってきます。

ただし、そのままの文章では「AIくささ」がまだまだ残っているため、最終的には自分が書きそうな言い回しにすべて修正して仕上げていく形をとりました。

AIで加速した8日間

今回の執筆期間は、ネタまとめをしていた10月の作業時間を除くと、12月16日に始めて23日に書き終えたため、実質8日間でした。2年前は12月12日に開始して25日に終わるという14日間だったため、一見すると今回のほうがスケジュール的に過酷そうですが、不思議と負担は少なく感じられました。 その理由としては、まず箇条書きで言いたいことだけを書き下ろし、それをo1 Proに与えて体裁を整えてもらうというフローが想像以上に楽だったことが大きいと思います。

かつてから、技術記事の連載や商業書籍の執筆を繰り返していて痛感するのは「その記事・書籍を通じて何を言いたいか」よりも「どういった文章でその内容を伝えるか」に圧倒的な時間が割かれる点です。漫画家がストーリーやコマ割りを考えたり、メインキャラの線画を描くだけでなく、背景描画や塗りもしなければならないことに似ているかもしれません。そのため、今回のAIの立ち位置は文章生成機というよりも「アシスタント」に近い感覚でした。

とはいえ、AIに生成させた文章でそのままコピペして掲載している内容は今回ひとつもありません。すべての文に対して修正が加わっています。 今回、作業効率だけの観点で「8割生成・2割手直し」を目標としていましたが、実際AIに書かせてみると「4割生成・6割手直し、または書き下ろし」くらいの割合になりました。特にTypeScriptサンプルコードこそすべて手書きとなっており、むしろコードについては生成を一切活用していません。

技術記事に関しては、タイトルだけ与えて全ての本文をAIに生成させるように丸投げしてしまうと低品質な記事が生まれていまうことは明白なので、箇条書きの段階で「自分が本当に伝えたい内容」を固めるプロセスを重視しました。

データで振り返る8日間

2年前と同様に、今回も各記事の文字数と執筆所要時間をまとめてみました。

日目 文字数 所要分 平均文字数/分
1 Valibotのご紹介 3048 64.65 47.15
2 Valibotで実践するBranded types 3229 33.15 97.41
3 応用編 Valid branded types 4401 37.33 117.88
4 文字列や配列の最大長が決まっていないときの対策 5932 74.57 79.55
5 実例 neverUsed(), $() 5769 55.4 104.13
6 DeepReadonly<T> 3870 54.8 70.62
7 StrictOmit<T, K> 3290 38.78 84.83
8 実例 ExtractKeyOf 3421 46.42 73.7
9 実例 is() 4207 45.9 91.66
10 実例 hooksTestingTools() 5833 104.7 55.71
11 noUncheckedIndexedAccess 3627 54.63 66.39
12 satisfies 5943 93.77 63.38
13 実例 mustFind() 6912 90.27 76.57
14 Vitest test-d.ts で複雑な型をテストする 5442 49.07 110.91
15 App Router 時代のエラーハンドリング 5846 88.28 66.22
16 実例 Result<T, E> 9061 128 70.79
17 実例 ConvenienceFixture, orDefault() 7332 61.15 119.9
18 実例 PageContext, AllowTransitionFrom 7896 116.62 67.71
19 実例 UnknownifyDiscriminatedUnion 9293 74.78 124.27
20 ECMAScript Private Fields 8203 37.2 220.51
21 using宣言 7164 66.95 107.01
22 tsx TypeScript Execute 3202 45.75 69.99
23 tsupでバンドルする 6031 106.08 56.85
24 Biomeを使ったフォーマットとLint 6626 126.07 52.56
25 今後のTypeScriptに期待すること 9371 163.32 57.38
合計 144949 1857.63 78.03
平均値 5797.96 74.31
中央値 5846 64.65 73.7

総執筆時間は前回の2166分から1857分へと、約5時間ほど短縮できました。記事数が25本であることは同じにもかかわらず日数を6日縮め、総執筆時間を5時間短縮できたのは、AIの力を多少なりとも活用することで執筆への心理的なハードルが下がったからだと感じています。

サンプルコードの文字数も含まれているため厳密ではないですが「平均文字数/分」のバラつきが2年前より大きくなっており、AI生成に任せて修正が少なかった回と、大半を自力で書き下ろしている回に差が大きい印象を持っています。特に業務上の実例を多く含む16〜19日目については、AIの生成がかなり貧弱だったため、ほぼすべて最初から書いています。

1記事あたりの文字数が2年前よりも1,000文字少々減っていることについては想定内で、2年前より小粒な記事を目指すという思惑通りに着地できたと思います。

執筆で気をつけたこと

筆者は昨今、技術記事に対する価値観が変わってきました。ドキュメントの翻訳や要約などはAIに任せるのが効率的で、技術紹介記事などは魅力が相対的に薄れてしまったと感じています。そのため、単なるTypeScriptの機能解説記事を25本書く意義はあまり見いだせませんでした。

そこで、なるべく実務寄りで、できるだけ筆者にしか書けない内容を中心に取り上げることを意識しました。具体的には、業務でどのような課題に直面したのか、その課題をどのようにに乗り越えたのかというリアルな体験談を積極的に盛り込むようにしたのです。AI丸投げ記事が量産されるなか、矜持のようなものでもあります。

また、その記事のタイトルには含まれていない「裏テーマ」を常に意識するようにしました。たとえば『DeepReadonly<T>』では、単なるライブラリの機能紹介だけでなく、なぜこのライブラリを導入すべきと感じたのかという采配の部分にかなり文量を割いています。筆者が定期配信しているPodcast番組『リファクタリングとともに生きるラジオ(リファラジ)』を継続し、リスナーから感想をいただくなかで気付いたこととして「その人が何を考えて業務にあたっているか」は貴重な情報であるという点がありました。ドキュメントや仕様書からは見えてこない、それを使う人が何を考えて使うのか、どう工夫しているのか、こういった点を話すと求めている読者がいるというのは、リファラジ継続からの学びでした。そのため、単なる機能紹介や事例紹介に加えて、常に背景や意思決定を丁寧に説明することを心がけています。これもAI丸投げ生成の記事には達成できないことです。

こういった「現場で実際に起きた話」は、AIはもちろん話してくれませんし、商業書籍でもページの都合上省略されがちです。だからこそ、実務においてTypeScriptをどのように使いこなしているかを自分の言葉で書くことにこそ、一人アドベントカレンダーを完走する大きな価値があると感じています。

これを読んでTypeScriptを活用し尽くしてほしい

2年前の25本は「中級者が学ぶべきTypeScriptのUtility types集」という全体的なテーマで書いていましたが、今回の25本は「実務における上級者のノウハウ集」といったテーマでまとめています。

TypeScriptスキルを他の開発者にレクチャーする際に筆者がよく感じるのは、ジェネリクスを特別なものだと思っている、あるいはOSS作者だけに縁のある機能だと思っている人がいるという点でした。日頃Array<T>Promise<T>だけは使うが、ジェネリクスを含む処理を自分の日頃のプログラミングに取り入れようという発想に至らないTypeScript利用者は少なくない印象です。

TypeScript利用者の中では、ビギナーからシニアの間が坂道のみで構成されておらず、坂・崖・坂という構成になっている気配を感じています。そのため、筆者としては「ジェネリクスは実務で日常的に使える」ということを示し、その段階に崖がないことを示したいという意図がありました。

実務におけるTypeScriptの活用は、今回の25記事で示した通り「小さな工夫の連続した組み合わせ」がほとんどです。小さなパーツをいくつも組み合わせて完成させるレゴブロックのようなものです。ひとつひとつのパーツの形を理解し、どれとどれを組み合わせると何が作れるか、それが思惑通りにハマるところにTypeScriptプログラミングの楽しさがあります。最新のTypeScriptを活用することで、ただの型付きJavaScriptに留まらない、さらなる安全性、開発効率が得られます。

2年前と今年のカレンダー全50記事は、途中から読んでも問題ない構成になっています。目次だけでなく索引から気になるページを見つけていただくこともできます。これらの記事があなたのTypeScriptスキルを彩るきっかけに繋がれば幸いです。

TypeScript 一人 Advent Calendar 2024の振り返りは以上です。それではよいお年を。

Discussion