もの作りをする時の考え方

## はじめに
（プログラムで）何かを新しく作る時に僕が考えている事になります。
今回は`Rubyスクリプト`（[ソースはこちら](https://github.com/syou007/how_much_your_rails_app)）を例に出しますが、`Ruby`以外でも参考になると思います。

※本記事は[あなたのRailsアプリはいくら](http://qiita.com/syou007/items/b57baa8b759335503809)の解説編にもなってます。

## 作りたいものを考える
初めのステップとして必要な事は`何を作るか？`になります。
これは頑張って考えるというよりも、僕の場合は`突然作りたくなる`ケースがほとんどです。

## とりあえず作ってみる
作るものが決まったらとりあえず作ってみる事です。
プログラムの書き方が正しいかどうかは二の次で、どんな糞コードでも良いので作りましょう。

作ったものが形になった時には達成感を得られます。
また反省ができて、次のステップに進む事ができます。
うまく行けばサービスとして世の中に公開できます。

## ディレクトリ構成を考える
プログラム初心者の人は`とりあえず作ってみる`とやってみても失敗する事の方が多いです。
そもそもモノが出来上がらなかったり、最初の一歩でつまづいてしまう事もよくあります。
また作ったプログラムを改修しようとしても、どこを直せば直るかわからないような酷いコードになっている事も多いです。
ただし、それでも一度自分一人で`とりあえず作ってみる`を行うことによって見えなかったものが見えてくるようになります。
ここから先を読む前に一度`とりあえず作ってみる`を実践してみると良いでしょう。

今回僕が作った[プログラム](https://github.com/syou007/how_much_your_rails_app)を元に作る時に必要になる構成を考えてみます。
このプログラムは簡単にいうと以下のようなフローを進んでいきます。

1. [how_much.rb](https://github.com/syou007/how_much_your_rails_app/blob/master/how_much.rb)がトリガーとなって動き出します。
2. [dispatch.rb](https://github.com/syou007/how_much_your_rails_app/blob/master/controllers/dispatch.rb)がRailsプロジェクトからファイルを取り出します。
3. 取り出されたファイルを[program.rb](https://github.com/syou007/how_much_your_rails_app/blob/master/models/program.rb)が解析します。
4. [page.rb](https://github.com/syou007/how_much_your_rails_app/blob/master/views/page.rb)でHTMLを作成します。

このような一連の処理を行う上で重要となるのは、どこで何をさせるかです。

### フレームワークを学ぶ
フレームワークは使う時にも役に立ちますが、何かを作る時の参考としても役に立ちます。
構成を考えるときに`ゼロベース`で考えると新しいことを発見できる場合もありますが、大抵においては先人の知恵にはかないません。

そういった時には`先人の知恵`であるフレームワークを参考にすると良い構成を作りやすいです。

[今回のプログラム](https://github.com/syou007/how_much_your_rails_app)を見てもらうとわかると思いますが、基本的な構成は`Rails`を参考にしてます。
`app`などのディレクトリはないですが、`Rails`の構成をフラットにしていることがわかると思います。

このように分けておくことで、後々思ったよりも大きなプロジェクトに発展した時にある程度まで許容できるプログラムが出来上がります。

なので、まずは人が作った構成を真似てプログラムを配置するディレクトリ構造を考えましょう。
そして、間違ってても良いのでディレクトリ構成を先に作りましょう。

## 何が重要なプログラムになるか見極める
[あなたのRailsアプリはいくら](http://qiita.com/syou007/items/b57baa8b759335503809)を作る時、真っ先に浮かべたのは`Dispatch`のプログラムです。

このプログラムの性質上、ルートディレクトリから全てのディレクトリを舐めていく必要があります。
そのあとにファイル毎に金額を計算する必要があると思ったので、肝となるプログラムは[Dispatchクラス](https://github.com/syou007/how_much_your_rails_app/blob/master/controllers/dispatch.rb)になると思ったのでこのプログラムを軸に構成を組み立てました。

今回のプログラムは１日足らずで作成した小さなものでしたが、大きなプログラムを作る時にも考え方は同じです。
肝となる部分がどこかを見極める事はプログラムを作る上で重要なポイントになります。

### 重要な部分は計算部分ではないのか？
今回のプログラムでいうと[Programクラス](https://github.com/syou007/how_much_your_rails_app/blob/master/models/program.rb)が中核を担っているようにも見えますが、このプログラムは呼び出されるクラスであるため`dispatch`とインターフェースを合わせれればどんな形でも動きます。

なので、僕はRailsプロジェクトを舐めていく`dispatch`の方が重要であり`program`部分はなんとでもなると判断しました。
もし、`program`から作った場合は、具体的なインターフェース部分がぼやけた状態で作成するため完成までもう少し時間がかかったでしょう。
（できない事はなかったと思います。）

ただし、プログラムが大きくなればなるほど重要なプログラムは増えていきます。
今回のように簡単にはいかないと思いますが、初めの一歩としては小さなプログラムの中で重要となるプログラムを見極める力を培うのは重要な事です。

## ボトルネックを事前に調べておく
今回のような小さなプログラムではあまりボトルネックが見当たりませんでしたが、重要なプログラムを見極めるのと同様にボトルネックを見極める事も重要になります。

今回でいうと以下の部分がボトルネックになりそうだったので事前に軽く調べておきました。

### スクリプトの引数を受け取る方法
僕は`Ruby`といえば`Rails`でやってたので、スクリプトの引数を受け取る方法を知りませんでした。

```rb
ARGV[0]
```

`$0`でプログラム名も受け取れるようです。（`$1`で第一引数を受け取れるという記事も見たのですが、僕が確認した限りでは受け取れれませんでした。）

### ERBの使用可否
最後にHTMLを出力する際に`ヒアドキュメント`で実装するのは厳しいと思ったので、事前に使えるかどうかだけ確認しました。
結果、使える事が分かったので調査はそこで終わらせてあとは実装時に検証して作りました。

```rb
require 'erb'

erb = ERB.new(File.read(Erbファイル))
# bindingは変数ではなくメソッドです。
p erb.result(binding)
```

### requireに関して
Railsの場合は`オートロード`でファイルが読み込まれるので、自前で`require`を行うときは`Gem`を使う場合などだけでした。
なので、事前に「どのようにファイルを読み込めるのか？」と「実行パスが違っても実行できるのか？」を調べておく必要がありました。

また、ディレクトリ内部の`rb`ファイルをすべて読み込めるようにしておかないと`require`だらけになると思ったのでこちらも調べておきました。

#### 些細な疑問
`require`についてはRailsのプログラムが参考になったのですが、根深いところはわかってません。
その中で一つの疑問があります。

継承関係を持つクラスの場合は親クラスの方を先に`require`しておく必要があります。
しかし、`Rails`では親クラスを先に読み込む指定をしなくても実行時エラーは発生しません。
なぜなんでしょうね・・・？

### これらを事前に調べた理由
今回のプログラムは難しい事はなく、ボトルネックなど調べる必要はなかったのですが、、、１日で実装するつもりだったので、可能であるかどうかを知るために事前に調べておきました。

実際に現場でアーキテクチャーとして働く場合は`ボトルネック`を先に調べないと、最後の最後に悲劇が待っている場合もあります。
（最後に実現不可能な事に気付き、泥臭い方法で回避するような局面を迎えるでしょう。）

## 一連の処理を作成する
ここまで出来たら一連の成功処理を作成しましょう！
イレギュラーなパターンは後で肉付けをしても問題ありません。各ディレクトリに一つしかファイルがなくても構いませんので一連の処理を作成します。

僕の場合は[このような形](https://github.com/syou007/how_much_your_rails_app/commit/e69a928c79d3d82fac357e9fb814b10a30b796b3)で一連の処理となる部分を作りました。

**Railsプロジェクトを舐めて表示する**

ここまでをまず作り、ファーストコミットとしました。
後はパーサー部分を作成すれば良いという状況に持っていきます。

`Rails`アプリでいうなら紙芝居（画面遷移だけで、処理は行わない状態）を作ったタイミングに似てます。

## 主要処理を作成する
ここまで出来たら主要処理の部分のインターフェースを考えて実装するだけです。
僕は`Program`というクラスを作成して、このクラスを起点にサブクラスを作成することにしました。

このように起点となるクラスを作成すればインターフェースは自ずと決まってきます。
`Dispatch`から呼び出すクラスは`Program`のサブクラスなので、できる限り処理を`Program`クラスに記述します。

それによってサブクラスの負荷を下げるように設計します。（`継承`は開発者を楽にして、開発効率を上げた上に保守性も上げるという素晴らしい仕組みです。ぜひ活用していきましょう！）

[このような形](https://github.com/syou007/how_much_your_rails_app/commit/e94b5d648385f8ac89d16400ec1c347ba05b1dac)で主要処理が出来上がりました。

※[こんな](https://github.com/syou007/how_much_your_rails_app/commit/b7e643fa8c676791125518a6f7124fbb2821632b)バグも出してしまいましたが・・・。（恥

## 肉付けをしていく
最後は肉付けです。
初期の構想時点から値段をつけるファイルは`rb`以外にも`coffee`や`scss`などというファイルが存在していることはわかってました。

なので、それらの部分を[このよう](https://github.com/syou007/how_much_your_rails_app/commit/0e4da42fe4fd400d7957e2a1edd88219e7609a8c)に肉付けしていきます。

若干ダルい部分ですが、このようなプログラムを書くケースは往々にしてあると思います。

この時点で係数にもいろいろ試行錯誤したことがわかると思います。

## 命名に関して
・・・。すいません。
本来ならこの部分は重要になるのですが、小さいプログラムだったため結構手を抜いてしまいました・・・。
命名に関してはあまり参考にしないでください・・・

大きなプロジェクトでは、命名にはそれなりに時間をかける必要があります。
後で見た時にこのプログラムが何をしているかがわかる名前をつけておくと`肉付け`をする時や`改修`をする時に楽になります。

## ピックアップすべき技術
・・・という程のプルグラムは書いてないのですが、微細ながら書いておきます。

### 絶対パスの作成
自分のファイルを起点に絶対パスを取得することで、どこに配置されても動くコードができます。
ただし、自分自身の位置を移動させるとプログラムが動かなくなるのでご注意ください。

```rb
File.expand_path("../path", __FILE__)
```

`__FILE__`が自分自身の絶対パスを保持しています。
`../`としているのは自分自身のパスもディレクトリとして扱ってしまうためです。
`../`以下が自分自身のパスになります。

### ディレクトリ内部のファイルロード
指定パスの配下に存在するファイル全てを読み込む。

```rb
  def self.path(path)
    Dir[File.expand_path("../../#{path}", __FILE__) << '/*.rb'].each do |file|
      require file
    end
  end
```

### 再起ロジックとコールバック
`ruby`では`&***`と書いた引数はブロックを受け取れます。（`&block`の名称が一般的）
そのブロックを使ってコールバックを行ってます。

また`read_all_file`内で`read_all_file`を呼び出すことで、ディレクトリ内部のディレクトリを再帰的に探し出してます。
昨今では大した技術では無いのですが、昔はこの手の再起プログラムを書ける人は随分少なかったです。

```rb

  # 再帰的に全てのフォルダを読み込みます。
  def read_all_file(current_path = "", &block)
    # ディレクトリを読み込みます。
    Dir.foreach("#{@rails_path}/#{current_path}") do |file|
      # 不要なディレクトリはスキップ
      next if file == "." || file == ".."

      if FileTest::directory? "#{@rails_path}#{current_path}/#{file}"
        # 対象外のフォルダの場合はスキップする。
        next if AppConfig.get(:base, :ignore_dir).include?(file)

        # ディレクトリの場合は再起する。
        read_all_file("#{current_path}/#{file}") do |rails_path, file_name|
          # ファイルの場合はコールバックを呼び出す。
          block.call("#{rails_path}", file_name)
        end
      else
        # ファイルの場合はコールバックを呼び出す。
        block.call("#{current_path}", file)
      end
    end
  end
```

### クラスの返却
Rubyではクラスも含めて全てがオブジェクトです。
なので、以下のようにクラスを返却して取得した先でインスタンスを作成することができます。
今回のケースでは無理に使う必要はなかったのですが、覚えておくと役に立つ時があります。

```rb
def hoge
	return HogeClass
end

hoge.new
```

### インスタンス変数キャッシュ
以下のプログラムを見ることは多いと思います。

```rb
  def method_price
    @method_price ||= config(:method, :price)
  end
```

`@method_price`はここ以外では使ってません。
なんのために行っているかというと、初回呼び出しでは`@method_price`にデータを格納しますが２度目からは`@method_price`に格納された値を使うテクニックです。

今回のケースでは`yaml`の読み込みのキャッシュをしているのでほとんど効果は無いのですが、`Rails`を使う場合は`ActiveRecode`を扱う際に役に立ちます。
一度目は`SQL`を発行して、２度目からはキャッシュを使うことで高速化＆リソースの有効活用ができます。

### インスタンスメソッドの動的作成
このテクニックは今回初めて知ったのですが、各サブクラスで一部だけ変更して他の挙動は同じにしたい場合があると思います。
そういう時に以下のような事で動的にメソッドを作る事ができます。

```rb
  # 使用する設定ファイルの定義
  def self.config_file(symbol)
    define_method(:config_file) {
      @config ||= AppConfig.get(:program, symbol)
    }
  end
  config_file :base
```

このように記述してサブクラスで以下のように定義するとインスタンス化をする前にメソッドが作成されます。

```rb
config_file :ruby
```

`Rails`で有名なところだと`before_action`なんかがこの手法で作られてます。
インスタンス化した後に値を設定したり、メソッドをオーバーライドしても良かったのですが・・・そうすると管理が面倒になったり行数が増えるためこの方法を採用しました。

結構便利です。
`define_method`がミソです。

ちなみに`Rails`の`before_action`は以下のように定義されてます。

```rb
[:before, :after, :around].each do |callback|
        define_method "#{callback}_action" do |*names, &blk|
          _insert_callbacks(names, blk) do |name, options|
            set_callback(:process_action, callback, name, options)
          end
        end
        alias_method :"#{callback}_filter", :"#{callback}_action"

        define_method "prepend_#{callback}_action" do |*names, &blk|
          _insert_callbacks(names, blk) do |name, options|
            set_callback(:process_action, callback, name, options.merge(:prepend => true))
          end
        end
        alias_method :"prepend_#{callback}_filter", :"prepend_#{callback}_action"

        # Skip a before, after or around callback. See _insert_callbacks
        # for details on the allowed parameters.
        define_method "skip_#{callback}_action" do |*names|
          _insert_callbacks(names) do |name, options|
            skip_callback(:process_action, callback, name, options)
          end
        end
        alias_method :"skip_#{callback}_filter", :"skip_#{callback}_action"

        # *_action is the same as append_*_action
        alias_method :"append_#{callback}_action", :"#{callback}_action"
        alias_method :"append_#{callback}_filter", :"#{callback}_action"
      end
```

## まとめ
いかがだったでしょうか？
参考になったかどうかわかりませんが、指針もなくアプリを作るといろいろ迷走をするのでちょっとでもお役に立てればと思います。

## 作った感想
作ってみるとプログラム規模が小さくて楽しく作れました。
最後の`肉付け`は少々面倒でしたが、適当に設定してもそれなりの金額が出るので`まぁいいか`という感じで作ってみました。

僕が今作っている`Rails`アプリに適用したところそれなりの金額が算出されたので、やってみると面白いと思います。
複数のアプリに対して行うとプログラム規模が比較できるので、一つの指針になるのでは無いでしょうか？

## 余談
余談ですが、[あなたのRailsアプリはいくら](http://qiita.com/syou007/items/b57baa8b759335503809)は思い立った翌日に開発着手〜完了となりました。
上記の事を約５時間ほどかけて行い、作成に至りました。

## 筆者について
僕は[TownSoft](http://townsoft.jp)の屋号を掲げている個人事業主です。
お仕事お引き受けしますので、お気軽にご連絡ください。