scaffoldで生成されたようなコントローラーを書こう

流しのRails業でチームの中で共有したtipsをちょっとずつブログにも書いていくぞという。気持ち。
ちょっと初心者向けの話題のように思うかもしれないけれど、私もなんども苦しんだことなので。

$ rails g scaffold Book name:string price:integer

scaffoldでこのように生成したとしよう。
そうすると、BooksController#create は以下のように生成される。

# POST /books
# POST /books.json
def create
  @book = Book.new(book_params)

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

もう少し簡易化してみましょう。

# POST /books
def create
  @book = Book.new(book_params)

   if @book.save
     redirect_to @book, notice: 'Book was successfully created.'
   else
    render :new
  end
end

respond_toを排除し、HTMLしか返さないようにしてみました。
何の変哲も無いcreateアクションに見えるでしょうが、これがrailsのcreateの基本形です。全てのPOSTをこの形で書けるようにすべきです。

例えば、Serviceクラスを使う時はこうなっていると綺麗です。

def create
  if BookRegisterService.call(book_params)
    redirect_to :show, notice: 'Book was successfully created.'
  else
    render :new
  end
end

save modelのインターフェースを委譲されたmodelでデコレーターパターンを用いて実装すると、もっと元の形に近いままです。

def create
  @book = Manga.new(Book.new(book_params))
  if @book.save
    redirect_to @book, notice: 'Book was successfully created.'
  else
    render :new
  end
end

MangaはBookクラスから委譲されたインターフェースを持っています。

class Manga
  delegate_missing_to :@book
  def initialize(book)
    @book = book
  end
  def save
    # Manga固有のロジックをここに書く
    @book.save
  end
end

Formオブジェクトも似たような形にできます。

def create
  @book = BookForm.new(book_params)
  if @book.save
    redirect_to @book, notice: 'Book was successfully created.'
  else
    render :new
  end
end
class BookForm
  include ActiveModel::Model
  attr_accessor :name, :price
  def save
    if valid?
      # フォームが正しかった時の処理
      true
    else
      false
    end
  end
end

とりあえず、今日はここまでにしておきます。

DHHの記事のメモ

プロジェクト管理ツールBasecampの最高技術責任者、デイヴィッド・ハンソンさんの仕事術 | ライフハッカー[日本版]

iA writerを知ったのも、この記事だった。
自分のタスク管理のやり方を見直そうとなんとなく調べていたら、こんな記事を見つけた。
確か、以前にも読んだことがある内容だったんだけれど、iA writerもタスク管理の方法も試せていなかった

DHHという憧れの人物のタスク管理が響かないタイミングもあるんだな。本当に人生はタイミングですね。

記事で印象に残ったこと

私はほとんどのことにNoと言っています。そうすれば、自分で本気で選んだ少数のことにだけに、完全にコミットできます。
余計なことは人生から取り除けば時間はたっぷりあるはず。

明日はいくつかNoと言えるようにしたい。

メールのInboxを空にすることには執着しています。

僕はメールはほとんど見ないけれど、DHHのGTDの基本はメールになっているよう。
また、slackは本当に有害だと思うので、どうにかしたい。
あとはtwitterを読まないということも大事だよなぁ。フォローを減らすなりリストしか見ないなり情報を減らす必要がありそう。

一般的に私がトラッキングするのは、自分のコントロールが及ばないことに関してだけ

私の場合はomnifocusを整理する必要がある。
自分のタスクもかなりトラッキングしてしまっていて、この辺の使い方をマスターする必要がある。小さなチーム大きな仕事ではTodoListは11個までにしようっていってた気がする。
GTD的にいうとnext actionは11個までで良さそうだ。

DHHマニアとして

RailsやBasecampの記事をひたすら漁ってる自分としては、日本語で読める記事が意外なところにあって見落としていた。DHHリンク集を作ろうかな(笑

iA writer に感動しました。

iA writer というソフトを知ってますか??

このソフトはめっちゃいいです。このソフトが刺さる人は下記のランディングページの動画を見ただけで釘付けになって、とっさにダウンロードしてしまうはずです。

iA Writer: The Benchmark of Markdown Writing Apps

何がいいって、書けば書くほど集中できます。
これをweb上で体験させるのはそう簡単ではないよなと諦めの境地に行けるような気分になります。

これに近い書き味のものにDropbox Papperがあります。
ただ、やはりブラウザの限界といったところでしょうか、iA writerがうたっているfocusという部分に多少の不足を感じてしまいます。

iA writerがあれば文章を書くのが楽しくなる

iA writer上に文章を打ち込むのが本当に楽しい。
ずっと長い間文章を書いていたくなる。
個人的にomnifocusに出会った時の感覚に似ています。omnifocusもひたすらにタスクを分割したりタスクを入力したくなるツールです。(ただtodoアプリはそんなにたくさん入力してもいいことは少ないのだけれども)

これだけ文章を入力することが苦でなくなるというのは本当にありがたいです。
本当にいろいろな文章が書けそうです。

僕がフリーランスエンジニアとして感じる壁

転職活動をすることを表明しましたが、
今現在自分が壁と考えていることを書きます。

権限の壁

私の経験上AWSの管理者権限をフリーランスエンジニアとして、任されることは少ないです。
AWSのサービスをフル活用して貢献するためには、
AWSやインフラに精通し、社外だとしてもこの人間に権限を委譲した方が生産性が高いと認定された場合に限ります。

こういった権限はAWSだけではなく様々な重要な意思決定に絡んできます。

組織の壁

フリーランスのエンジニアが組織構造に対して助言することはあっても、
そこに対する意思決定までのプロセスが常に公開されていることは少ないです。
ある程度の規模の会社で経営経験があり、経営者に対してのアドバイスを求められる場合にのみ、
それらが委譲されるでしょう。

お金の壁

フリーランスはお客さんの事業へのお金の決裁権は通常は一切持ちません。
たまに予算を任せてくるような案件もありますが、その予算を承認するプロセスに立ち入ることはできません。
圧倒的な政治力があれば、権限の壁や組織の壁と同じく超えることは可能かもしれません。

壁はフリーランスのままでも超えられる

私は一般的にフリーランスに立ちはだかる壁を超えて来ました。
(リーダーは任せられない、マネジメントは任せられない、インフラは任せられないetc)

この三つの壁は越えられないものではありません。
自らの能力が高ければ、フリーランスのままでも突破することのできる壁です。

ただ、これらの壁を越えるには私の現在の能力では少し難しそうです。

私が壁を越えるために

正社員であれば、様々な制約がかかる代わりにこれらの壁を越えるためのサポートが得られると考えています。
そして、これらの壁を突破すれば、視座が高まり解決できる課題も増えると考えています。

私は一度会社にコミットして、この壁と向き合おうと考えました。
3つの壁を超えて、能力を上げて行きたいです。

意識低いrubocopの運用の仕方

rails 界隈では Sider の普及に伴い rubocop を業務で使っている方も増えてきたのではないでしょうか?
しかしながら、一度荒れ果てた荒野にrubocopを放っても成果はほとんど上がらないことでしょう。
必要なのは、すべてのコードを綺麗にするぞ!という高尚な志ではなく、現実を少し改善すれば、それでOKという意識低い気持ちな気がします。

--lint オプション

rubocopには -l または --lint というオプションがあるのをご存知でしょうか?
こいつはlintオプションと呼ばれるやつで、bugに繋がりやすい警告レベルを指摘してくれます。

こいつをまずデフォルトにしましょう。
.rubocop ファイルに --lint と記述すると、rubocopのコマンドが常に--lintオプションがついた状態で実行されるようになります。
.rubocop ファイルを使うことで、プロジェクトのメンバー全員がそのオプションをつけてrubocopを実行することができるため、「 rubocop -l と実行してください!」などと呼びかける必要がなく便利です。

rubocop_todo.yml と向き合う

次にこの状態で、rubocop_todo.yml を生成します。
rubocop --auto-gen-config

プロジェクトにこれ以上 --lint に違反するコードを入れないようにするためです。

rubocopを入れると、rubocop対応で色々と対応工数が増えてしまうと恐れている方もいらっしゃると思いますが、
この --lint オプションは宗教戦争的なものはほぼなく、バグに繋がる恐れがあるか?という観点での指摘です。

さて、auto-genされた rubocop_todo.yml には問題が山積です。
これらは指摘事項を修正していかなくてはなりません。

todoファイルと向き合いきれなかった場合

rubocop_todo.yml ではルールをファイルあたりで抑制してしまうため、
todoファイルを全部修正できない場合は、問題の箇所を特定してコメントアウトで警告を抑制する方法をとったほうが良いでしょう。
じゃないと、 rubocop_todo.yml に記載されたファイルは治安が悪化して行きます。

一日1cop修正

私のプロジェクトでは1日に一つだけ、これを実行していくことを行いました。
修正はコミットを細かく分けて、tmpブランチからcherry-pickをしてmasterにマージする量を調整する形をお勧めします。
(OSSである dev.to では一つのpull requestがマージされたら新しいpull requestを作るという方法をとりました。)

rubocop_todo.ymlを消すことができれば、これでとりあえずrubocop -lに適応した状態を作ることができたということです。

--lint 以外のオプションと向きあう

次の段階としてrubocop -lをやめて、rubocop.ymlを設定していくというステップがありますが、これは次回以降に。
まずは、--lintで怒られないくらいを目指すのはいかがでしょうか?