console.log(‘blog’) | puts ‘blog’

JavascriptとかRubyとか

HamlとSassをよしなに変換してくれるGruntfileを書いた

HamlとSassを勉強しています。普通にHTMLとCSSで書けばいいものをなぜわざわざツールを覚える必要があるのか?と疑問で今までやってきませんでしたが、やってみると便利ですね。この手の技術は基本的に難しいことはなく、ひたすら書きまくって慣れるしかないです。

HamlやSassを書きまくっていると、どうしてもコマンドラインを打つ手間が面倒くさくなってきます。GruntとかGulpとか流行っているのが体感的に分かりました。今からだとGulpの方がいいのかもしれませんが、Watchされて手間が少なくなれば目的を満たせるので、情報量も多いGruntで自動化してみました。CoffeeScriptでGruntfileが書けたので「もうこれでいいじゃん!」ってな感じでGulpを試すモチベーションがあまり湧きませんでした。一応、CoffeeScriptのタスクやJavascriptのテストのタスクも追加してみました。HamlとSassに慣れたらCoffeeScriptでjQueryのコードをシンプル化してみようと思っております。

https://github.com/kanjihtmt/frontend

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
module.exports = (grunt) ->
  pkg = grunt.file.readJSON 'package.json'
  grunt.initConfig
    coffeelint:
      app:
        files:
          src: [
            'Gruntfile.coffee',
            'src/**/*.coffee',
            'test/**/*.coffee'
          ]
    simplemocha:
      all:
        src: ['test/**/*.coffee']
        options:
          ui: 'bdd'
    coffee:
      compile:
        files: [
           expand: true,
           cwd: 'src',
           src: '*.coffee',
           dest: 'js',
           ext: '.js'
        ]
    haml:
      dist:
        files: [
          expand: true,
          cwd: 'haml',
          src: '*.haml',
          dest: '.',
          ext: '.html'
        ]
    sass:
      dist:
        options:
          style: 'expanded'
        files: [
          expand: true,
          cwd: 'sass',
          src: ['*.scss'],
          dest: 'css',
          ext: '.css'
        ]
    watch:
      css:
        files: 'sass/*.scss'
        tasks: ['sass']
      haml:
        files: 'haml/*.haml'
        tasks: ['haml']
      scripts:
        files: [
          'src/**/*.coffee',
          'test/**/*.coffee',
        ]
        tasks: [
          'coffeelint',
          'coffee'
          'simplemocha'
        ]

  for t of pkg.devDependencies
    if t.substring(0, 6) is 'grunt-'
      grunt.loadNpmTasks t

  grunt.registerTask 'default', ['watch']

まだminifyや画像のリサイズなどのタスクは書いてません。Gruntfileはこれから徐々に育てていこうと思っております。(もしかしたらGulpに移行する気になるかもしれません) これを使って連休中は、レスポンシブデザインの学習のためSassとHamlを書きまくろうかと思ってます。

Railsのscaffoldで生成されたコードを1行1行説明する

Rails初心者です。頑張ってます。Ruby on Railsのscaffoldで生成されたコードを全て説明できるようになるようにと言われたので、説明してみます。

bundle exec rails g scaffold Entry title:string body:text

ファイル構成

scaffoldを実行すると以下のファイルが生成されます。その他に生成されるテストコードとかマイグレーションファイルは無視しています。

PROJECT_ROOT
 |- controllers
 |    |- entries_controller.rb
 |- helpers
 |    |- entries_helper.rb
 |- models
 |    |- entry.rb
 |- views
 |    |- _form.html.erb
 |    |- edit.html.erb
 |    |- index.html.erb
 |    |- index.json.jbuilder
 |    |- new.html.erb
 |    |- show.html.erb
 |    |- show.json.jbuilder

コントローラ

まずはコントローラからです。コントローラは空のクラスであるApplicationControllerを継承してます。コントローラの共通処理を定義するためにこのクラスは存在しています。ApplicationControllerは、さらにその親クラスであるActionController::Baseを継承しています。このコードはprotect_from_forgeryメソッドによりCSRF対策をデフォルトで有効にしています。

1
2
3
class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
end

Entryコントローラにはindex, show, new, edit, create, update, destroyアクションが定義されます。規約によりアクション、URL、HTTPメソッドの対応関係が決まっています。これはRestからの設計思想で以下のようになっています。

アクション URLパス HTTP METHOD
index /entries/ GET
show /entries/1 GET
new /entries/new GET
edit /entries/1/edit GET
create /entries POST
update /entries/1 PATCH
destroy /entries/1 DELETE

そしてこの仕組みを作っているのがルーティングになります。ブロック内でresourcesメソッドにシンボルを渡すことでRailsがRESTアクセスを許可します。exceptや、onlyなどのオプションでアクセスを制御することもできます。

1
2
3
Rails.application.routes.draw do
  resources :entries
end

通常はHTTPメソッド 'URLパス', 'コントローラ#アクション'の形式で定義していきますが、scaffoldが追記したルーティングはリソースベースのルーティングになります。これは以下のルーティング定義と同じになります。

1
2
3
4
5
6
7
8
9
Rails.application.routes.draw do
  get 'entries' => 'entries#index'
  get 'entries/:id' => 'entries#show'
  get 'entries/new' => 'entries#new'
  get 'entries/:id/edit' => 'entries#edit'
  post 'entries' => 'entries#create'
  patch 'entries/:id' => 'entries#update'
  delete 'entries/:id' => 'entries#delete'
end

ビューで使用されるルーティング名もここで定義されます。

URLパス ルーティング名
/entries :entries
/entries/1 :entry
/entries/new :new_entry
/entries/1/edit :edit_entry

あとコントローラのソースをざっと見て感じたことは、scaffoldで生成したコントローラのprivateメソッドは1つインデントを下げているのでコーディング規約的にはこれを覚えた方がいいかなと思います。

1
2
3
4
private
  def set_entry
    @entry = Entry.find(params[:id])
  end

beforeアクション

各アクションが実行される前に必ず処理されます。アクションで処理を共通化したい場合はここに書きます。これらはshow, edit, update, destroyアクションの前にset_entryというメソッドを実行するよう定義しています。

1
before_action :set_entry, only: [:show, :edit, :update, :destroy]

indexアクション

Entryモデルから全件取得し、@entriesというインスタンス変数に代入しているだけです。

1
2
3
index
  @entries = Entry.all
end

showアクション

メソッドを定義しているだけで処理内容がありませんが、before_actionが実行されるため処理内容がアクション内になくてもビューにEntryオブジェクトの値が渡ります。

newアクション

Entryモデルのインスタンスを生成して@entryインスタンス変数に渡しています。

editアクション

こちらもメソッドを定義しているだけで実装がありませんが、showアクションと同様、before_actionで処理を任せています。

createアクション

POSTされた値を受け取ってentry_paramsプライベートメソッドに処理をさせます。これは何をやっているかというとStrong Parameterという機能です。たとえばこのentitiesというテーブルにはtitleとbodyといったカラム以外に、created_atなどユーザには表示しないシステムの都合上のカラムなどもあります。不正なアクセスで改ざんされる危険性がありますので、titleとbodyのみを許可するようこのメソッドで処理しています。

1
2
3
def entry_params
  params.require(:entry).permit(:title, :body)
end

こうして許可されたパラメータだけが返ってくるので、そのパラメータを使ってEntryモデルを初期化します。respond_toメソッドのブロックでHTTPレスポンスの処理を行います。formatオブジェクトのhtmlメソッドにはHTMLを返すための処理を定義します、jsonメソッドはJSONを返すための処理を定義します。

問題無くエントリーが保存された場合は、HTMLを取得するためのアクセスならばリダイレクトします。JSONを取得するためのアクセスならばJSONを返します。保存に失敗した場合は、HTMLを取得するためのアクセスならばnewアクションに戻して再入力を施します。JSONを取得するためのアクセスならば、クライアントにJSONでエラー状態のJSONを返します。 saveメソッドは、if文の条件に使われているので成功したらtrue, 失敗したらfalseを返しますが、save!と破壊的メソッドにすれば失敗した場合は例外がraiseされます。

1
2
3
4
5
6
7
8
9
10
11
12
13
def create
  @entry = Entry.new(entry_params)

  respond_to do |format|
    if @entry.save
      format.html { redirect_to @entry, notice: 'Entry was successfully created.' }
      format.json { render :show, status: :created, location: @entry }
    else
      format.html { render :new }
      format.json { render json: @entry.errors, status: :unprocessable_entity }
    end
  end
end

updateアクション

モデルのupdateメソッドを呼ぶところとメッセージ以外、ほぼcreateアクションと同じです。

destroyアクション

モデルのdestroyメソッドを呼び出し、リダイレクトします。ここでredirect_toメソッドの引数でentries_urlというメソッドが呼び出されていますが、このようにルーティングで定義されたルーティング名である:entriesに_urlというサフィックスを付けたメソッドを呼び出すことで/entriesへのURLを生成してくれます。

1
2
3
4
5
6
7
def destroy
  @entry.destroy
  respond_to do |format|
    format.html { redirect_to entries_url, notice: 'Entry was successfully destroyed.' }
    format.json { head :no_content }
  end
end

モデル

モデルはバリデーションも定義してませんので2行だけです。これだけで多くの機能を使うことができます。

1
2
class Entry < ActiveRecord::Base
end

ビュー

ビューはRailsのデフォルトではERBが使われます。拡張子が.jbuilderはJSONのビューになりますが、ここでは取り扱わず、erbのみ説明します。

index.html.erb

重要なところは以下の箇所です。コントローラから渡されたエントリー一覧をeachメソッドで繰り返しています。モデルのプロパティを呼び出しながら値を表示します。link_toメソッドはビューのヘルパーメソッドで、第1引数にリンクの文字列、第2引数にURLパスを指定します。showやdestroyの場合はentryオブジェクトを渡すだけでURLパスにしてくれます。editやnewに関してはルーティング名に_pathをつけたヘルパーメソッドがURLパスを出力してくれます。

1
2
3
4
5
6
7
8
9
10
11
<% @entries.each do |entry| %>
  <tr>
    <td><%= entry.title %></td>
    <td><%= entry.body %></td>
    <td><%= link_to 'Show', entry_path %></td>
    <td><%= link_to 'Edit', edit_entry_path(entry) %></td>
    <td><%= link_to 'Destroy', entry, method: :delete, data: { confirm: 'Are you sure?' } %></td>
  </tr>
<% end %>

<%= link_to 'New Entry', new_entry_path %>

削除のlink_toはちょっと複雑です、第2引数にentryオブジェクトを渡すのはshowアクションへのリンクと同じですが、第3引数にハッシュを渡しています。method: :deleteと定義することでdata-method="delete"という属性を出力します。この指定をすることでRailsはリンクをGETではなくDELETEでアクセスします。data: { conform: 'Are you sure?' }と定義することでdata-confirm="Are you sure?"という属性を出力します。これにより削除のリンクをクリックするとconfirmダイアログが出力されます。

show.html.erb

このビューも重要なのは以下の箇所です。ルーティング名である:entries, :edit_entryに_pathをつけたヘルパーメソッドによりURLパスを指定しています。

1
2
<%= link_to 'Edit', edit_entry_path(@entry) %> |
<%= link_to 'Back', entries_path %>

new.html.erb

ビューでのrenderヘルパーメソッドは引数に文字列を指定すると、_指定した文字列.html.erbのファイルを読み込みます。フォームの内容は_form.html.erbに記述されています。

1
2
3
<%= render 'form' %>

<%= link_to 'Back', entries_path %>

edit.html.erb

new.html.erbとほぼ一緒です。

1
2
3
4
<%= render 'form' %>

<%= link_to 'Show', @entry %> |
<%= link_to 'Back', entries_path %>

_form.html.erb

フォームヘルパーにエントリーオブジェクトを渡してブロックでフォーム内容を定義していきます。最初にあるのはエラー処理になります。フォームを作成するには、フォームオブジェクトのヘルパーメソッドにモデルの属性をシンボルを渡していけばHTMLでフォームを出力します。フォームヘルパーはひとつずつ覚えていくしかないと思います。

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
<%= form_for(@entry) do |f| %>
  <% if @entry.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@entry.errors.count, "error") %> prohibited this entry from being saved:</h2>

      <ul>
      <% @entry.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :title %><br>
    <%= f.text_field :title %>
  </div>
  <div class="field">
    <%= f.label :body %><br>
    <%= f.text_area :body %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

まとめ

1行1行説明することで理解ができました。基本をやりなさいと言われた時、「それぐらい分かる」と思いがちで実際に素直にやらない場合もあるかもしれませんが、経験的にこの辺の基礎的なことは、もうバカみたいに実直にやった方がいいと思います。仕組みが分かったので、後はscaffoldを何度か写経したら完璧です。

「納品のない受託開発」でエンジニアがお客様に提供する価値

「納品」をなくせばうまくいくーソフトウェア業界の常識を変えビジネスモデル

僕は「納品をなくせばうまくいく」という「納品のない受託開発」の書籍が出版されてすぐに購入し、何度か繰り返し読んだのですが、毎回「これは面白いわ−!」と読む度に思えました。時間が経ち自分の腹に落ちてきた部分もありますので、今日は僕が思う「納品のない受託開発」で何が素晴らしいのか自分のなりの意見を書いてみたいと思います。

最初にお断りしておきますが、これはウォーターフォールやアジャイル開発をdisっている訳ではなく、あくまで「納品のない受託開発」の良さに注目しております。

「納品のない受託開発」が提供する価値とは「お客様が失敗でき、ビジネスを柔軟に軌道修正できること」だと僕は思います。

通常の受託開発には様々な問題があります。そして一般的な企業などでアジャイル開発なら上手くいくのではないか?とその新しいアプローチを導入したりします。なかなかアジャイル開発をうまく導入することさえ難しい問題ですが、仮にアジャイル開発をうまく導入できたとしてアジャイルなら全てが問題なく解決できるのか?それをうまくやれた時は理想的で素晴らしい開発になるのだろうか?と考えた場合、いくらか問題があることに気が付きます。

アジャイル開発は、イテレーションを小さく回しながらリスクを軽減します。そしてリスクが分かった時点で軌道修正します。アジャイルは基本的に仕様変更に柔軟に対応することがスタンスとしてありますが、仕様変更をいくらでも受けれるという訳ではないと思います。予算が決められているため、仕様変更は無い方が、あるとしてもできるだけ少ない方が良いはずです。いくら「Embrace Change(変化を抱擁する)」とアジャイル開発のマインドを持っていてもあまりにも仕様変更が多い場合は「お客さん、そろそろいい加減にして頂けないかと。。。」となるはずですし、ビジネス的にも赤字プロジェクトになっていきます。

またスタートアップなどで、まだ類似するものが世の中にないビジネスを立ち上げようとする機運がクラウドの影響もあり、多くなってきました。そしてビジネスの移り変わりも激しくなりました。昔は海外で流行ったものを数年後に日本で展開すれば成功したビジネスが今では出来ません。世界で段階的に発生するのではなく同時に発生するリアルタイムでスピードが早い時代にインターネットがしてしまいました。サービスを立ち上げるコストは10年前と比べるとかなり安くなっています。これまで大手でないとできなかったビジネスも個人で立ち上げることが可能になってきました。昔は金銭的な問題、地理的な問題があり、チャレンジしなかったもしくはできなかった人が今はインターネットの力を借りてチャレンジが可能です。このようなスタートアップでビジネスを立ち上げようとする数は、これからもまだまだ増えていくと思います。

このようなスタートアップの開発のサポートは、通常の受託開発では扱いきれなくなってきたと思われます。最初は外注で試して駄目だったから自社で開発者を雇って内製化して今があるといった会社も多く出てきました。しかしそのように内製化にシフトすることにより結果的に成功した企業はよいですが、外注が駄目だったから内製という移行フェーズで失敗する企業や、そもそも発注したシステム会社のリスクを取り過ぎて上積みされまくった見積り金額に驚き、予算が無く先に進めない経営者の方も多いと思います。

以上の「アジャイル開発の限界」、「ビジネスのスピードの早さ」、「時代の変化」などの理由から、これからのビジネスをサポートし、加速させるには、新しい開発のアプローチが必要になってきます。「納品のない受託開発」は社外CTOが出来ることだとよく言われます。開発をし、ビジネスをサポートするコンサルタントとも言われます。しかし、お客様のビジネスの成功は保証できませんし、あくまで決定するのは経営者です。経営者は事業をやろうと思った時点でアイデアがいくらかあるはずですし、ある程度の自信もあるはずです。ですが多くは失敗していきます。当然です。人間ですから。

これまでの受託開発は経営者の失敗を許さなかった開発方法だったと思います。僕はこれまでそのようなことを意識したことは一度もありませんでしたが「納品のない受託開発」が出てきたことによって初めてそれに気づかされました。受託開発とは要件定義をして仕様を確定して、ある程度の長い期間をかけて実装し、その仕様どうりに動くかどうかテストして開発が終わります。その後は細かい機能追加やシステムを安定稼働させるための運用フェーズに移ります。この運用フェーズを知らないまま、開発の一部のみ携わっただけの開発者も多くいますし、それは珍しいことではありません。このやり方だと最初に青写真を描いた経営者が「間違っていない」ことが前提条件になります。もし間違っていた場合はまたさらに多くの出費をし、思いどうりのシステムにするか、予算がなければ「使われないシステム」となってしまいます。私達プログラマでさえ組んでみないと分からないことが多くあります。にもかかわらず、経営者はシステム開発においては、段階的に試しながら軌道修正したりすることができません。よくよく考えれば非常に厳しい仕組みです。

「納品のない受託開発」はこの問題に風穴を空けました。アジャイル開発では開発者に変化を要求し「Embrace Change(変化を抱擁する)」をさせます。その主体はあくまで開発者です。「納品のない受託開発」では、そうではなく主体は経営者(とサポートするプログラマ)で、「ビジネスの主役である経営者に変化を抱擁させた」のではないかと思います。プログラマに求められるものは変化に対する柔軟性や失敗した時にお客様からの相談に答えられ、現状の適切な説明とアドバイスが出来ることです。成功するまで共に戦ってくれ、失敗が許される安心感を与えられることが僕は一番の価値だと思います。

「納品のない受託開発」が生み出したものは「ビジネスの変化を抱擁する」というパラダイムシフトになります。ですから仕様変更は当たり前ですし、仕様変更が必要な時は、問題があることが分かったということですから、今後の方向性を決定する材料にもなります。これまでの受託開発とは考え方がずいぶん変わってきます。この開発には色々な特徴、魅力、価値がありますが、既存の仕組み自体を変えてしまっていることが、僕が「納品のない受託開発」に惹きつけられる一番の魅力になります。

個人的にソニックガーデンはこれまで働いたことがないため、正確には分かりませんが、倉貫さんのやられている会社ということで外からはアジャイルをやっているのだと思われがちですが、実はソニックガーデンの内部ではアジャイル開発をやっている意識や実感がほとんどないのではないか?と想像しております。

倉貫さんからコメントを頂きましたので追記します。

これまでの受託開発は経営者の失敗を許さなかった開発方法

そうなんですよね。開発側は理解できなかったところかもしれないですけど、そうなんです。

ソニックガーデンの内部ではアジャイル開発をやっている意識や実感がほとんどないのではないか?

その通りです。社内でアジャイルなんて言ったことないです。

ということで、見当違いなことを書いた訳ではないことが分かってホッとしました。技術コミュニティにはアジャイルの亜種のように思われたりしますし、経営者の方には「ほんとうにこの本に書かれたとおりのことが出来るのだろうか?」と思われる方もいらっしゃるかもしれませんが、まずは書籍を読んで分からないことがあれば、直接ご本人にお聞きすればよいと思います。僕は「ビール片手に納品の無い受託開発を語る会」があり、そこで直接、倉貫さんにたくさん質問をしました。その都度、理路整然とした答えが返ってきました。不思議と論破されているような感じはなく、逆に清々かったです。

Infrastructure as Code

色々あってしばらく投稿できなく、いまさら感がありますが2/14の「オープンセミナー2015@広島」に参加しました。

普段から開発環境やサーバを構築するのにプロビジョニングツールやVagrant等を使っていましたので、僕よりも実践で活用されている方の経験を聞け、自分自身も考えが整理できました。去年はテスト駆動開発、今年は構成管理がテーマとして続き、ソフトウェア開発の現場でホットなことを毎年扱う良いイベントになってきたなと思いました。

広島でも最近、勉強会やコミュニティが活性化して来て、ますます面白くなっている感じがします。

僕も一応、懇親会のLTで発表をしました。

僕は新しい技術であれば何でも良いわけではなく、新しいパラダイムやアプローチで既存のやり方や仕組みを変えてしまうようなものが好きですし、そういった技術にすぐに反応してしまいます。「Infrastructure as Code」という考えはこれまでサーバを構築したり運用してきた人の暗黙知をコードとして落としこむことに意味があると思っております。脅威とかリスクはなにか?を考えるとある日突然、サーバ担当者が会社に来なくなるとか退社するという現実です。 そういった現実に対してプロビジョニングツールやServerspecといったツールを利用することで面倒なExcelを使った運用管理ドキュメントの保守(このドキュメント自体が保守されないですが)や面倒な引き継ぎ作業といったことが無くなると考え、これまでこれらの技術と向き合ってきました。そういったベースがあり自分の考えや知見をLTしてみました。

思った以上に反響があり、個人的にはServerspecの作者の方からコメントを頂けたのが何より嬉しかったです。自分が尊敬しているエンジニアの方からそういうのがあると励みにもなります。ありがとうございました。