一人アドベントカレンダーのススメ
こんにちは、クレスウェア株式会社の奥野賢太郎 (@okunokentaro) です。本記事は、2022年12月に掲載されたTypeScript 一人 Advent Calendar 2022の25記事を執筆した筆者によって、一人アドベントカレンダーをやる意義を、そしてなぜ今回この企画を実施したのかという裏話的な側面をお話します。
結論、ススメない
出オチですが、一人でアドベントカレンダーを書くことはオススメしません。なぜオススメしないかを述べます。
- 業務以外の時間は、寝るか記事を書いていた
- 食生活と家事がすべて最底ランクになった
- 寝ている間に記事を書く夢を見た
筆者は今回『TypeScript 一人 Advent Calendar 2022』を開催し、25記事を発表しました。これは2022年の長い期間を掛けて記事を準備し、書き溜めていた内容を2022年12月1日から1記事ずつ公開したというわけではありません。
あろうことか12月12日に「アドベントカレンダーやるか」と思いつき、12月12日の時点では0記事の状態で、そこから25日に25記事目を載せるというものでした。通常業務もありながら、14日間で25記事作成するというのはかなりのハイペースであることがわかります。
そこで今回はせっかくなのでデータから振り返り、14日間で25記事作成するのはどういうことなのかを記録しておく。これがこの記事の主旨です。そして最後には、25記事までは書かないにせよ技術記事自体は積極的に書いていくべきという話題で締めくくります。
データで振り返る執筆活動
今思えばよく間に合ったと思います。企画時は「1記事2,000文字程度の紹介を25本くらいならいけるだろう」という見積もりでしたが、フタを開けてみたらちょっとした書籍程度の規模になりました。そこで、ちょうど執筆のペースは記録をとっていたため、14日間を振り返ってみることにしましょう。
12(月)
- ネタ出しとQiitaへのページ作成
00:50
-
1日目
ReturnType<T>
執筆 /00:46
- 18:04 1日目公開
残り13日、残り24記事、未公開記事0
13(火)
-
2日目
Awaited<T>
執筆 /01:33
- 17:31 2日目公開
残り12日、残り23記事、未公開記事0
14(水)
-
3日目
infer
と実例UnArray<T>
執筆 /01:07
- 8:40 3日目公開
-
4日目
実例 runRenderHook()
執筆 /01:04
-
5日目
Parameters<T>
,ConstructorParameters<T>
執筆 /01:14
残り11日、残り20記事、未公開記事2
15(木)
- 7:40 4日目公開
- 13:10 5日目公開
-
6日目
Pick<T, K>
執筆 /01:35
-
7日目
Omit<T, K>
執筆 /01:05
残り10日、残り18記事、未公開記事2
16(金)
- 12:39 6日目公開
-
8日目
Extract<T, U>
とExclude<T, U>
執筆 /00:55
残り9日、残り17記事、未公開記事2
17(土)
-
7日目
Omit<T, K>
執筆 /00:15
(計01:20
) -
9日目 Mapped Typesを活用する執筆 /
00:59
残り8日、残り16記事、未公開記事3
18(日)
- 別件にて執筆時間なし
残り7日、残り16記事、未公開記事3
19(月)
- 9:20 7日目公開
- 13:02 8日目公開
-
10日目
readonly
とReadonlyArray<T>
執筆 /00:59
-
11日目 Mapping Modifiersと実例
Writable<T, K>
執筆 /00:33
-
12日目
Partial<T>
執筆 /01:42
残り6日、残り13記事、未公開記事4
20(火)
-
9日目 Mapped Typesを活用する執筆 /
00:27
(計01:26
) - 10:30 9日目公開
- 12:16 10日目公開
-
13日目 実例
RecursivePartial<T>
執筆 /00:55
-
14日目
Required<T>
,Readonly<T>
執筆 /01:03
-
15日目
object
とRecord<K, T>
執筆 /01:49
-
16日目
intrinsic
とTemplate Literal Types執筆 /01:33
残り5日、残り9記事、未公開記事6
21(水)
残り4日、残り8記事、未公開記事5
22(木)
- 8:53 13日目公開
- 17:55 14日目公開
-
17日目
NonNullable<T>
と実例assertExists()
執筆 /01:02
(計02:03
) -
18日目 Branded Typesを導入してみる執筆 /
01:35
-
19日目 実例
FilledString
,UserId
執筆 /01:28
残り3日、残り6記事、未公開記事5
23(金)
- 9:01 15日目公開
- 13:40 16日目公開
-
17日目
NonNullable<T>
と実例assertExists()
執筆 /00:16
(計02:19
) - 15:52 17日目公開
-
19日目 実例
FilledString
,UserId
執筆 /00:45
(計02:13
) -
20日目 String Literal Typesと
as const
執筆 /01:25
残り2日、残り5記事、未公開記事3
24(土)
- 14:47 18日目公開
- 14:48 19日目公開
-
21日目
if
文とswitch
文は使い分ける?執筆 /01:18
-
22日目 実例
mapOrElse()
執筆 /00:51
-
23日目 実例
extends Error
執筆 /01:56
-
24日目 実例 再帰型定義と
RGBA
執筆 /00:46
- 22:32 20日目公開
- 22:32 21日目公開
- 22:32 22日目公開
- 22:33 23日目公開
- 22:35 24日目公開
-
25日目 実例
assertMatchedType()
執筆 /00:34
残り1日、残り1記事、未公開記事1
25(日)
-
25日目 実例
assertMatchedType()
執筆 /03:35
(計04:09
) - 12:00 25日目公開
-
目次と索引 手配
01:32
26(月)
-
目次と索引 手配
02:56
(計04:28
) - 振り返りSpace
01:10
文字数データから振り返る
日目 | 題 | 文字数 | 所要分 | 平均文字数/分 |
---|---|---|---|---|
1 | ReturnType<T> |
4555 | 46 | 99 |
2 | Awaited<T> |
6103 | 93 | 65 |
3 |
infer と実例 UnArray<T>
|
7784 | 67 | 116 |
4 | 実例 runRenderHook()
|
9439 | 64 | 147 |
5 |
Parameters<T> , ConstructorParameters<T>
|
6396 | 74 | 86 |
6 | Pick<T, K> |
6862 | 95 | 72 |
7 | Omit<T, K> |
6541 | 80 | 81 |
8 |
Extract<T, U> とExclude<T, U>
|
7269 | 55 | 132 |
9 | Mapped Typesを活用する | 3982 | 86 | 46 |
10 |
readonly とReadonlyArray<T>
|
5359 | 59 | 90 |
11 | Mapping Modifiersと実例 Writable<T, K>
|
3410 | 33 | 103 |
12 | Partial<T> |
7328 | 102 | 71 |
13 | 実例 RecursivePartial<T>
|
4702 | 55 | 85 |
14 |
Required<T> , Readonly<T>
|
3806 | 63 | 60 |
15 |
object とRecord<K, T>
|
8261 | 109 | 75 |
16 |
intrinsic とTemplate Literal Types |
7546 | 93 | 81 |
17 |
NonNullable<T> と実例 assertExists()
|
12589 | 139 | 90 |
18 | Branded Typesを導入してみる | 9124 | 95 | 96 |
19 | 実例 FilledString , UserId
|
9551 | 133 | 71 |
20 | String Literal Typesとas const
|
9813 | 85 | 115 |
21 |
if 文とswitch 文は使い分ける? |
4600 | 78 | 58 |
22 | 実例 mapOrElse()
|
3043 | 51 | 59 |
23 | 実例 extends Error
|
8071 | 116 | 69 |
24 | 実例 再帰型定義とRGBA
|
4889 | 46 | 106 |
25 | 実例 assertMatchedType()
|
26054 | 249 | 104 |
合計 | 187077 | 2166 | N/A | |
1〜24日目の平均値 | 6709.29 | 79.87 | 86.37 | |
1〜25日目の平均値 | 7483.08 | 86.64 | 87.08 |
データから考察
文字数
データから分かることとして、25日目だけ極端に記事が大きくなってしまったのですが(これは意図的なもの)それでも1〜24日目の平均文字数が6〜7千字であるという点です。
だいたい技術記事というのは4千字を割ると読み応えに欠け、1万字を超えると読むのが面倒になり途中で離脱されてしまうという傾向を肌感として持っています。そのため「技術記事としてさらっと読める文字数」というものを筆者は5千字に設定しており、それよりちょっと多い6〜7千字を「一度に読破でき、かつ満足感のある文量」としています。
その感覚から、当初の想定である2,000字25記事というのは「ツイート感覚で超短編を25本連発する」という想定だったわけですが、色々と書いているうちにちゃんとした記事の体裁になり、アベレージ5,000字以上というボリュームになりました。
この文字数の計算の注意点は原稿データから割り出しているためサンプルコードや、本文中のURLを含んでいる点です。実際に画面上に表示される文字数でみたらこの7割程度ではあるため、総文字数は(計算していませんが)10万文字強になるはずです。10万文字であれば100ページを超える程度の書籍という辺りで、鈍器と呼ばれる厚みにまではさすがに達さないです。
執筆時間
執筆時間の記録は実際に「書くぞ」という気概でキーボードに向かっていた時間の計測なので、実際はこれ以外にも、シャワーを浴びている間や、トイレに行ってる間、食事中などにもネタの順番や構成を頭の中では考えており、そういった時間は含んでいません。なので正直寝ている時間以外は記事のことをどこかで考えていました。
12月18日だけ全く執筆ができていないので除外すると、13日間で平均2時間46分は執筆に向かっていたようです。これは実際の感覚とも合致しており、弊社の通常業務(開発、打ち合わせ、経理、事務等)をしていない時間、すなわち朝に1時間と夜2〜3時間という時間確保をしていたため、想定していたペースと記録が一致しています。
朝に1本、夜に2, 3本の記事を作成するというペースが続いたので、だいたい夜はアルコール抜き、無駄な夜食抜きという生活でした。アルコールを入れてしまうとまるで書けないためです。これによってだらだらと晩酌することがなく、健康的ではありました。ただし、すべての自炊をカットしUberかコンビニのみになり、家事もすべて放棄して会社の休業日にまとめて実施していたため、全体的な生活水準でいうとかなり退廃的だとは思います。
執筆速度
執筆に費やした時間から1分辺りの文字数を出してみると、25日目を含んでも含んでいなくても1分あたり87文字であるのは興味深いです。そのため、25日目の執筆時間が長くなってしまったのは、単純に総量が多いからとわかります。
執筆から公開日までの間隔を振り返ると、おおよそ執筆後の翌日か翌々日には公開という流れになっています。このペースを維持するために、書いてから推敲と校正で2周読み直す以外はあえてもう読まないようにしています。何度も何度も読んでいると「もっとあれを足したほうが」とか「もっと説明したほうが」といった不安に駆られることもしばしばあり、今回のアドベントカレンダーはむしろそういった心理は割り切って「撮って出し」のような感覚で書くことにしました。
それでもなぜ25記事に挑戦したのか
筆者自身、アドベントカレンダーを一人で書き切ってみたいと思ったことが今まであったかというと、ありはしました。ただ、あったところで「できないしやらない」と思っていました。筆者自身、もう何年もアドベントカレンダーには参加してきましたが、参加したとして多くて年4記事、普通は年1記事の提供でした。そして年4記事ですら、ちょっと後悔したことを覚えています。
今回ついに25記事を書き切り、達成感がある一方でこれを万人に勧めることはできません。確実に犠牲となる要素も多かったためです。本節では、筆者がなぜそのような負担や犠牲があるなかで25記事執筆に挑戦したかを述べます。
教えること自体に慣れていた
筆者はもともとの出自から話すと、音楽専門学校の講師を務めていた時期があります。まだTypeScriptが世に出るより前なので10年以上前です。
この頃は打ち込み音楽、いわゆるDTMやMIDI、DAWソフトウェアの扱いや音楽理論といったことを教えていました。あまり記録が残っておらずうろ覚えではありますが、期間は2年程度だったと思います。
カリキュラムはすべて生徒の習熟度に応じて講師(筆者)が個別に組むというもので、ある程度のテンプレートはありつつも、カウンセリングしてその生徒さんごとの希望する内容や苦手とする分野を補うよう組んでいたことを覚えています。少人数制クラスでの授業は好評で、生徒のみなさんからたくさんの嬉しい感想をいただいたことをよく覚えています。
そのため、特定の技術に対して体系的にまとめあげ公開するというフロー自体には慣れがあり、一人で25記事作成するにあたりどういう順番で公開すると読み物として面白くなるかというノウハウがありました。
プロの執筆環境を一時期体験した
もうひとつの業務経験として、2017年〜18年に会社員として勤めていた株式会社ピクセルグリッドにて、その会社が運営するWeb開発者向けオンラインメディアCodeGridの連載を担当していた時期があるということです。
ここでは文章のプロである編集者の方が担当についてくださり、二人三脚体制で執筆をしていました。手応えがある文量は5,000文字であるという感覚が身についたのもこの頃です。
もともと先述の講師経験もあり、体系的な情報を論理的な日本語として書き下す訓練はできていたので、このときの執筆も大幅な赤ペンを入れられることなく、数度の打ち合わせと軽い修正以外はけっこう筆者自身の文章表現がそのまま掲載されてありがたかった覚えがあります。
とはいえ、その中で助詞の扱いや句読点の扱いなど、執筆のプロの観点で指導いただけたのは今の執筆体験に大きく寄与していると思います。今回13日間で25記事を手を止めずに書き切ることができたのは、間違いなくこのときの連載担当の経験によるものです。
商業本の執筆
いろいろと縁に恵まれて、筆者には商業本の出版経験があります。『Angularデベロッパーズガイド 高速かつ堅牢に動作するフロントエンドフレームワーク』 (ISBN 9784295002574) というもので、出版当時、2017年のAngularバージョンに合わせているためそこから5年経過した現在からするとかなり古い本です。
当時の執筆活動は、共著とはいえ険しいものであったのは事実で、かなり陰鬱な状態だったことを記憶しています。ですがやはり書店に自分の名前が並ぶという達成感はひとしお。本文とサンプルコードの書き方などは、CodeGridと合わせて商業本でもかなり学べました。
コロナ時代によるアウトプットの不足
これは筆者のNote側にも掲載した内容で、コロナの時代においてアウトプットが減少したことは、逆に今回のモチベーションに繋がりました。
ここまであまりアウトプットに割ける時間がなかった、業務が忙しかったというのは事実なのですが、それだけでなく勉強会文化の衰退を「書く機運と捉えていなかった」というのはあります。この3年間は技術勉強会がことごとく中止になり、カンファレンスも開催されなくなり、情報発信という文化そのものが見直された期間だったと思います。
2023年以降は、さすがにようやくオフラインの勉強会が復活してきそうです。オンラインでMeetやZoomで参加できる勉強会は便利ではありますが、やはり筆者としては技術コミュニティの運営スタッフを務めていただけあって、対面でなにかを伝えるという活動が好きなようで。
そんなときに「TypeScriptアドベントカレンダーに1記事寄せた人がいる」という情報と「一人で25記事を全部書いた人がいる」という情報で比較したら、どっちの人と一緒に技術イベントを展開していきたいか。自分なら間違いなく25記事書いてしまう謎のモチベーションに溢れた人物と手を組んでイベントを盛り上げていきたい。
そんなエンターテイナーとしての自分の熱意はまだ失われていなかったようで、どうすれば面白く見てもらえるか、どうすれば楽しく学べるかという、自分としての盛り上げ方や教え方の美学について一度いい区切りとして言語化して整理したいという気持ちがありました。この辺の気概は、先述の音楽専門学校の講師だったとき、バンドのミュージシャンを掛け持ちしていたマインドが割と受け継がれています。
TypeScriptの体系的な知識の整理
この速度で25記事を執筆できた理由はまだあります。
単に日常的に業務で触っているだけでは、TypeScript公式のドキュメントのどこになにが書かれているかまでは把握できていなかったと思います。その点、筆者は一度TypeScriptに関して商業本のオファーが来そうだった時期がありました。それを見越してTypeScriptのドキュメントは改めてすべて読んでおり、10万字超の原稿を用意したりもしたのですが、いろいろと事情があってTypeScript商業本として世に出ることはなくなりました。
今回のカレンダーでの内容の紹介順は、半分以上がその元原稿での紹介順を元ネタとしています。どの内容を先に紹介しておくと、あとでどの内容が紹介しやすいかというように、話題同士には複雑な依存関係がありますので、この順番を事前に考え抜いていたことは今回の速度向上に寄与しました。
その時のサンプルコードや文中の語彙、表現などは、今回のアドベントカレンダーにそのまま転用されたわけではないにせよ、かなりの部分が活かされています。特に、公式ドキュメントがどこにどういった用語で情報を掲載しているかは、かなり頭に入っていました。そのため、今回の執筆において根拠に不安な要素があったとしても、即座に該当箇所を読み込み直し、その理解で執筆を続けることができました。
サンプルコードをどう書くとよいかについても、過去の商業本の経験や、今回のTypeScript原稿において考え抜いていたため、サンプルコードづくりで悩むということはありませんでした。執筆中に調査のために逐一手を止めていないという点は、今回の執筆速度に大いに貢献しています。
一人でアドベントカレンダーをやる意義
今回、運良く様々な状況が重なり25記事を一人で書くと思い至り、そのまま達成できました。これによって得られた教訓は次のとおりです。
- 体系的に人に伝えると、自分もより体系的に理解できる
- 正確な表現を心がけると、既存の理解に曖昧な部分が減る
- どこに何が載っているか把握していると、業務上でも即座に引用できる
「技術力」という曖昧な言葉を取り上げてその高低について論じている状況をよく見かけますが、筆者はひとつには「反応の早さ」が技術力にあたると思っています。例えば、何らかの話題にどれだけすぐ反応できるか、どこの何か、いつの何かをすぐに連想して、検索して元の情報に辿り着ける、この早さは一般に言われる「技術力」の高さを構成する一要素だと思っています。もちろん記憶力や知識量も含まれますが、仮に知識が薄い領域でもその本質にすぐ辿り着ける力も含まれると思います。
これを読んでいるみなさんがアドベントカレンダーを一人で25記事書く必要はまったくないと思います。ですが、カレンダーに限らずなんらかの技術記事を書くのであれば、次のことに注意するとよりよくなります。
- ただの雑記の羅列ではなく、体系的に論理的な話題の流れになるようまとめることに注力してみる
- 正確な語彙で、正確な表現を引用することを心がける
- いくつもの信頼できる文献を確保しておく(TypeScript公式、Node.js公式、ECMAScript仕様書、MDN、など)
この心がけの蓄積は、間違いなく血となり肉となるという感覚があります。そして今回の25記事執筆は、よりその手応えを強固なものにしました。
総括
今回のアドベントカレンダーの企画は、12月12日からやると宣言したものの、その宣言通り25日に25記事を掲載しきり大成功を収めました。
その裏では、日頃からTypeScriptの体系的なカリキュラムの構築に関心があったことや、その話題を日常的に業務内で収集してきたこと、そして技術記事の執筆や勉強会登壇に慣れていたこと、といった日々の蓄積があったからこそだと感じます。
具体的に技術記事を書く際に筆者が注意している点や、扱いに気をつける表現など、執筆に伴うテクニックもいくつかありますが、その紹介についてはまた別の記事にしたいと思います。
アドベントカレンダー、ならびに本稿をお読みいただきましてありがとうございます。来年もよろしくお願いします。それではよいお年を。
Discussion