「読みやすさ」を最適化する

ごちゃごちゃとしたコードは読みにくく、バグを発見しづらいものです。ふつう、コードというものは書くよりも読む回数の方が圧倒的に多いので、ごちゃごちゃとした部分を減らすことで「読みやすさ」を最適化しなければなりません。読みやすいコードほどバグを発見しやすく、機能を付け加えるのも簡単です。

コードを読みやすく保つには

この「読みやすさ」を実現するにはどうすればいいでしょうか? すぐ思い付くのは「シンプルにする」ということです。シンプルでないコードは読めません。たとえば、次のようなコードは読めません。

  • ひとつのメソッドが数十行に及ぶほど長い
  • 多重の if などの複雑な制御構造を使っている

したがって、コードベースを健全に保つには読みづらい部分を改善し続ける必要があります。

ここでいくつか問題があります。

  • 読みやすさというのはその日の気分や体調に影響されやすく、個人間でのばらつきも大きいものです。そこで、読みやすさを示す客観的な指標が必要です。
  • コード全体に目を通し読みにくい箇所をみつけるのはとても大変です。そこで、読みやすさの指標に基いて問題のある部分を発見してくれるツールが必須です。

flog ターゲット

Trema では「読みにくいコード」を機械的に検出する仕組みを提供しています。 flog という rake ターゲットは、ソースコード中の複雑なメソッドを flog 独自の指標を元に検出します。複雑度が高いメソッドほど点数が大きくなります。コマンド一発なので、コード全体にくまなく目を通す必要もなく一瞬で検出できます。

実行してみましょう。

$ rake flog
10.2: Trema::Process#initialize
10.3: Trema::Ofctl#flows
10.5: Trema#tmp
10.7: Trema::Link#real_eth
10.8: Trema::SwitchDaemon#options
10.9: Trema::DSL::Syntax#rswitch
10.9: Trema::DSL::Syntax#switch
10.9: Trema::DSL::Syntax#run
11.2: Trema::Daemon#daemon_id
11.4: Trema::Controller#daemonize!
11.6: Trema::DSL::Syntax#vhost
11.6: Trema#file
11.7: Trema::DSL::Parser#eval
11.7: Trema::DSL::Parser#parse
11.7: Trema::Command#dump
11.7: Trema::Command#trema_up
11.8: Trema::Ofctl#users_flows
11.9: SubProcess::Shell#handle_child_output
12.2: Trema::DSL::Configuration#initialize
12.3: Trema::Ofctl#add_flow
12.3: Trema::Executables#path
12.4: Trema::DSL::Syntax#vswitch
12.5: Trema::VendorAction#initialize
12.5: Trema::Phost#none
12.8: Trema::Shell#vhost
13.0: Trema::App#none
13.2: Trema::Command#shell
13.9: MonkeyPatch::Module::ClassMethod#define_class_method
14.1: SubProcess::Shell#exec
14.2: Trema::SendOutPort#initialize
14.4: Trema::Process#kill!
14.4: Trema::Switch::inherited
15.2: Trema::Shell#reset_stats
15.2: Trema::Daemon#log_file
16.2: Trema::IP#prefixlen
16.4: Trema::DSL::Runner#maybe_run_switches
16.4: Trema::Daemon#wait_until_up
16.6: Trema::StatsHelper#to_s
16.7: Trema::Daemon::included
17.7: Trema::Link#initialize
17.8: SubProcess::Process#initialize
18.2: Trema::Cli#send_packets
19.2: Trema::Controller#none
19.8: Trema::App#initialize
21.0: Trema::Executables#none
21.1: Trema::Enqueue#initialize
21.4: Trema::Daemon#run!
22.5: Trema::Shell#show_stats
23.3: Trema::Shell#vswitch
23.6: Trema::Daemon#pid_file
26.7: Trema::DSL::Runner#maybe_run_apps
27.4: Trema::Command#none
27.9: Trema::Flow::parse
30.6: Trema::Shell#link
30.8: Trema::Command#trema_run
38.1: Trema::Shell#run
40.5: Trema::Util#cleanup
40.8: Trema#none
45.7: Trema::Command#load_config
56.1: Trema::Cli#send_packets_options
59.8: Timers::TimerMethods#none
62.7: Trema::DSL::Parser#configure
66.0: Trema::Command#trema_send_packets
82.9: Trema::DSL::Runner#maybe_run_switch_manager
rake aborted!
64 methods have a flog complexity > 10

64 個のメソッドがひっかかってしまいました。Trema の flog の設定では複雑度が 10 以上のメソッドを検出します。この 10 という値はかなり厳しめなので多めのメソッドがひっかかってしまったようです。

複雑度を下げるには

メソッドの複雑度を下げるにはリファクタリングが有効です。大抵は、リファクタリングの中でもとくにオーソドックスなメソッドの抽出だけでメソッドを単純化できます。

もし、複雑なメソッドを単純化するパッチを作った人は Pull-Request をぜひおねがいします。こうしたリファクタリングのパッチは、機能的な面の変更が無いのでどこか出しづらい雰囲気があります。しかし、コードベースを改善するという意味ではとても貢献度の高いパッチです。

Tagged ,

Leave a Reply