blog.waterlow.work

Ruby, Rails, js, etc...

OKR本を読んだ

はじめに

OKR(オーケーアール) シリコンバレー式で大胆な目標を達成する方法

OKR(オーケーアール) シリコンバレー式で大胆な目標を達成する方法

OKRの本を会社から支給されました。大事なことは原典を読んでいただくのが良いですが、気になったところを書いてみます。

スタートアップでもミッションを掲げるべき

どんなに夢のあるようなビジネスでも、マネタイズしなければ意味がないというのが自分の考えでした。しかし「お金がほしいなら、ウォール街コンサルティング企業に入社するほうが遥かに安全だ。」という言葉をみてなるほどとおもいました。マネタイズは大事だけど、同じくらいミッションというか使命みたいなものが大事だと思います。

自信度の変化のトラック

今の会社でもOKRを取り入れていますが、自信度の変化をトラックしていません。はじめは50%でも自信度は刻々と変化していくため、OKRを振り返るためにも自信度の変化は重要であると考えました。

健康、健全性

これは、「利益に走りすぎて、エンゲージメントを失う」とか「締切を守るあまり、メンテナンス性の低いコードをリリースしてしまう」といった状況への抑止になると感じました。KRを達成さえすればそれでいいというような状況はなくなりそうです。

まとめ

OKRについて、まだまだ知らないことがあるなということと、これを遂行するにはメンバーのメンタリティも重要のように思いました。 あと、これとは別に「仕事はたのしいかね?」という本も読んでいてうーーーんという感じでした。

そもそもRailsでカスタム例外を定義すべき機会は少ない

はじめに

今仕事でRailsアプリケーションの運用をやっているのですが、いろいろなところで例外が定義されていて「これ必要なくね…」となんとなく思ったことが多々ありました。 しかし、effective rubyには「raiseにはただの文字列ではなくカスタム例外を渡そう」という章もあり、この違いはなんだろうと思いました。 なんでそう思ったのか整理して、今後自分のプログラミングに生かして行こうと思います。まとめると以下になります。

  • カスタム例外を自分でraiseしてrescueするな。戻り値で判断しろ。

よく見るコード

Resourceモデル

class Resource
  Error = Class.new(StandardError)
  def write
    # 何かの処理
    result = false # 何かの処理の結果falseだったと仮定
    raise Error, '保存時にエラーが発生しました。'
  end
end

Resourcesコントローラ

class ResourcesController < ApplicationController
  def create
    Resource.new.write
    redirect_to '/', flash: { notice: '作成されました' }
  rescue Resource::Error => e
    redirect_to '/', flash: { error: e.message }
  end
end

よく見るコードがあまり良くない理由

汎用性も可読性も低い。一般的でもないということですね…。

どうすればいいか

Resourceモデル

class Resource
  def write
    # 何かの処理
    false # 何かの処理の結果falseだったと仮定
  end
end

Resourcesコントローラ

class ResourcesController < ApplicationController
  def create
    if Resource.new.write
      redirect_to '/', flash: { notice: '作成されました' }
    else
      redirect_to '/', flash: { error: '作成されませんでした' }
    end
  end
end

カスタム例外は必要なくなりましたし、表示用のメッセージがモデルに縛られなくなりました。

結局カスタム例外は必要ないの?

必要ないとは言いませんが、単体のRailsアプリケーションを書いている場合、自分でraiseしようとしている例外はそもそもシステムエラーではなく業務エラー(日常的におこりうる)であることが多いように思いました。 もしそれがシステムエラーならば、rescueして握りつぶしては検知できないですし、そうなるとrescueしないんだからカスタム例外ではなくてもいいよねという話になると思い、最終的に独自例外いらないよねということになるんじゃないかなと思います。。。

gemなど不特定多数の人が使うものに関しては積極的に定義していくべきだと思います。gemから返ってくる例外がRuntimeErrorだとつらいですしね。

まとめ

やっぱりRailsでカスタム例外を定義すべき機会は少ないし、少なくとも自分はめったにやらないかなと思いました。

プロジェクトの立ち上げ時に入れてよかった/入れなくてもよかったgem

f:id:waterlow2013:20181109010853j:plain

はじめに

ここ最近趣味でrailsアプリを複数人で開発しています。
自分以外Railsは初心者 で、rails newしてgemを入れてDB初期設計やってはじめのコントローラ(API)をつくるまで位を自分でやったのですが、その後入れてよかった/入れなくてもよかったと思うgemがあり、多少は他の人や未来の自分にも役立つだろうということで書き留めます。

入れてよかった

onkcop(rubocop)

コーディングスタイルについて揉めたり、議論したりすることがなかった。
自分が設定して満足できた。

bootstrap

本デザインが当たっていないサンプルの状態でも、まあまあいい感じに見せられる。素のHTMLを見ることによるテンションの落ちがない。

gimei

後述するseed-fuでのサンプルデータ作成に役立った。

ridgepole

migrationファイルの記法がほとんど使えるため学習コストが低かった。ちょこちょこスキーマを修正するのにいちいちmigrationを作らなくてよかった。(古いmigrationファイルを直せばいいというのもあるけど、ほんの少し罪悪感がある。)

seed-fu

サンプルデータをはじめに整備しておくことで、いろいろイメージが付きやすかったり、たたき台にできたり。

shrine

本番ではS3を使うのだが、developmentではローカルにファイルを置くとか実装を切り替えれたのが便利。初めてつかったけど carrierwave をちゃんと使ったことがあればある程度は動かせた。 他の人を見ていると学習コストは高めだった。

capistrano-*

よくわからんままとりあえずgit pullでデプロイとかしなくてよかった。快適

入れなくても良かった

active_model_serializers

これを使いこなすためには きれいなAPI設計 がおそらく必要なのだけど、それがネックだった。 APIが汚いとserializerも汚くなる。 controllerでの手動よびだしとかするといまいち。 jbuilderや、素のhashを返すpure rubyのクラスを作って自前でas_jsonをしていくほうが、コスト低くある程度の規約ができてよかったかもしれない。

devise

自分が知っていたので立ち上がりは早かった。ただ、自分が入れてjwtなどの設定もしたので、自分が全部面倒見る感じになってしまった。 管理画面には積極的に使えばいいとおもう。

rspec

実際は「テスト各時間を取れなかった」という感じになる。作るものもよくわからないし、教える時間が満足に取れない状況ではどうしてもテストは後回しになってしまった。

まとめ

すべて学習コストとリターンのバランスかなという感じがしました!

Rails.cacheの落とし穴

はじめに

仕事で開発をしていた所、コードを動かしていてキャッシュされるべきところがキャッシュされないことがあったのでメモ。

結論

モデルをキャッシュする時、以下のようにしてもキャッシュされない。

@users = Rails.cache.fetch('user_all') do
  User.all
end

なぜか

ActiveRecord は評価を遅延させます。@users = User.allとしてもすぐにSQLが発行されることはなく@users.eachなど発行するクエリが決まった段階でクエリ発行されるわけです。

結論に書いたケースだとUser::ActiveRecord_Relationインスタンスがキャッシュに入り、インスタンスが評価された段階でSQLが発行されるため、結果としてキャッシュを使っても毎回SQLが発行されてしまうわけです。

どうればいいか

http://morizyun.github.io/blog/model-master-cache-rails-redis/index.html#Active-Record-Relation-to-a-1%E5%9B%9E%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%97%E3%81%A6-%E3%81%AE%E3%82%AD%E3%83%A3%E3%83%83%E3%82%B7%E3%83%A5

上記の記事を参考にさせていただきました。 以下の用にto_aを使ってクエリを即時発行すればOK。

@users = Rails.cache.fetch('user_all') do
  User.all.to_a
end

webpackerのサンプルをparcelでつかったらautoloadが効かなかった

はじめに

parcelを使っていて動かすコードとしてwebpackerのreactのサンプルを使っていました。

その中で、parcelにはdefaultでautoloadの機能が備わっているのにloadされないという状態が起こりました。

ここでは原因とその対処法について書いていきます。

問題のコード

https://github.com/rails/webpacker/blob/05062bd72a6e759d34ed3f4e05639dbd0f3b4ce4/lib/install/examples/react/hello_react.jsx

import React from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'

const Hello = props => (
  <div>Hello {props.name}!</div>
)

Hello.defaultProps = {
  name: 'David'
}

Hello.propTypes = {
  name: PropTypes.string
}

document.addEventListener('DOMContentLoaded', () => {
  ReactDOM.render(
    <Hello name="React" />,
    document.body.appendChild(document.createElement('div')),
  )
})

原因

以下のコードが問題でした。

document.addEventListener('DOMContentLoaded', () => {
  ReactDOM.render(
    <Hello name="React" />,
    document.body.appendChild(document.createElement('div')),
  )
})

autoloadはjsが再実行されるだけなので、addEventListenerで再度イベント登録しても、domがrenderされることはありません。

対処

まず、addEventListenerを使わずReactDOM.renderを即時実行するようにします。そうするとautoloadするたびにappendChildされるので、getElementByIdにして何個もdomが作られないようにします。html側にid要素をもつdivを一個作っておきました。

const mountNode = document.getElementById("app");
ReactDOM.render(<Hello name="React" />, mountNode);

jsのscriptタグがheadに書いてあったので、bodyの一番最後に変更してdivがある状態で読み込まれるようにもしました。

背景

Railsは基本scriptタグはheadに置くので、haedにおいても大丈夫なようにaddEventListenerを使った書き方になっているのだと思います。

まとめ

まだまだjsについては無知だなと感じました。

モチベーションを上げたい2〜猪子寿之の話に学ぶ〜

f:id:waterlow2013:20181109010843j:plain

猪子寿之の話

https://ja.wikipedia.org/wiki/%E7%8C%AA%E5%AD%90%E5%AF%BF%E4%B9%8B

かなり前の話になるのだが、テレビで以下のような話をしていた。

  • 仕事で海外に1人出張することが多く、いろいろとつらい
  • 海外で自分の食べたいものを食べられないのがとくにつらい
  • なので、どこでも食べられる目玉焼きを好きになることにした
  • 本当に好きになってたまに目玉焼きを家でも作る

モチベーションアップに置き換える

  • モチベーションの上がらない仕事を好きになる
  • 何かモチベーションアップにつながるルーティンを持っておく

まとめ

結局のところ自己暗示の話なのだが、好きなものを変えるというのはなかなかぶっ飛んでいて面白いと思った。

「Presentational and Container Components」を読んだメモ

はじめに

さいきんちょこちょこReactやReduxをやっているのですが、いつも読んだドキュメントのことを忘れてしまうのでちょこちょこまとめて行こうと思います。
今回はReduxの作者でもある@dan_abramov氏の書いた、Presentational and Container Componentsです。

Presentational and Container Components

  • コンポーネントをPresentationalとContainerに分けると、再利用がやりやすくなる。

presentational コンポーネントの特徴

  • 見た目に関すること
  • presentational/container コンポーネントのどちらも含む。
  • DOM markupを含む。
  • this.props.childrenによる封じ込めを許可する(?)
  • アプリケーションの他の機能に依存がない
  • データの扱いや操作は書かない
  • propsを通じてデータやcallback関数を受け取る
  • まれに自身のstateを含む(?)
  • stateへのアクセスや、lifecycle hook、パフォーマンスの問題がない限り(?)はfunctionalにかく
  • ex) Page, Sidebar, Story, UserInfo, List.

container コンポーネントの特徴

  • どう動くかに関すること
  • presentational/container コンポーネントのどちらも含む。
  • ラップするためのdivを除いて、DOM markupを含まない
  • dataや振る舞いを他のpresentational/containerコンポーネントに提供する。
  • Flux actionを呼んでpresentationalコンポーネントにcallback関数として提供する(?)
  • ステートフルで、データソースとして機能することが多い。
  • 手で書かない。React Reduxのconnect()を使う。
  • ex) UserPage, FollowersSidebar, StoryContainer, FollowedUserList.

このアプローチの利点

  • アプリケーションとUIをよく理解できる
  • 再利用性が上がる
  • デザインだけの微調整ができる
  • layout componentsだけを外出することができる。(?)

どちらのコンポーネントもemit DOM(?)を含まないこと

presentationalコンポーネントだけでアプリケーションを作ろうとするとpropsを渡す煩雑さに気づく。(?) propsを渡して歩くよりcontainerを使う方が良い場合がある。(?)

2つのコンポーネントの差はtechnical(?)なものではなく目的である。

宗教的に2つのコンポーネントを書き分けようとしないこと。 presentationかcontainerかわからなければ、あえて決めなくても良い。