forked from heroku/erlang-in-anger
/
101-diving-ja.tex
232 lines (178 loc) · 28.9 KB
/
101-diving-ja.tex
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
%\chapter{How to Dive into a Code Base}
\chapter{コードベースへの飛び込み方}
\label{chap:how-to-dive-into-a-code-base}
%"Read the source" is one of the most annoying things to be told, but dealing with Erlang programmers, you'll have to do it often. Either the documentation for a library will be incomplete, outdated, or just not there. In other cases, Erlang programmers are a bit similar to Lispers in that they will tend to write libraries that will solve their problems and not really test or try them in other circumstances, leaving it to you to extend or fix issues that arise in new contexts.
「ソースを読め」というフレーズは言われるともっとも煩わしい言葉ではありますが、Erlangプログラマとしてやっていくのであれば、しばしばそうしなければならないでしょう。
ライブラリのドキュメントが不完全だったり、古かったり、あるいは単純にドキュメントが存在しなかったりします。
また他の理由として、ErlangプログラマはLisperに近しいところが少しあって、ライブラリを書くときには自身に起こっている問題を解決するために書いて、テストをしたり、他の状況で試したりということはあまりしない傾向にあります。そしてそういった別のコンテキストで発生する問題を直したり、拡張する場合は自分で行う必要があります。
%It's thus pretty much guaranteed you'll have to go dive in some code base you know nothing about, either because you inherited it at work, or because you need to fix it or understand it to be able to move forward with your own system. This is in fact true of most languages whenever the project you work on is not one you designed yourself.
したがって、仕事で引き継ぎがあった場合でも、自分のシステムと連携するために問題を修正したりあるいは中身を理解する場合でも、何も知らないコードベースに飛び込まなければならなくなることはまず間違いないでしょう。
これは取り組んでいるプロジェクトが自分自身で設計したわけではない場合はいつでも、たいていの言語でも同様です。
%There are three main types of Erlang code bases you'll encounter in the wild: raw Erlang code bases, OTP applications, and OTP releases. In this chapter, we'll look at each of these and try to provide helpful tips on navigating them.
世間にあるErlangのコードベースには主に3つの種類があります。1つめは生のErlangコードベース、2つめはOTPアプリケーション、3つめはOTPリリースです。
この章ではこれら3つのそれぞれに見ていき、それぞれを読み込んでいくのに役立つ秘訣をお教えします。
%\section{Raw Erlang}
\section{生のErlang}
\label{sec:dive-raw-erlang}
%If you encounter a raw Erlang code base, you're pretty much on your own. These rarely follow any specific standard, and you have to dive in the old way to figure out whatever happens in there.
生のErlangコードベースに遭遇したら、各自でなんとかしてください。こうしたコードはなにか特に標準に従っているわけでもないので、何が起きているかは自分で深い道に分け入っていかなければなりません。
%This means hoping for a \filename{README.md} file or something similar that can point to an entry point in the application, and going from there, or hoping for some contact information that can be used to ask questions to the author(s) of the library.
つまり、\filename{README.md}ファイルの類がアプリケーションのエントリーポイントを示してくれていて、さらにいえば、ライブラリ作者に質問するための連絡先情報などがあることを願うのみということです。
%Fortunately, you should rarely encounter raw Erlang in the wild, and they are often beginner projects, or awesome projects that were once built by Erlang beginners and now need a serious rewrite. In general, the advent of tools such as \app{rebar3} and its earlier incarnations\footnote{\href{https://www.rebar3.org}{https://www.rebar3.org} — a build tool briefly introduced in Chapter \ref{chap:building-open-source-erlang-software}} made it so most people use OTP Applications.
幸いにも、生のErlangに遭遇することは滅多にありません。あったとしても、だいたいが初心者のプロジェクトか、あるいはかつてErlang初心者によって書かれた素晴らしいプロジェクトで真剣に書き直しが必要になっているものです。
一般的に、 \app{rebar3} やその前身 \footnote{\href{https://www.rebar3.org}{https://www.rebar3.org} --- 第 \ref{chap:building-open-source-erlang-software} 章で簡単に紹介されるビルドツールです。} のようなツールの出現によって、ほとんどの人がOTPアプリケーションを使うようになりました。
%\section{OTP Applications}
\section{OTPアプリケーション}
\label{sec:dive-otp-applications}
%Figuring out OTP applications is usually rather simple. They usually all share a directory structure that looks like:
OTPアプリケーションを理解するのは通常かなり単純です。OTPアプリケーションはみな次のようなディレクトリ構造をしています。
\begin{VerbatimRaw}
doc/
ebin/
src/
test/
LICENSE.txt
README.md
rebar.config
\end{VerbatimRaw}
%There might be slight differences, but the general structure will be the same.
わずかな違いはあるかもしれませんが、一般的な構造は同じです。
%Each OTP application should contain an \emph{app file}, either \filename{ebin/<AppName>.app} or more often, \filename{src/<AppName>.app.src}\footnote{A build system generates the final file that goes in \filename{ebin}. Note that in these cases, many \filename{src/<AppName>.app.src} files do not specify modules and let the build system take care of it.}. There are two main varieties of app files:
各OTPアプリケーションは \emph{appファイル} を持っていて、\filename{ebin/<AppName>.app}か、あるいはしばしば \filename{src/<AppName>.app.src} という名前になっているはずです。\footnote{ビルドシステムが最終的に \filename{ebin} にファイルを生成します。この場合、多くの \filename{src/<AppName>.app.src} ファイルはモジュールを示すものではなく、ビルドシステムがモジュール化の面倒を見ることになります。}
appファイルには主に2つの種類があります。
\includecode[erlang]{useragent.app.src}
%And:
そして
\includecode[erlang]{dispcount.app}
の2種類です。
%This first case is called a \emph{library application}, while the second case is a regular \emph{application}.
最初のケースは \emph{ライブラリアプリケーション} と呼ばれていて、2つめのケースは標準 \emph{アプリケーション} と呼ばれています。
%\subsection{Library Applications}
\subsection{ライブラリアプリケーション}
\label{subsec:dive-library-applications}
%Library applications will usually have modules named \module{\emph{appname}\_something}, and one module named \module{\emph{appname}}. This will usually be the interface module that's central to the library and contains a quick way into most of the functionality provided.
ライブラリアプリケーションは通常 \module{\emph{appname}\_something} というような名前のモジュールと、 \module{\emph{appname}} という名前のモジュールを持っています。
これは通常ライブラリの中心となるインターフェースモジュールで、提供される大半の機能がそこに含まれています。
%By looking at the source of the module, you can figure out how it works with little effort: If the module adheres to any given behaviour (\module{gen\_server}, \module{gen\_fsm}, etc.), you're most likely expected to start a process under one of your own supervisors and call it that way. If no behaviour is included, then you probably have a functional, stateless library on your hands. For this case, the module's exported functions should give you a quick way to understand its purpose.
モジュールのソースを見ることで、少しの労力でモジュールがどのように動作するか理解できます。もしモジュールが特定のビヘイビア(\module{gen\_server}や\module{gen\_fsm}など)を何度も使っているようであれば、おそらくスーパーバイザーの下でプロセスを起動して、然るべき方法で呼び出すことが想定されているでしょう。
ビヘイビアが一つもなければ、そこにあるのは関数のステートレスなライブラリです。この場合、モジュールのエクスポートされた関数を見ることで、このライブラリの目的を素早く理解できるでしょう。
%\subsection{Regular Applications}
\subsection{標準アプリケーション}
\label{subsec:dive-regular-applications}
%For a regular OTP application, there are two potential modules that act as the entry point:
標準的なOTPアプリケーションでは、エントリーポイントとして機能する2つの潜在的なモジュールがあります。
\begin{enumerate*}
\item \module{\emph{appname}}
\item \module{\emph{appname}\_app}
\end{enumerate*}
%The first file should be similar in use to what we had in a library application (an entry point), while the second one will implement the \module{application} behaviour, and will represent the top of the application's process hierarchy. In some cases the first file will play both roles at once.
最初のファイルはライブラリアプリケーションで見たものと似た使われ方(エントリーポイント)をします。一方で、2つめのファイルは \module{application} ビヘイビアを実装するもので、アプリケーションの階層構造の頂点を表すものになります。
状況によっては最初のファイルは同時に両方の役割を果たします。
%If you plan on simply adding the application as a dependency to your own app, then look inside \module{\emph{appname}} for details and information. If you need to maintain and/or fix the application, go for \module{\emph{appname}\_app} instead.
そのアプリケーションを単純にあなたのアプリケーションの依存先として追加しようとしているのであれば、 \module{\emph{appname}}の中を詳しく見てみましょう。
そのアプリケーションの運用や修正を行う必要があるのであれば、かわりに \module{\emph{appname}\_app} の中を見てみましょう。
%The application will start a top-level supervisor and return its \emph{pid}. This top-level supervisor will then contain the specifications of all the child processes it will start on its own\footnote{In some cases, the supervisor specifies no children: they will either be started dynamically by some function of the API or in a start phase of the application, or the supervisor is only there to allow OTP environment variables (in the \expression{env} tuple of the app file) to be loaded.}.
アプリケーションはトップレベルのスーパーバイザーを起動して、その \emph{pid} を返します。
このトップレベルのスーパーバイザーはそれが自動で起動するすべての子プロセスの仕様を含んでいます。 \footnote{場合によっては、そのスーパーバイザーが子プロセスをまったく指定しないこともあります。その場合、子プロセスはそのAPIの関数あるいはアプリケーションの起動プロセス内で動的に起動される、あるいはそのスーパーバイザーが(アプリケーションファイルの \expression{env} タプル内の)OTPの環境変数が読み込まれるのを許可するためだけに存在しているかのどちらかです。}
%The higher a process resides in the tree, the more likely it is to be vital to the survival of the application. You can also estimate how important a process is by the order it is started (all children in the supervision tree are started in order, depth-first). If a process is started later in the supervision tree, it probably depends on processes that were started earlier.
プロセスが監視ツリーのより上位にあれば、アプリケーションの存続にとってより不可欠になってきます。
またプロセスの重要性は起動開始の早さによっても予測可能です。(監視ツリー内の子プロセスはすべて順番に深さ優先で起動されています。)
プロセスが監視ツリー内であとの方で起動されたとしたら、おそらくそれより前に起動されたプロセスに依存しているでしょう。
%Moreover, worker processes that depend on each other within the same application (say, a process that buffers socket communications and relays them to a finite-state machine in charge of understanding the protocol) are likely to be regrouped under the same supervisor and to fail together when something goes wrong. This is a deliberate choice, as it is usually simpler to start from a blank slate, restarting both processes, rather than trying to figure out how to recuperate when one or the other loses or corrupts its state.
さらに、同じアプリケーション内で依存しあっているワーカープロセス(たとえば、ソケット通信をバッファしているプロセスと、その通信プロトコルを理解するための有限ステートマシンにそのデータをリレーするプロセス)は、おそらく同じスーパーバイザーの下で再グループ化されていて、何かおかしなことが起きたらまとめて落ちるでしょう。
これは熟慮の末の選択で、通常どちらかのプロセスがいなくなったり状態がおかしくなってしまったときに、両方のプロセスを再起動してまっさらな状態から始めるほうが、どう回復するかを考えるよりも単純だからです。
%The supervisor restart strategy reflects the relationship between processes under a supervisor:
スーパーバイザーの再起動戦略はスーパーバイザー以下のプロセス間での関係性に影響を与えます。
\begin{itemize*}
%\item \expression{one\_for\_one} and \expression{simple\_one\_for\_one} are used for processes that are not dependent upon each other directly, although their failures will collectively be counted towards total application shutdown\footnote{Some developers will use \expression{one\_for\_one} supervisors when \expression{rest\_for\_one} is more appropriate. They require strict ordering to boot correctly, but forget about said order when restarting or if a predecessor dies.}.
\item \expression{one\_for\_one}と\expression{simple\_one\_for\_one}は、失敗は全体としてアプリケーションの停止に関係してくるものの、お互いに直接依存しあっていないプロセスに使われます。\footnote{開発者によっては\expression{rest\_for\_one}がより適切な場面で\expression{one\_for\_one}を使ったりします。起動順を正しく行うことを求めてそうするわけですが、先に言ったような再起動時や先に起動されたプロセスが死んだときの起動順については忘れてしまうのです。}
%\item \expression{rest\_for\_one} will be used to represent processes that depend on each other in a linear manner.
\item \expression{rest\_for\_one}はお互いに直列に依存しているプロセスを表現するうときに使われます。
%\item \expression{one\_for\_all} is used for processes that entirely depend on each other.
\item \expression{one\_for\_all}は全体がお互いに依存しあっているプロセスに使われます。
\end{itemize*}
%This structure means it is easiest to navigate OTP applications in a top-down manner by exploring supervision subtrees.
この構造の意味するところは、OTPアプリケーションを見るときは監視ツリーを上から順にたどるのが最も簡単であるということです。
%For each worker process supervised, the behaviour it implements will give a good clue about its purpose:
監視された各ワーカープロセスでは、それが実装しているビヘイビアがそのプロセスの目的を知る上で良い手がかりとなります。
\begin{itemize*}
%\item a \module{gen\_server} holds resources and tends to follow client/server patterns (or more generally, request/response patterns)
\item \module{gen\_server} はリソースを保持して、クライアント・サーバーパターン(より一般的にはリクエスト・レスポンスパターン)に沿っています。
%\item a \module{gen\_fsm} will deal with a sequence of events or inputs and react depending on them, as a Finite State Machine. It will often be used to implement protocols.
\item \module{gen\_fsm} は有限ステートマシンなので一連のイベントやイベントに依存する入力と反応を扱います。プロトコルを実装するときによく使われます。
%\item a \module{gen\_event} will act as an event hub for callbacks, or as a way to deal with notifications of some sort.
\item \module{gen\_event} はコールバック用のイベントのハブとして振る舞ったり、通知を扱う方法として使われます。
\end{itemize*}
%All of these modules will contain the same kind of structure: exported functions that represent the user-facing interface, exported functions for the callback module, and private functions, usually in that order.
これらのモジュールはすべてある種の構造を持っています。通常はユーザーに晒されたインターフェースを表すエクスポートされた関数、コールバックモジュール用のエクスポートされた関数、プライベート関数の順です。
%Based on their supervision relationship and the typical role of each behaviour, looking at the interface to be used by other modules and the behaviours implemented should reveal a lot of information about the program you're diving into.
監視関係や各ビヘイビアの典型的な役割を下地に、他のモジュールに使われているインターフェースや実装されたビヘイビアを見ることで、いま読み込んでいるプログラムに関するたくさんの情報が明らかになります。
%\subsection{Dependencies}
\subsection{依存関係}
\label{subsec:dive-dependencies}
%All applications have dependencies\footnote{At the very least on the \module{kernel} and \module{stdlib} applications}, and these dependencies will have their own dependencies. OTP applications usually share no state between them, so it's possible to know what bits of code depend on what other bits of code by looking at the app file only, assuming the developer wrote them in a mostly correct manner. Figure~\ref{fig:app-deps} shows a diagram that can be generated from looking at app files to help understand the structure of OTP applications.
すべてのアプリケーションには依存するものが存在します。\footnote{どんなに少なくとも\module{kernel}アプリケーションと\module{stdlib}アプリケーションに依存しています。}そして、これらの依存先にはそれぞれの依存が存在します。
OTPアプリケーションには通常状態を共有するものはありません。したがって、コードのある部分が他の部分にどのように依存しているかは、アプリケーションの開発者が正しく実装していると想定すれば、アプリケーションファイルをみるだけで知ることが出来ます。
図~\ref{fig:app-deps}は、アプリケーションファイルを見ることで生成できるダイアグラムで、OTPアプリケーションの構造の理解に役立ちます。
\begin{figure}
\includegraphics{app-deps-riak-cs.pdf}%
%\caption{Dependency graph of riak\_cs, Basho's open source cloud library.
%The graph ignores dependencies on common applications like kernel and stdlib. Ovals are applications, rectangles are library applications.}
\caption{Bashoのオープンソースクラウドライブラリである riak\_cs の依存関係を表したグラフです。
このグラフはkernelやstdlibといった必ず依存するようなものは除いています。楕円はアプリケーションで、四角はライブラリアプリケーションです。}
\label{fig:app-deps}
\end{figure}
%Using such a hierarchy and looking at each application's short description might be helpful to draw a rough, general map of where everything is located. To generate a similar diagram, find \app{recon}'s script directory and call \command{escript script/app\_deps.erl}\footnote{This script depends on graphviz}. Similar hierarchies can be found using the \module{observer}\footnote{\href{http://www.erlang.org/doc/apps/observer/observer\_ug.html}{http://www.erlang.org/doc/apps/observer/observer\_ug.html}} application, but for individual supervision trees. Put together, you may get an easy way to find out what does what in the code base.
こうした依存関係を使って各アプリケーションの短い解説を見ることで、何がどこにあるかの大まかな地図を描くのに役立つでしょう。
似たダイヤグラムを生成するためには、\app{recon}のscriptディレクトリ内のツールを使って\command{escript script/app\_deps.erl}を実行してみましょう。\footnote{このスクリプトはgraphvizに依存しています。}
似たダイヤグラムが\module{observer}\footnote{\href{http://www.erlang.org/doc/apps/observer/observer\_ug.html}{http://www.erlang.org/doc/apps/observer/observer\_ug.html}}アプリケーションを使うことで得られますが、各監視ツリーのものになります。
これらをまとめることで、コードベースの中で何が何をしているかを簡単に見つけられるようになるでしょう。
\FloatBarrier
%\section{OTP Releases}
\section{OTPリリース}
\label{sec:dive-otp-releases}
%OTP releases are not a lot harder to understand than most OTP applications you'll encounter in the wild. A release is a set of OTP applications packaged in a production-ready manner so it boots and shuts down without needing to manually call \function{application:start/2} for any app. Compiled releases may contain their own copy of the Erlang virtual machine with more or less libraries than the default distribution, and can be ready to run standalone. Of course there's a bit more to releases than that, but generally, the same discovery process used for individual OTP applications will be applicable here.
OTPリリースは世間で見かけるたいていのOTPアプリケーションよりもそれほど難しいものではありません。
OTPリリースは複数のOTPアプリケーションを本番投入可能な状態でパッケージ化したもので、これによって手動でアプリケーションの\function{application:start/2}を呼び出す必要なく起動と停止を行えるようになっています。
コンパイルされたリリースが含むライブラリの数は、デフォルトの配布形式と比べて多少違いますが、自分専用のErlang VMのコピーを持っていて、単独で起動できるようになっています。
もちろん、リリースに関してはまだ話すことはありますが、一般的にOTPアプリケーションのときと同じようなやり方で中身を確認していきます。
%You'll usually have a file named \filename{relx.config} or a \term{relx} tuple in a \filename{rebar.config} file, which will state which top-level applications are part of the release and some options regarding their packaging. Relx-based releases can be understood by reading the project's wiki\footnote{\href{https://github.com/erlware/relx/wiki}{https://github.com/erlware/relx/wiki}}, or their documentation on the documentation sites of \app{rebar3}\footnote{\href{https://www.rebar3.org/docs/releases}{https://www.rebar3.org/docs/releases}} or \filename{erlang.mk}\footnote{\href{http://erlang.mk/guide/relx.html}{http://erlang.mk/guide/relx.html}}.
OTPリリース内には通常、\filename{relx.config}または\filename{rebar.config}ファイル内の\term{relx}タプルがあります。ここに、どのトップレベルアプリケーションがリリースに含まれているかとパッケージ化に関するオプションが書かれています。
relxを使ったリリースはプロジェクトのWikiページ\footnote{\href{https://github.com/erlware/relx/wiki}{https://github.com/erlware/relx/wiki}}や\app{rebar3}\footnote{\href{https://www.rebar3.org/docs/releases}{https://www.rebar3.org/docs/releases}}のドキュメントサイトや\filename{erlang.mk}\footnote{\href{http://erlang.mk/guide/relx.html}{http://erlang.mk/guide/relx.html}}にあるドキュメントを読めば理解できます。
%Other systems may depend on the configuration files used by \module{systools} or \module{reltool}, which will state all applications part of the release and a few\footnote{A lot} options regarding their packaging. To understand them, I recommend \href{http://learnyousomeerlang.com/release-is-the-word}{reading existing documentation on them}.
他のシステムは\module{systools}や\module{reltool}で使われる設定ファイルに依存しているでしょう。
ここにリリースに含まれるすべてのアプリケーションが記述されていて、パッケージに関するオプションが少々\footnote{多数}書かれています。
それらを理解するには、\href{http://learnyousomeerlang.com/release-is-the-word}{既存のドキュメントを読むことをおすすめします。}\footnote{訳注: 日本語訳版 \href{https://www.ymotongpoo.com/works/lyse-ja/ja/24\_release\_is\_the\_word.html}{https://www.ymotongpoo.com/works/lyse-ja/ja/24\_release\_is\_the\_word.html}}
%\section{Exercises}
\section{演習}
%\subsection*{Review Questions}
\subsection*{復習問題}
\begin{enumerate}
%\item How do you know if a code base is an application? A release?
\item コードベースがアプリケーションがリリースかはどうやって確認できますか
%\item What differentiates an application from a library application?
\item ライブラリアプリケーションとアプリケーションはどの点が異なりますか
%\item What can be said of processes under a \term{one\_for\_all} scheme for supervision?
\item 監視において\term{one\_for\_all}戦略で管理されるプロセスとはどういうプロセスですか
%\item Why would someone use a \module{gen\_fsm} behaviour over a \module{gen\_server}?
\item \module{gen\_server}ビヘイビアではなく\module{gen\_fsm}ビヘイビアを使うのはどういう状況ですか
\end{enumerate}
%\subsection*{Hands-On}
\subsection*{ハンズオン}
%Download the code at \href{https://github.com/ferd/recon\_demo}{https://github.com/ferd/recon\_demo}. This will be used as a test bed for exercises throughout the book. Given you are not familiar with the code base yet, let's see if you can use the tips and tricks mentioned in this chapter to get an understanding of it.
\href{https://github.com/ferd/recon\_demo}{https://github.com/ferd/recon\_demo}のコードをダウンロードしてください。
このコードは本書内の演習問題のテストベッドとして使われます。このコードベースにまだ詳しくないという前提で、この章で説明された秘訣や裏ワザを使ってこのコードベースを理解できるか見てみましょう。
\begin{enumerate}
%\item Is this application meant to be used as a library? A standalone system?
\item このアプリケーションはライブラリですか。スタンドアロンシステムですか。
%\item What does it do?
\item このアプリは何をしますか。
%\item Does it have any dependencies? What are they?
\item 依存するものはありますか。あるとすればなんですか。
%\item The app's \filename{README} mentions being non-deterministic. Can you prove if this is true? How?
\item \filename{README}によると、このアプリケーションは非決定的な振る舞いをするらしい。これは真でしょうか。その理由も説明してください。
%\item Can you express the dependency chain of applications in there? Generate a diagram of them?
\item このアプリケーションの依存関係の連鎖を表現できますか。ダイヤグラムを生成してください。
%\item Can you add more processes to the main application than those described in the \filename{README}?
\item \filename{README}で説明されているメインアプリケーションにより多くのプロセスを追加できますか。
\end{enumerate}