Hush-up houndci-bot by morygonzalez · Pull Request #232 · lokka/lokka

Hush-up houndci-bot by morygonzalez · Pull Request #232 · lokka/lokka

Let @houndci-bot shut his big mouse up What I did Add Rubocop and HAML-Lint to Gemfile in order to check link locally. Add rules for Rub...

github.com

lokka/lokka 、 Pull Request を出す度に Hound CI のチェックが走って bot にコードレビューでぼこぼこにされるので、この bot を黙らせるべくガチャガチャやってた。 Hound CI のチェックルールは Rubocop に準拠しているようで、 2011 年からある Rack アプリを Rubocop のチェックにかけるのは面白かった。

Lokka 、意外と Hacky なコードが多く、条件式内での代入とか、ヨーダ記法とか、後置の until とか、スコープが広い一文字変数とか、めっちゃ長いメソッドとか、 if 文のネスト、代入したものの使われてない変数なんかを修正した。 method_missing はカスタムフィールドを定義できるという Lokka の仕様上根絶できなかったけど、 .rubocop.yml に最低限の除外ルールを追加して Rubocop のチェックはパスするようにできた。

Lokka 、 ORM が ActiveRecord じゃないことが問題だと思ってたけど、真の問題は lib/lokka/helpers/{helers,render_helper}.rb にビジネスロジックが詰め込まれてることだと思った。しかもこのあたりのコードの可読性がよくなく、触るのが怖い感じの複雑なやつが多い。この辺のコードをもうちょいクラス化して分割し、ユニットテストも手厚くしていかないと ORM を変えても F/E を今風にしてもウェブアプリケーションとして生存していくことは厳しいと思う。

前に進んでいくためにも Rubocop のチェックを入れる&パスさせるのはプラスになると思う。 頑張ってメンテしていくぞ。

追記

この辺のコードをもうちょいクラス化して分割し

と書いたけど、 Rails と違って手軽にサクッと作れるのが Sinatra の良い所なわけではあって、仕事で作る Rails アプリのノリでクラスやファイルを分割したりするのは違うのかもしれないと思った。 Rails で作られたオープソースの CMS やブログツールに長生きし続けるものがないのも、 Rails の場合、個人が偶発的に始めてメンテ出来るようなものになりにくいからかも知れない。

とはいえヘルパーがビジネスロジックを所持しているのはテスタビリティやメンテナビリティが良くないので Lokka と心中する覚悟でやっていくぞ!!!、!

BOSE QuietComfort 35

Google アシスタントに対応した後継機種( QC 35 II )が出たことで BOSE の QC 35 旧型が 1 万円近く安くなっていたのでクリスマス、誕生日、バレンタインデーの合算プレゼントとして嫁さんに買ってもらった。 SONY の MDR-1RBT が壊れてしまったのでその代替。

ノイズキャンセリングは思ったほど効かないと感じるが、音楽を聴くと周囲の音はほとんど聞こえなくなるので自分の HHKB の音が気になって仕事に集中できない、というようなことがなくなり思う存分キーボードをガチャガチャさせながら豪快にプログラミングできて便利。

音やノイズキャンセリング以外で優れていると思ったのがスイッチや充電用の microUSB 端子。 MDR-1RBT や通勤・ジョギング用に使ってる Anker のワイヤレスイヤフォンはスイッチが長押し式で、電源を入れたり切ったりが煩わしかった。 QC 35 はスライド式になっており、オン・オフの切り替えが直感的でわかりやすい。

BOSE QuietComfort 35

microUSB のメス端子に樹脂カバーが付いてないのも良い。充電するときにピローンとした蓋を外さないといけないのも小さくはあるがストレスだった。あんなもん付いてても意味ないし、充電必要なときにケーブルをぶっ刺すだけで充電できるのは非常に心地よい。スイッチにしろ端子のカバーの有無にしろ小さなことではあるが、地味にストレスになっていたことから解放されて嬉しい。

BOSE QuietComfort 35

高いものなので自分ではなかなか買えないが、買ってもらえてよかった。

🤩人気記事を表示するようにした - portal shit! で人気の記事を表示するようにしたけど、人気のエントリー(直近一ヶ月間でアクセス数が多い記事)に加えて、ホットエントリー(はてなブックマークでブックマーク数が多い記事)も表示するようにしてみた1ところ興味深い結果になった。

スクリーンショット 2018-02-08 10.09.53.png

短期的に膨大なアクセスを集める記事と長期的に安定したアクセスを集める記事は全く異なる。はてブのようなサービスで見つけられるのは前者で、後者のような記事を見つける場所が意外にネットにはないのではないかと思う。前者を動的な人気記事だとすれば、後者は静かな人気記事だと言えるだろう。こういう静かな人気記事だけを紹介するウェブサービスがあっても面白いのかもしれない。ちなみに人気のエントリーのリンク元は Google を除くとだいたいヤフー知恵袋か 2ch の過去ログが多い。


  1. このサイトの はてブの RSS を利用しています 

ツイッター歴10年を超え、どういうウプダテスをしたらファボをもらえるかはだいたい予想がつくようになってきたけど、それよりも前からやってるブログに関してはどうやったらバズるかがわからない。 mizch さんがブログを書く前にどのくらいブックマークが付くか想像できると言ってた気がする1けどそういうのすごいと思う。「もうちょい反応あるんじゃないかな」と思った記事が全然伸びなかったり、逆に完全に自己満足のために書いた記事がバズったこともある。ツイッターもブログも商売と同じで読み手に価値を提供することができたら良い反応があるものだと思う。ツイッターに関しては面白ツイートで読み手に価値を提供できている(自分が面白いと思うものが読み手にとっても面白いと評価されている)のだろうけど、ブログでは価値を提供できていない(少なくとも狙ってはやれていない)のだろう。

短文で面白おじさんを演じるのは簡単だけど、長文だととても難しくなる。自分で自分が書いた過去の記事を読んでも「滑ってるなぁ」という感じしかしない一方で、たとえば寿司について書いた記事はいま自分で読んでも「攻めてるなぁ」と感じる。また仕事で社内ブログに記事を投稿してもそこそこ反響得られてるので文章を書く能力が著しく低いわけではないのだと思う。

つまるところ自分はブログで記事を書くときに、自分の興味関心とオーディエンスの興味関心を一致させられていないのだろう。ツイッターや社内ブログでは読み手が誰であるかを把握するのが簡単なので事前にコンテキストを共有した上で記事を書ける。コンテキストが共有されているのでどんな内容が受けるかを想像しやすいのだ。しかしブログの場合は誰が読むかは見当がつかない。パソコン関係の記事が受けるのか、日記的な雑文が受けるのか、蓄財についての記事が受けるのか、あるいはそれ以外か、全く見当がつかない。

15年前にブログが流行ったとき、ブログはテーマを絞った方がいいというアドバイスをよく目にした。思えばそれは読者の種類を絞り、読み手とコンテキストを共有することで記事を書きやすくするためだったんだろうなぁと思う。

自分はなんでもブログに書くスタンスでやってきたので今更書く内容を絞ったりはしたくないんだけど、今年は読み手とのコンテキストの共有を意識してインターネットしていきたい。


  1. ブログを書き続けること - mizchi's blog読まれるテキストは読者へのおもてなしの構造を持っている - mizchi's blog あたりで書いてたような気がするけどそんなことなかった。ツイッターでの発言かもしれない。 これだった ブログで何を書くべきか - mizchi's blog 

Say Farewell to Fat Model.png

ルビーオンレイルザーの皆さん、 Fat モデル対策やってますか。 Fat モデル対策と言えば Concern ですね。 app/models/concerns/ ディレクトリに module を置いてモデルに include させるというアレです。

Put chubby models on a diet with concerns

Put chubby models on a diet with concerns

Different models in your Rails application will often share a set of cross-cutting concerns. In Basecamp, we have almost forty such conce...

signalvnoise.com

しかしただ module を作って Fat モデルのコードを移動し、元のモデル側に include させるだけでは結局モデルのインスタンスに生えるメソッドの数に変わりはないので臭いものに蓋をしてるだけになります。 Rubocop の Metrics/LineLength 警告を逃れるためだけの module 乱立はあんまり意味がないでしょう。間違って別の module で同名のメソッドを定義してしまい意図しない挙動になってしまうことも考えられます。

最近自分がやってるのは、 include される module に定義するメソッドはせいぜい一つか二つにして、このメソッドから別クラス( Plain Old Ruby Object)に定義したメソッドを呼び出す(委譲する)というものです。モデルに得体の知れないメソッドが増えないので便利。

例えば以下のようなモデルがあるとします。

  • app/models/entry.rb
  • app/models/comment.rb

両方ともレコードの新規登録があったときに通知を行いたい。共通の処理なので Notifiable モジュールを作ってそれを Entry モデルと Comment モデルでそれぞれ include しましょう。ここまでは皆さんよくやると思います。

  • app/models/concerns/notifiable.rb
module Notifiable
  private

  def notify
    # do something
  end
end
class Entry < ApplicationRecord
  include Notifiable
  has_many :comments
  after_commit :notify, on: :create
end
class Comment < ApplicationRecord
  include Notifiable
  belongs_to :entry
  after_commit :notify, on: :create
end

しかし Entry と Comment では通知内容が異なるので単純に #notify メソッドを callback で実行すればよいというわけではない。通知用パラメーターを生成する処理をモデルに書くとよいのですが、そういうのを繰り返した結果が Fat モデル地獄なので通知内容を生成するクラスを別に作ります。こんな感じ。

  • app/models/concerns/notifiable/entry_notification.rb
  • app/models/concerns/notifiable/comment_notification.rb

Base クラスを作って共通処理をまとめ、継承させると便利でしょう。

  • app/models/concerns/notifications/base_notification.rb
module Notifiable
  class BaseNotification
    def initialize(object)
      @object = object
    end

    def perform
      NotificationJob.perform(notification_params)
    end
  end
end
module Notifiable
  class EntryNotification < BaseNotification
    def notification_params
      {
        recipient_ids: @object.subscriber_ids,
        title: @object.title
      }
    end
  end
end
module Notifiable
  class CommentNotification < BaseNotification
    def notification_params
      {
        recipient_ids: @object.thread_joiner_ids,
        title: @object.body.truncate(25)
      }
    end
  end
end

Notifiable モジュールはこんな感じになります。

module Notifiable
  private

  def notifiy
    notification.perform
  end

  def notification
    "#{self.class}Notification".constantize.new(self)
  end
end

図にするとこんな感じ。

Rails Fat Model Strategy.png

この Notifiable モジュールを include しても Model には #notify メソッドと #notification メソッドしか追加されず、通知処理の実装をモデルから分離することができます。 Entry クラスも Comment クラスも #notify メソッドより先のことは何も気にしなくてよくなる。リソースが追加されたときに #notify メソッドを実行することだけに責任を持てばよいし、通知を飛ばすという処理自体は Notifiable::EntryNotificationNotifiable::CommentNotification クラスの責任になります。

私はこれで Fat モデルのコードを concerns ディレクトリにしまい込んで臭いものに蓋をするような対応におさらばしました。よろしければお試し下さい。またもし他に良い方法をご存じであれば教えて下さい。

去年の年末に Rails に大掃除も年賀状もやらずに Rails に Pull Request を出してた。

ActionMailer のプレビューで locale が複数ある場合に指定できるようにするというもの。 Kaizen Platform の Rails アプリにはこの機能付いてて多言語対応のメールをプレビューするときにめっちゃ便利だった。調べたところ Rails 4 時代にそういう Pull Request 出してた人がいて Merge 寸前まで行ってたんだけど commit が複数に分かれてたのを「 squash してくれない?」とレビューされたところでプルリク主の意欲が燃え尽きたっぽくて Merge されずにコンフリクトして死んでた。

Add locale selector to email preview by plus3x · Pull Request #19923 · rails/rails

Add locale selector to email preview by plus3x · Pull Request #19923 · rails/rails

@rafaelfranca Fix of #19922

github.com

Rails 5 でも動くようにコンフリクトを解消してテストケースも追加したのが以下。

Add locale selector to email preview by morygonzalez · Pull Request #31596 · rails/rails

Add locale selector to email preview by morygonzalez · Pull Request #31596 · rails/rails

Summary This Pull Request make it possible to select location on ActionMailer Preview. Just like below. This is a rework of #19923. #199...

github.com

動作イメージはこんな感じ。

34454066\-f8bf06ec\-eda5\-11e7\-82ba\-1c2a0961b6b8\.gif \(833×768\)

ただ Merge 後にバグってるのを指摘されていま直してるところです。

Fix locale_selector JS bug in ActionMailer Preview by morygonzalez · Pull Request #31750 · rails/rails

Fix locale_selector JS bug in ActionMailer Preview by morygonzalez · Pull Request #31750 · rails/rails

Summary Fix bug arise from the Pull Request #3159 . locale_select only appears in I18n.available_locales.count &gt; 1. So if users have...

github.com

頭良くないのでこういうしょぼい Pull Request でしか contribute できないけど自分にできる範囲で貢献していきたい。

追記 2018-01-24

問題を修正する Pull Request も Merge してもらったんで多分 Rails 5.2 にこの機能入ります

IMG_4551.jpg

嫁さんの Mac mini 2011 が危機的な状況を迎えていて、何か操作する度に常にレインボーサークルがくるくるしてしまい動作が非常に遅くなっていた。ディスクの空き容量が足りないこととメモリ不足が原因のようだった。このまま極限まで空き容量がなくなると OS の起動さえできなくなる恐れがあったので 960GB のSSD と 16GB のメモリを嫁さんに調達させて換装してみることにした。

購入時、 Mac mini 2011 はデフォルトのメモリは 4GB で拡張しても 8GB までということだったので Apple Store で 8GB に増設してもらったのだが、ネットで調査したところ実は 8GB 二枚差しで 16GB まで認識できるということがわかった。 8GB のメモリ 2 枚が 13000 円、 960GB の SSD が 30000 円ちょいで合計 43000 円程度費用がかかった。 SSD は SanDisk のものを、メモリは Komputerbay という聞いたことがないメーカーのものを利用した。

データ移行時に使うディスクケースと分解時に使うトルクスドライバーは以前使ったやつがあった。分解の手順は以下のサイトが詳細で非常に参考になった。

Mac mini(Mid 2011)のHDDをSSDに入れ換える

Mac mini(Mid 2011)のHDDをSSDに入れ換える

2018/1/22(追記):こちらの記事は内容が古くなってしまった(&分解手順がザックリだった)ので、各内容を新たな記事として作成し直しました。よって、こちらの記事ではなく以下の新しい記事をご覧ください。・Mac mini 2011/201

sekinesan.jp

なお Mac mini は外見は似ていても発売年によって中のレイアウトは違いがあるようなので参考にするサイトを探すときは交換対象と同じ年式かどうかを確認した方がよい

手順を以下にまとめる。

  1. ディスクケースに SSD を入れて Mac mini に USB 接続しフォーマット
  2. Mac mini の電源を落として +R しながら起動
  3. ディスクユーティリティで起動ディスク(交換前の HDD )の内容を外付けディスク(交換用の SSD )にコピー
    • 一晩かかる
  4. Mac mini を分解して SSD とメモリを交換
    • ほこりがいっぱいたまっているので掃除機で吸いながら分解する
    • トルクスドライバーは T6 と T8 の両方が必要
    • ロジックボードにつなげてあるコネクターの取り外し作業は思い切りが必要かつミスって壊すと Mac mini が不燃ゴミと化すので慎重さと大胆さが求められる
  5. 元通りに組み立てる
    • SSD はねじの出っ張り部分が元付いていた HDD と同じ穴に入るように取り付けないときちんと固定されない
    • 元に戻すときに SATA ケーブルとロジックボードのコネクターが外れてしまいやすい。きちんと取り付けられていないと Mac 起動時にフォルダー内にはてなマークが表示されて正しく動作しない。
      • ディスクコピーがちゃんとできていないのかと思って焦ったが再分解して確認したところコネクターが外れていた
  6. Mac を起動して動作確認
    • ブラウザーのクッキーはおろか開いていたウィンドウやタブまで完全に復元される
    • MS Office 系はライセンス認証が切れているのでライセンスキーの再入力が必要
      • Adobe ソフトを利用している場合はおそらくそちらも
  7. Terminal.app を開いて sudo trimforce enable を実行し TRIM を有効にする

MacBook Pro のディスク交換よりも難易度は高かったが何とかなった。開発用途に使わない Mac なら十数万出して最新式のに買い換えるよりも数万円出してハードドライブを SSD に変えたりメモリを増やしてあげるだけで快適に使い続けられると思う。 Mac mini が遅くなったなぁとお困りの方はお試し下さい。