fmlのProgramming Style
(株)インターネットイニシアティブ
札幌支店インターネット技術部
深町 賢一
Copyright (C) 1998 Ken'ichi Fukamachi
All rights reserved.
(page 1)
Table of Contents
fml overview
Programming Style
Perl4と5のはざまで
ポータビリティ
まとめ
今後について
(page 2)
fml overview
(page 3)
メーリングリスト
メーリングリストの概念図
MTA(Mail Transport Agent)がメールを受け、下受けのfmlに渡す。
fmlが一種のフィルタリングとして機能し再びMTAにMLのメンバーへの配送をゆだねる。
(page 4)
動機: perlの選択
- それ以上はshell script(/bin/sh)かperlに移る
どっちを使うかは内容次第
text処理中心ならperl
メーリングリストはtext処理が一杯だろう
socket使いたい(自力SMTP)
最近(当時)流行りつつあって面白そう:) # 4.01xの頃の話
(page 5)
mgp2ps4 (sh+perl)
この資料を印刷するのに作ったdebug拡張込み10分で作成(いいかげん)プログラム:)
postscriptを一行修正するだけのもの。shell script と perl の混成
#!/bin/sh
PSMULTI4="psmulti -rtol -r180 -pages 4"
FILTER=/tmp/disable_showpage.pl
... variables ...
trap "rm -f $FILTER $tmp" 0 1 3 15
set -- `getopt hdp:cv $*`
... getopt ...
echo x - disable_showpage.pl 1>&2
sed 's/^X//' >disable_showpage.pl << 'END-of-disable_showpage.pl'
Xwhile (<>){
X if ($flag && /showpage/) {
X s/showpage/pshowpage/; $flag = 0;
X }
X if (/^\/(BeginDocument|BeginEPSF)/) { $flag = 1;}
X print;
X}
END-of-disable_showpage.pl
if [ $pages -eq 4 ]
then
mgp2ps $opt $* | perl $FILTER | $PSMULTI4 | perl $FILTER
...
(page 6)
動機: 何故作る?
- それは1993年頃…
- eval `cat /etc/majordomo.cf `;
(センスにめまい) => 捨て!
- メーリングリストと1/fゆらぎの研究のために実装もしてみる
K. Fukamachi,
Interdisciplinary Information Science vol.1, 157 (1995)
(page 7)
デザイン・ポリシー
- 人間は機械より高価な資源
- routine workを減らしたい
- 改造の手間暇
- 管理者やユーザの自由度
- 人間は人それぞれなもの。それを尊重しよう。
- デフォールトの挙動は注意深く選ぼう
- その一方で上級者には自由にパラメータを変えられるように
- 豊富な機能
- 明示的に機能をONにするべし(deny and permit ...)
- 改造の出発点は初めから一通り揃えておきたい
(page 8)
歴史
Official Release History (fj.sources)
日付 リリース
1998/09 2.2
1997/08 2.1
1995/01 1.5
1994/09 1.3
1994/05 1.2.1
1994/03 1.2
[備考]
1.6 %Envelope hashの導入
2.0 幻のversion?
(page 9)
Supported Systems
今は1.3H(1998/09上旬)
Windows NT4
βテスト中で、2つのバージョンがある
include形式
POP3版(POP -> fml -> MTA)
sendmail(+smtpfeed), qmail, exim などで実験
(page 10)
必要な環境
自分もしくはML専用のアカウント
localhost
同じLAN上の複数のMTA
同じホストで違うポートでMTA
- NT上でPOP版を使う場合はPOPサーバとMTA両方
それぞれ別のマシン可
配送だけUNIXでsmtpfeedとかも可 :)
(page 11)
特徴(1)
- makefml対話設定プログラム(CUI)
- 配送用アドレス、コマンド用アドレスごとのアクセス制御
(anyone/members_only/moderator)
- 自動登録/削除:confirmation他
- 投稿メールのフィルタリング
- トラフィックモニタ(mail bomb対策)
- Message-ID Cache, 特殊accountの排除(ループ対策)
- まとめ送り(ユーザごとにcustomize)
- リモート管理(認証:address+password〜PGP)
- PGP暗合化ML
(page 12)
特徴(2)
- ヘッダフィールドのきめこまかい設定
- 豊富なファイル操作
UNIX FROM,RFC934,RFC1153,MIME/Multipart
gzip,Lha + Ish,Lha + uuencode,tar + gzip
zip + base64,uuencode
- 記事の自動圧縮/Expire
- HTML記事作成(HTML 4.0 FORMAT)
- Listserv(Majordomo)互換インターフェイス
- MLに参加し続けるか?を一定期間ごとにconfirmする
- エラーメールを解析して自動的にユーザを削除する(β)
(page 13)
特徴(3)
- newsyslog(8)/RCS backup of configurations
- RESOURCE LIMITS
メールサイズ
メンバー数
1メール当たりのコマンド数
- USE_MEMBER_NAME extension
address と実名のテーブル
スタートレック宇宙歴
mail2irc
(page 14)
Programming Style
(page 15)
fmlの場合の決めごと
これらは開発のはじまる前に決められた。
- 変数名
- 全部大文字: ユーザ定義用のグローバル変数
- 大文字で始まる: システム用のグローバル変数
- 子文字: ローカル変数
- 関数名
- 原則としてX11風に大文字で始まる文字列
- ユーザカスタマイズ用のものは全部大文字
- なお & はつけることになっている
(page 16)
関数名の例
大文字で始まる
&Distribute(*e)
&SetEvent &ClearEvent &Tick
Lisp風
チェックをしてyes/noを返す類い(p == predicate)
&SecureP &MailLoopP
大文字
ユーザ定義用なので変数と同様に大文字
&DEFINE_SUBJECT_TAG("[ ]");
e.g. [Elena ID] style
(page 17)
変数名の例
ユーザカスタマイズ用
$DOMAINNAME = "fml.org";
$FQDN = "beth.fml.org";
$MAIL_LIST = "elena\@$DOMAINNAME";
$PERMIT_POST_FROM = "members_only";
$REJECT_POST_HANDLER = "reject";
システムの使うグローバル変数
%Envelope (sendmailのENVELOPE相当)
$SiteInitPath
$SitedefPath
(page 18)
時代によってperlらしくなくなった例
while(<>) { $WHOLE_MAIL .= $_;}
while ($p = sysread(STDIN, $_, 1024)) {
$bufsiz += $p;
if ($INCOMING_MAIL_SIZE_LIMIT &&
($bufsiz > $maxbufsiz)) {
...
}
}
- 簡単にメモリがとれる(短期開発ツール系の多くに共通)
- DOS (Denial of Service) Attack
- 暗黙の配列allocの可能性…
e.g. directory操作 => 境界値テスト
(page 19)
疑似構造体
関数間で一気に渡すための構造体
e.g. &Distribute(*Envelope);
fml (> 1.6) sendmail
$Envelope{'h:From:'} <=> e->e_from.q_paddr
h, mode, macro, message ...
* perl 4の頃に設計されたため疑似的
* ARRAYは滅多にないためあまり困らない
* ユーザは &DEFINE_FIELD_* を通して間接アクセス
(いじろうと思えばいじれるが)
(page 20)
Hashによる関数定義
Hashに関数定義テーブルを持つ。これはperl 4でも使えた。
ユーザが自由にオーバーロードできる。
fml全域に渡り同様の技法が数多く使われている。
@PermitProcedure
%LocalProcedure
@DenyProcedure
- fml default
%Procedure = ('help', 'ProcFileSendBack');
- config.ph
%LocalProcedure = ('help', 'MyhelpFunction');
- call
$fp = $Procedure{$proc};
$status = &$fp($_, *Fld, *e, *misc);
(page 21)
Hash and Chips
-- libfml.pl
if ($proc = $Procedure{$_}) {
$status = &$proc($_, *Fld, *e, *misc);
last GivenCommands if $status eq 'LAST';
next GivenCommands;
}
-- libfop.pl
for $proc (
'hdr',
'cnstr',
'retrieve',
'encode',
'split',
'encode_as',
'destr'
) {
$prog = $_fp{$proc, $mode};
&$prog(*conf, *r, *misc) if $prog;
}
(page 22)
main()
&CheckUGID;
chdir $DIR || die "Can't chdir to $DIR\n";
&InitConfig; # Load config.ph, initialize conf, date,...
&Parse; # Phase 1, pre-parsing here
&GetFieldsFromHeader; # Phase 2, extract fields
&FixHeaderFields(*Envelope); # Phase 3, fixing fields information
&CheckCurrentProc(*Envelope); # Phase 4, check the current proc
&Lock; # Lock!
if ($USE_LOG_MAIL) { &use('logmail'); &MailCacheDir;}
if (! &MailLoopP) {
&CacheMessageId(*Envelope);
&RunStartHooks; # run hooks
&ModeBifurcate(*Envelope); # 1. &Distribute
# 2. &Command
}
&Unlock; # UnLock!
&RunHooks; # run hooks after unlocking
&Notify() if $Envelope{'message'} || $Envelope{'error'};
&ExecNewProcess; # start new process execution (if defined)
exit 0; # the main ends.
(page 23)
プログラミング・スタイルのまとめ
- 一度決めたスタイルは守ろう
- 少々悪くても決めたことは守ろう
- プログラムは作者の思う以上に長生きするもの
- エレガントなコードはいけない
- 1年後に自分で読んでわからないコードはだめ
- 高度なコードはポータビリティが低い
(page 24)
ちょっとしたこと(1)
開発中のdebugコードは基本的に残す=> ... if $debug
- コメントは一杯残そう(=> ただしバランス感覚が大事)
注釈のメンテもわすれずに/注釈の付け過ぎにも注意
ポータビリティ
newsyslog(8)的バックアップ, RCS バックアップ
各MLは独立したもの
システムに複数のユーザのそれぞれの世界(MLだから)
(page 25)
コメントの割合
自分のコード 31.4 %
互換コード 34.9 %
libexec/ 32.6 %
人のコード 34.2 %
[参考]
/sys/kern 16.4 %
/sys/uvm 37.6 %
/sys/vm 29.2 %
(page 26)
ちょっとしたこと(2)
まとめおくりのcrontabの設定
教育あるのみ?
テンプレート作成支援/インストーラが頑張る?
(page 27)
fml told me (1)
ありふれたことが便利にできること
変数はtoggle?switch?決断は常に2,3手先を読む
$debugやswitch構文のdefaultなどを必ず書く
改良はアルゴリズムとデータ表現自体ということも
パラメータはこのくらいの範囲…
こんなことするやつはいないはありえない!いや必ずいる!
(page 28)
fml told me (2)
何もしない時おかしいことがおこらないように
MLなら0通、10万通テスト
小さいものに分割
perlよりCかも?
(page 29)
fml Project
cvs.fml.org などの運用形態はなし
ドキュメント部分などはやってもいいのかもしれない
基本的にメールで patch をもらうなど
僕が査読して当てる
1. スタイルはその時に修正される
2. 完全に独立保守されているもの
(僕はいじっていない)
e.g. libtraffic.pl, libmember_name.pl
(page 30)
Perl4と5のはざまで…
(page 31)
Perl4と5のはざまで…
fmlはperl4と5両方で動くようにしてある
perl5は5.003くらいになるまで静観していた
5.003になるはるか前に今のスタイルが確立し終っている
4で動くものをあえて5で書きなおす必要はない
運用面
開発面(としては面白くない?)
今まではそうだが、では新規分については?
互換性、ポータビリティ、壱からテスト?
Reference は使いたいかも…
(page 32)
Object
理念はよいが、のめりこみ過ぎる側面もありうる
世の中はぐちゃぐちゃなのを見つめよう
すべての理論は適用可能なパラメータレンジがある
常にバランス感覚を忘れないように
適材適所
# quick hack や perl poem もいいけれどね:)
perlというカテゴリにしばられる必要もない
e.g. libnntp.plはNNTP::Client(3)を使っている
すでにあったから
(page 33)
ポータビリティ
(page 34)
ポータビリティを上げるためには?
UNIX間ではperlが差を吸収しているのであまり苦労はない
config.guess(GNU automake)で推測, SYSV系はちょっと…
MTAの挙動,信頼性はOSによってかなりばらつきがある
インストーラーとドキュメントで吸収せざるをえない
既にあるものは使おう(しかし枯れてるものに絞るべき)
UNIXコマンドに依存しない e.g. 自力SMTP
UNIX以外へのportは教訓が得られる
fork, alarm, get*() 系。暗黙のUNIXの仮定
(page 35)
例: SocketInit
Socket 初期化コード
0. $STRUCT_SOCKADDRはインストーラが推測
1. eval("use Socket;");
2. eval("require 'sys/socket.ph';");
3. SYSV ? (config.guessによる判定) => &AF_INET
4. BSD or LAST RESORT => &AF_INET
* やりすぎか?
* perl自体のinstallをしくじっている場合も救える(こともある)
(page 36)
プロファイル
行数
メイン+ライブラリ 20456
インストール 6454
互換コード 583
人の書いたコード 2838
libexec/ 7379
bin/ 4714
sys/SOLARIS2/ 16
sys/WINDOWS_NT4/ 1194
UNIXの特別な機種向けはほとんどない。
NT用の特殊なコードは全体からみればごくわずか
ほとんどUNIX版をそのまま使っている
上の1000行の内訳はほとんどインストーラとPOP版のコード
(page 37)
Porting to NT
NT用の特殊コードは全部合わせて1000行程度
include版はほとんどなし
インストーラとPOP版で半々程度
fork, alarm, select 駆動の問題
fileパス名などで暗黙のうちにUNIXな前提をしている
get*() 系
(page 38)
まとめ
(page 39)
まとめ
スタイルを持とう。決めたら守り抜こう
バランス感覚と適材適所
短期開発可能な良さと弱点とを見つめること
perlらしさとperlらしさを避けることと…
わかりやすいコードを書こう
技巧に走っても効率はさしてかわらない
コメントはつける(付け過ぎても駄目)
アルゴリズムとデータ構造(〜ポータビリティ)
根本的な部分は言語によらない
走り疲れたら初心に戻ろう
インストーラ, 設定インターフェイス, ドキュメント
(page 40)
今後について
コードをきれいに(永遠のテーマ?)
ドキュメントの整理(永遠のテーマ?)
翻訳
系統的にまとまったものがあるべき
Operation, Design&Implementation は分離すべき
それ以外にFAQ?
インストーラ、設定ツールの改良, GUI?
日本語化?e.g. &Mesg(*e, buf, id, @argv)
ポーティング
cvs.fml.org ?
(page 41)
スタイルという点についての参考文献
The Elements of Programming Style
B.W. Kernighan and P.J. Plauger
(プログラミング書法, 木村 泉訳, 共立出版)
Software Tools
B.W. Kernighan and P.J. Plauger
(ソフトウエア作法, 木村 泉訳, 共立出版)
ポータビリティの高いソフトウエアのソースコード
(page 42)