技術書典5に出典します!!

初めましてモンストサーバチームの松原です。

10月8日に催される技術書典5ですが、今回は弊社からも出典します!「XFLAG Tech Note」という名前で当日200冊を無料頒布します。また、何らかの形で電子版も配布したいと思います。

表紙はこんな感じです。かっこいいですよね、弊社のデザイナーが作ってくれました(業務の一部として作ってもらいました)。

デザイナーさんの案で知的なイメージのキャラを表紙に持ってきました

内容は以下の6つです。ちなみに、僕は4つ目を書きました。

  1. 本当にあった、モンスターストライクのギミック実装事例
  2. 明日から使える品質向上 Tips 集(モンストの QA チームが意識してることについて)
  3. とある Unity 開発事例(Unity でアーキテクチャの話)
  4. git challenge を支える技術(git challenge という学生向け競技型イベントの裏側の話)
  5. Unity で板野サーカス -誘導ミサイルでクォータニオン入門-
  6. 非同期処理の速度問題と解決の試案(Crystal で Ruby の非同期処理の速度改善)

配置は「き15」です。ご来典お待ちしております。

出来上がるまでの話

以降では、書籍が出来上がるまでの話をつらつらと書き残したいと思います。
正確には執筆時点ではまだ出来上がってないのですが(笑)

タイムライン

07/06 人事より話が持ち上がる

お疲れ様です。人事戦略室XXです。
みなさま、アウトプットしてますか?今週末は、生憎の雨で出かけられない・・!そんなあなたのために耳寄り情報!
『技術書典5』にサークル参加してみませんか?
https://blog.techbookfest.org/2018/06/20/open-for-circle/
というお誘いです
注:イベントは10月です。今週末の天候は関係ありません。
今のところ、… で集まっていただいておりますが、せっかくなので、他の方にも執筆に是非ご参加いただきたく、少しでもご興味ある方は、ここで挙手でも、私までこっそりでも構いませんので、お知らせいただけますと幸いでございます。
※サークル応募期限が7/19までのため、来週水曜までにご連絡ください 🙇 🙇 🙇
同時に!
- 表紙のデザインなどを担当してくださる素敵なデザイナーさん
- 素敵なサークル名やペンネーム
も募集しております 🙏

と言うメッセージが弊社 Slack の XFLAG ワークスペースの general チャンネルに投稿されました。
僕はこの時点で挙手をして参加しました。

07/12 初回ミーティング

コミケ玄人や別サークルで過去の技術書典に出典経験者などが居たので話を聞いたり他のサークルが出した本があったので見てみたり、イロイロと情報共有をしました。
KLab Teck Book vol.2 の第3章「Re:VIEW で書いた原稿の CI を
AWS CodeBuild で回す」を参考に執筆環境を整えることに。

07/16 までにネタ出しをする

19日が技術書典5の応募締め切りだったので、この日までに執筆者各位がざっくりとネタ出しをしました。応募それ自体は人事の人がしてくれました。

08/21 書き始める

遅いよね、わかる。もちろん、7月の時点で書き始めてもいいんですよ。

09/04 初稿〆

結局閉まらず、延期。

09/28 入稿

ここまでずっと校正を頑張ってました。

10/08 頒布!

GitHub と CI

ここからテックな話を少しだけします。GitHub で管理してる以上、せっかくだからなんか CI を使いたいですよね。と言うことで、自動ビルドと簡単な静的解析を導入しました。

自動ビルド

これは KLab Teck Book vol.2 で紹介されていたものです。AWS の CodeBuild を使うので、次のような YAML ファイルを書きました。

version: 0.2
phases:
build:
commands:
- . ./script/export-pdf.sh
post_build:
commands:
- . ./script/upload-pdf-to-slack.sh

script/export-pdf.sh で Re:VIEW のビルドを行います:

review-pdfmaker config.yml

script/upload-pdf-to-slack.sh で Slack への通知を行います:

# 版情報作成
PR_NUM=$(echo ${CODEBUILD_SOURCE_VERSION} | sed 's/pr\/\(.*\)/\1/')
HISTORY="<https://github.com/org/repo/issues/${PR_NUM}|PR-${PR_NUM}>"
# Slack 投稿用コメント作成
SLACK_COMMENT="【"${HISTORY}"】の原稿ができました"
# Slack 投稿
curl -F file=@book.pdf \
-F channels=20181008_技術書典 \
-F token=xxx \
-F initial_comment=${SLACK_COMMENT} \
https://slack.com/api/files.upload

こんな感じに届きます。PR-20 をクリックすると対応する GitHub の PR へ飛びます。

ちなみに、実行する Docker イメージには vvakame/review:2.5 を使いました。

静的解析

人力で校正するのは大変ですね。と言うことで、textlint を導入してみました。textlint は JavaScript の静的解析ツール ESLint の自然言語版です。用語のぶれ(「サーバー」か「サーバ」みたいな)や一文の句読点の数などを静的にチェックしてくれます。基本的にプラグイン形式で機能を追加していきます。

今回追加したプライグインは次の5つです。

  • textlint-plugin-review : Re:VIEW 記法に対応させるため
  • textlint-rule-max-ten : 一文の句読点の数を抑制する(僕が多用するタイプだったのでデフォルトの3個ではなく5個に設定した)
  • textlint-rule-no-mix-dearu-desumasu : 一文に「ですます調」と「である調」が混ざらないように
  • textlint-rule-prh : 「サーバー」か「サーバ」みたいな用語のぶれを抑制、WEB+DBの設定を持ってきた(ただし「git/Git」と「アプリ」は外した)
  • textlint-filter-rule-comments : textlint-disable...textlint-enable で囲まれた部分の textlint を無視する、書籍や記事の名前などどうしても無視したいときに使う用

さらに、textlint によるチェックを PR 時に CI で行い、PR へコメントするようにしました。今回やったのは細かく各行にコメントするのではなく、もっと単純にエラーメッセージを返すだけです。

僕のトークンを使ったので僕がコメントしたみたいになる

やり方は簡単で、次のようなシェルスクリプト(script/exec_textlint.sh)と:

GH_TOKEN=...
REPO=xflagstudio/techbookfest-5
textlint *.re > result
if test -s result ; then
ruby script/post_pr_comment.rb result $CODEBUILD_SOURCE_VERSION $REPO $GH_TOKEN
exit 1
fi

次のような Ruby スクリプト(script/post_pr_comment.rb)を書いて:

result   = File.read(ARGV[0]).tr('"', "'")
pr_num = ARGV[1]
if pr_num =~ /^pr/
endpoint = "api.github.com/repos/#{ARGV[2]}/issues/#{pr_num.tr('pr/','')}/comments"
url = "https:/#{endpoint}?access_token=#{ARGV[3]}"
json = "{\"body\":\"textlint でエラーがあったようです。\n~~~#{result}~~~\"}"
puts "[POST] : #{endpoint} : #{json.inspect}"
`curl -X POST -H 'Content-Type:application/json' -d #{json.inspect} #{url}`
end

buildspec.yml を更新するだけです:

version: 0.2
phases:
build:
commands:
- . ./script/export-pdf.sh
post_build:
commands:
- . ./script/upload-pdf-to-slack.sh
- . ./script/exec_textlint.sh # 追加

Ruby を使ったのは単純に Re:VIEW が Ruby だからです(余計な環境構築をする必要がない)。多分もっといい書き方がある気がしますが、書き捨てのスクリプトなのでご勘弁を。

そして、これを CI で回すには Docker イメージを更新する必要があります。前述した通り、もともとは vvakame/review:2.5 と言う Docker イメージを利用してビルドしていたので、プラグインを npm でインストールする必要があるからです。

FROM vvakame/review:2.5
RUN npm install -g \
textlint \
textlint-plugin-review \
textlint-rule-max-ten \
textlint-rule-no-mix-dearu-desumasu \
textlint-rule-prh \
textlint-filter-rule-comments

ビルドした Docker イメージは AWS の ECR にあげて CI などで利用します。

Re:VIEW の調整

Re:VIEW は学生時代にお世話になる LaTeX に Ruby の皮を被せたような組版システムです。そのため、フォントサイズなど細かい調整を LaTeX で行う必要があります。

いじったところは以下の通り:

  • 章や節のフォントサイズ
  • ヘッダーやフッターのフォントサイズ
  • 図表のキャプションのフォントサイズ
  • リンクのフォントカラーを変更
  • 目次の出力レベルを減らす

最後のやつは簡単で Re:VIEW の config.ymltoclevel をいじれば良い(デフォルトが 3 だったので 2 にした)。

他は sty/reviewmacro.stylayouts/layout.tex.erb をいじる必要があります。フォントサイズの調整をいろんなところでするのが面倒だったので、次のような設定を config.yml で記述しました:

fontsize:
chapter: 22pt
section: 14pt
section_num: 15pt
subsection: 12pt
subsubsection: 10pt
paragraph: 10pt
graph: footnotesize
chaptermark: footnotesize
sectionmark: footnotesize
footer: small

layout.tex.erb ではこれらの設定を @config["fontsize"]["chapter"] と書くことで取り出せます。
reviewmacro.sty でも同様にできれば楽なので、次のようなスクリプト lib/tasks/customize_style.rake を書きました:

require 'yaml'
require 'erb'
namespace :style do
desc 'generate style file and layout file'
task :gen do
config_path = ENV.fetch('config', './config.yml')
style_path = ENV.fetch('style', './sty/reviewmacro.sty')
puts "Generate style file from #{style_path}.erb with #{config_path}"
    config     = YAML.load_file(config_path)
style_tmpl = File.read(style_path + '.erb')
    fontsize = {}
config['fontsize'].each do |key, value|
if value =~ /pt$/
fontsize[key] = "\\fontsize{#{value}}{1cm}\\selectfont"
elsif ['footer'].include?(key)
fontsize[key] = "\\#{value}"
else
fontsize[key] = value
end
end
    puts "fontsize: #{fontsize}"
File.write(style_path, ERB.new(style_tmpl).result(binding))
end
end

これの実行を script/export-pdf.sh に書き加えます。

bundle exec rake style:gen # 追加
review-pdfmaker config.yml

ちなみに、章や説のフォントサイズは次のようなものを sty/reviewmacro.sty.erb に書きます。

\def\@makechapterhead#1{%
\vspace*{2\Cvs}% 欧文は50pt
{\parindent \z@ \raggedright \normalfont
\ifnum \c@secnumdepth >\m@ne
\if@mainmatter
\huge\headfont \@chapapp\thechapter\@chappos
\par\nobreak
\vskip \Cvs % 欧文は20pt
\fi
\fi
\interlinepenalty\@M
<%= fontsize['chapter'] %> \headfont #1\par\nobreak
\vskip 3\Cvs}} % 欧文は40pt
\renewcommand{\section}{%
\if@slide\clearpage\fi
\@startsection{section}{1}{\z@<%= fontsize['section_num'] %>}%
{\Cvs \@plus.5\Cdp \@minus.2\Cdp}% 前アキ
{.5\Cvs \@plus.3\Cdp}% 後アキ
{\normalfont<%= fontsize['section'] %>\headfont\raggedright}}
\renewcommand{\subsection}{\@startsection{subsection}{2}{\z@}%
{\Cvs \@plus.5\Cdp \@minus.2\Cdp}% 前アキ
{.5\Cvs \@plus.3\Cdp}% 後アキ
{\normalfont<%= fontsize['subsection'] %>\headfont}}
\renewcommand{\subsubsection}{\@startsection{subsubsection}{3}{\z@}%
{\Cvs \@plus.5\Cdp \@minus.2\Cdp}%
{\if@slide .5\Cvs \@plus.3\Cdp \else \z@ \fi}%
{\normalfont<%= fontsize['subsubsection'] %>\headfont}}
\renewcommand{\paragraph}{\@startsection{paragraph}{4}{\z@}%
{0.5\Cvs \@plus.5\Cdp \@minus.2\Cdp}%
{\if@slide .5\Cvs \@plus.3\Cdp \else -1zw\fi}% 改行せず 1zw のアキ
{\normalfont<%= fontsize['paragraph'] %>\jsParagraphMark}}

ヘッダーは layouts/layout.tex.erbchaptermarksectionmark をいじりました:

\renewcommand{\chaptermark}[1]{\markboth{\<%= @config["fontsize"]["chaptermark"] %>\prechaptername\thechapter\postchaptername~#1}{}}
\renewcommand{\sectionmark}[1]{\markright{\<%= @config["fontsize"]["sectionmark"] %>\thesection #1}{}}

フッターは reviewmacro.sty.erbfancyfoot と言う部分をいじります。
また reviewmacro.sty.erb に、リンクのフォントカラーを変更するために \hypersetup{linkcolor=black} と言う一文を追加し、図表のキャプションのフォントサイズを変更するために \usepackage[font=<%= fontsize['graph'] %>,labelfont=bf]{caption} をに追加しました。

最後の。。。

9月28日に入稿したのですが、修正依頼がきました。
一応書いておきます。

  • B5サイズでデータ作る必要あり : 1p目だけ全面イラストなので、塗り足し188x263で作る
  • 通しでノンブル必要 : のりで隠れる隠し位置でいいので1–100まで欲しい
  • まえがきの本文、目次の節、各章のはじめにだけ文字色がグレーだが問題ないか

特に一つ目が問題で、僕は確かに次のような変更をして Re:VIEW で B5 が吐き出されるようにしていた。

page_metric: B5

実はこれは間違ってなく、Re:VIEW 自体は B5 で作成しているが、最終的な出力PDFが A4 になっているようだ。

デザイナーが作ってくれた超わかりやすい説明画像

結局、デザイナーさんが直せそうとのことで修正してもらった。
感謝。

おしまい

執筆してくれた方達はもちろん、表紙や最終的なデザイン等の校正をしてくれたデザイナーさん、文章の校正や事務的な手続きをしてくださった人事部の方達の協力のもと無事完成しそうです。感想を少し述べると、会社の中のチームでやることで、いろんな業種の方達がいい感じに協力できて楽しかったです。

モンストの5周年企画と重なり、各位業務の忙しい中、時間を調整して作成した渾身の一冊です。ぜひ貰いにきてください!