プログラミング 美徳の不幸

Ruby, Rails, JavaScriptなどのプログラミングまとめ、解説、備忘録。

カンマ入ったり全角入った数字(の文字列)を数値にしたいやつ

タイトルのやつ自体はrubyだとカンタンなんだけど、適当にこういうクラス作って

module Bacchus
  class IntegerFilter
    def initialize(num_string)
      @num_string = num_string
    end

    def convert
      unless @num_string.is_a?(String)
        return @num_string
      end

      @num_string = @num_string.tr("0-9",  "0-9").gsub(/,||/, '')
      n = @num_string.to_i
      if n == 0 && !['0', 0].include?(@num_string)
        @num_string
      else
        n
      end
    end
  end
end

数字っぽい文字列なら数値にして、それ以外はそのまま戻すコードを用意しておく。 (なんか汚いな、最近エレガントな興味書こうみたいな意欲が全くなくなった気がする...。'hoge'.to_iが0になるの、チェックの仕方これしかないのかな)

問題はウェブアプリケーションでこれをどこに置きますかっていう話。

クラウド家計簿サービスはこういうのとか、空文字列をnilに変換する処理をわりとRackなのかスーパークラスなのか、とにかく低層の共通処理においてしまったがためにわりと標準の仕組み的にうまくいかないことが増えて負債化してしまったらしい。

一見モデルのbefore_saveあたりに置けば良さそうだけど、Int型のItem#priceとかのカラムに文字列'12,345'を突っ込んだ時点でRailsが12にしちゃうのでそれはできない。

というわけでcontrollerで

  def hoge_params
    _params = params.require(:hoge).permit(*Hoge::ACCESSIBLE_ATTRIBUTES)
    [:price, :item_number].each do |attr|
      _params[attr] = Bacchus::IntegerFilter.new(_params[attr]).convert
    end

    _params
  end

が無難かなぁ・・・と思いつつこれが頻出するのは嫌だよね。 なんか良いやり方思いついたら教えて下さい。

簡潔かつセキュアなログインフォーム

ログインフォームは一般的に「メール」「パスワード」の組み合わせをSSLで送受信して適当にセッションを付与するのが基本なのだろうけど、以下のような問題点がある。

スマホ時代にパスワード入力は鬱陶しい

最大のポイント。一般論として英数字記号などが適度に含まれててある程度の長さを持っているパスワードのほうが安全だけど、スマホはキーボード切り替えが面倒なのでそんなパスワードを設定してもらうのを期待するのは厳しいのでは。

どうせ使い回すのでユーザのパスワードが他サービスから漏れたら不正アクセスされる

「ぱす」とかで入力候補に使い回しパスワードが出るようにしてる人もいるし、「他サービスから漏れたのが原因だからうちのサービスで被害が出たのはこっちの責任じゃない」というのは法的には成立しても親切ではない。

復旧手段が脆弱

パスワードを忘れた場合、メールアドレス宛に再発行URLを送るのが一般的実装だけど、メールは盗聴可能であるという前提を持つと再発行URLは脆弱。このあたりはいろんなサイトで判断が分かれてるところだけど、再発行URLからさらに秘密の質問的なものを踏ませないと安全ではない。それもどこまで効果があるか疑問。 だいいち秘密の質問にまともに回答してますか? 僕「test」とか適当に入れてるけど。

というわけで対抗策をいくつか考えてみた。

セッションを破棄せず一つのブラウザでしか使わせない

ログイン・ログアウトの概念をなくす。個人のスマホでサービスが使われるという前提があるならわりと安全だと思う。ブラウザをまたぎたい場合は最初に使ったブラウザからソーシャルアカウントと連携させる。

まぁソーシャル連携は案外敷居が高いので、クロスブラウザでは使えないサービスになるけど。

批判

セッションを破棄しないのは危険。なぜなら個人の端末で使われるとは限らないため。またシークレットモードとかの扱いも面倒(シークレットモードで使ってもらうと困るから)だし、そもそもクッキー消されたら一生ログインできなくなっちゃう。

SMS

メール・パスワードの組み合わせではなく電話番号・ワンタイムパスワードにする。 SMSって盗聴されるんですかね?(ちょっとよくわかってない) これならパスワードいらないし、別メール飛ばすよりもiPhoneだと上からぴょっと出るからけっこう楽だと思うけど。

批判

SMSが届く電話番号がないとサービスが使えない=PCのユーザビリティ低下+MVNOでSMS使えないケースもある。 またSMS実装はコストがかかる。

個人的にはこれLINEに送れるといいと思う。そのままLINEで問い合わせ対応できるようにとか・・・。ないのかな?

安全かつシンプルがいいとも限らない

ただ、最大の問題はユーザが電話番号ログインとかワンタイムパスワード慣れしてないので、いま「電話番号だけでログインできます」というサービスを作っても付いてこれない気がする。

ハナマサの神対応

最近引っ越したのだが以前の家にも今の家にも近所にハナマサ(花正)がある。 ハナマサは独り身には量が多かったり業務用のものが多いので少し不便な点もあるのだけど、安いので助かっている。

ただ、残念なことが一つあった。 引越前の店舗には「鶏ヤゲン軟骨」が置いてあったのだけど、今の近所の店舗には置いてないのだ。

http://www.ss-chicken.com/images/material/item_XXL/yagen01.jpg

これは鶏一羽から一欠しか取れない、貴重なわりに安い軟骨。調理法は極めて簡単でフライパンで適当に焼いて塩コショウをかけるだけでサイコーのつまみになるので前の店舗時代から相当量を買っていた。

しかし引越し先には存在しない。そこでダメ元でハナマサのHPから要望を出してみた。

いつも大変お世話になっております。 赤坂店の近所から池袋店の近所に引っ越したのですが、赤坂店で販売しており 大変好物だった鶏ヤゲン軟骨が池袋店で取り扱っておらず、非常に残念に思っております。 池袋店で鶏軟骨の販売を心待ちにしておりますので仕入れのご参考にしていただければと思います。

翌日すぐに返信が来た(返信いらなかったけど)。

平素は花正をご愛顧頂き誠に有難う御座います。メールを 拝見しました。ご不便をお掛けし申し訳御座いません。 赤坂店では解凍販売させて頂いておりますが池袋店では 冷凍販売をさせて頂いております。ご要望を池袋店に報告 した結果明日より解凍販売もさせて頂くとの報告を受けて おります。何卒御利用頂けます様お願い致します。

神対応ですね。ハナマサ。ちなみに僕は1年に1,2回くらい、どうしても食べたいものにはわりとこうやって直接問い合わせで要望出してるんですが、以前「光◯」というラーメン屋が醤油味を辞めた時に「どうしても醤油味が食べたいから復活してほしい」と送った時は何の反応もなかったです。ちなみに「光◯」は最近破産したらしいんですが、破産するからいちいち対応できないのか、はたまたその逆か、興味深いものです。

ドキュメントを書けば?

b.hatena.ne.jp


これ。当然私は「いいこと言ってるなぁ」派。

これに寄せられるいくつかのコメントについて。

新規サービスをテスト書かずに立ち上げた奴らが創業者利益でがっぽり勝ち逃げして後から入った真面目な若者が負債による圧迫で「こんな機能追加するのにこんなにかかるの?」みたいに詰められてる姿が目に浮かぶ

それはテストを書くかどうかの話より、技術的負債を積み上げ続けたまま勝ち逃げする人たちの批判ですかね。
テスト書いてあっても技術的負債が積み上がったプロジェクトだってあるし、テストはないけどプロジェクトのメンテナンスちゃんとしてるプロジェクトもあるし。
一般論としてテスト書いてる現場のほうがメンテナンスちゃんとしてる傾向にはあるだろうけど、直接の論点とは違うんじゃないですかね。

インフラとかライブラリ系はテスト書きまくっとくと安心感が凄い。簡単なテスト書いてるだけでも結構自分の思考の漏れが見つかる事多いしね。フロントはあんま関わらないからノーコメント。

そうそう、ライブラリは書いたほうがいいし書くべきなんですよ。読みづらいコードも増えるし。
でも、フロントはそんなにいらない。

テストを書くか書かないかは自由かもしれんけど動く事を保証するための動作確認をテストと言っているなら他人に説明するためのシナリオは必須だと思う


シナリオとは? TDDのシナリオですかね。私はシナリオとかスペックという概念(仕様とテスト実装、両方を表すようで両方ともと違う)は無駄な中間概念だと考えているので嫌いです。
普通にドキュメント書いて、あとminitest書けばと思う。

「よくできたRSpecはテスト自体が英語で仕様を表す」みたいなのって水素水とか、声がけで水の結晶が〜みたいなレベルのカルト思想だと思う。

共感してる人は元記事の矛盾に気づいてるのだろうか?"ユーザーに価値を届ける"事には"ユーザーの価値を壊さない"事も含まれる筈なのだが;多分これが許されるのって最初から完璧なコードが書けて修正不要な場合だけ

テストを書けば確かに価値を壊すリスクは減るとは思う。これはビジネス側の解釈なのでケースによるけど、壊すだけの価値がある時点でテスト書けばよい。たいていのスタートアップは誰も使わないとかのレベルで停滞してるわけで。


自称出来る人のドキュメントなしテストコードなしのソースを引き継いだ経験のある人はまったく賛同できないだろうな。それやるならお前が一人で開発して一人で墓まで持ってけよって。

そう、これなんだけど、「テストが書かれていてドキュメントがない」状況とその逆だったら、ドキュメントがあってテストがないほうが全然よくない? つまり、テスト書かなくてもドキュメントがちゃんと用意されてればこの問題はある程度緩和されると思う。実際、ここの仕様の意味がわからないというときにテスト読むって少し無理な注文だと思う。(少なくても教科書的に、「あぁこのメソッドはこういう振る舞いが期待されてるのか」と納得した経験はかなり少ない)

いいエンジニアはコメントを書かない、というかコメントにはBad Codeの臭いがあるのは確かにそうなのだけど、コメントを書かないにしてもドキュメントは書いたほうが良い。

例えば本番データを開発環境に投入するコマンドとか、キャッシュクリア、デプロイ手順(capistranoで自動化されてるにせよ普通にrollbackしようとしたら変なエラーが起きたりとかけっこうある)、ビジネスロジック上わかりづらいが重要な違いがあるメソッド(`Article.published`と`Article.visible`とか)。




ちなみに、昔自分がやったプロジェクトでRSpecでゴリゴリテスト書きまくってカバレッジも優秀なRailsアプリがあったのだけど、紆余曲折あって運営元が変わって、2年後くらいに見に行ったら一切実行されてないテストと「ドキュメントが一切ないクソプロジェクトなんですよ」という現場の声にショックを受けたので、今やドキュメント85, テスト15くらいの割合で考えてる。

2年連続でインフルエンザになる

確か去年はA型だったんですが、今年はB型になりました。節約のため高速バスで仙台に帰った翌日くらいから体調が悪くなったんで、バスの中で感染ったのだと思います。

しかし、今回のインフルエンザはけっこう辛かったです。去年ももちろん辛かったは辛かったんですが、高熱が出て翌日に病院に行ったらすぐにインフルエンザ陽性が出たのでイナビルという鼻から吸引するお薬をキメたら8時間くらいで回復したんですが、


tkot.hatenablog.com


今回のは熱が出て翌日に病院に行ったらインフルエンザ陰性。ただの風邪かと思いそのまま外で仕事してたらどんどん悪化したので2日後にまた病院に行ってようやく陽性反応が出ました。これは運が悪かったらしい。

で、今回はイナビルじゃなくて例のタミフル。これを5日間飲むらしいんですが、回復がけっこうゆっくりで未だ気持ち悪いんですよね・・・。

金曜 朝にバスから降りる(この時点で感染?)
土曜 なんともなし
日曜 38度くらい熱が出る
月曜 インフル陰性
火曜 仕事するも相当悪化
水曜 ずっと寝てる+夜間の救急病院に行ってインフル陽性
木曜 ずっと寝てる
金曜 だいたい寝てる

というわけでまだ指先の動きが悪かったり足元がふらついたりします。



これ去年も思ったんですが、病院代と薬代、電気毛布買ったりで軽く1万超えてるし仕事しなかった損害分も考慮したらけっこうな打撃なので、高速バス・新幹線って時間的なものだけでなく乗るにしても季節考えるとか重要ですね。

Rails初心者に知ってほしい本当の脱初心者の方法

qiita.com

この記事読みました。まぁ感想を一言で言えば

http://nplll.com/assets/2011/02/13_01.jpg

まぁ言いたいことを順を追って言っていきます。

ロジックで用いる具体的な数字は定数に格納する

これは半分正しいですが半分間違いです。マジックナンバー死すべしみたいな人が短絡的にあらゆる数値をそのクラスの定数にしちゃったりしてますが、程度問題です。

例えば

@articles = Article.where(...).page(params[:page]).per(PAGINATE_ITEM_LENGTH)

みたいなやつ。こういうの、結局ここでしか使わないから修正箇所1個だけなんですよね。だからベタ書きでもいいと思います。 定数にしたほうがいいやつってむしろこういうやつで

$li_margin_top : 50px;
ul {
  margin-top: -$li_margin_top;
}

li {
  margin-top: $li_margin_top:
}

まぁ変更する頻度が高い、どこかの数字と連動している、とか。

CRUDとルーティング

ある時期まではとりあえずresourcesが使えないか考えるべしというのは姿勢としてはいいのですが、現実問題としてわりと厳しいです。 例えばあるレストランの詳細ページの中に、地図を表示するページとかメニューを表示するページとかいろいろ作る時

resources :restaurants, only: %w[show] do
  resource :maps, only: %w[show]
  resource :menus, only: %w[index]
  resource :reviews, only: %w[index]
end

みたいな。まぁreviewsとかはいいんですけどmapみたいに明らかに1画面しか作らないなら

resources :restaurants, only: %w[show]
get 'restaurants/:id/map', as: :restaurant_map・・・①

resources :restaurants, only: %w[show] do
  get 'map' => 'restaurants#map', as: :restaurant_map・・・②
end

で十分ですよね。とくに①の方法は:idの部分を:nameとか:uuidとか変えられるのでオススメです。その際named_routesがそれっぽくなるようにちゃんとasオプションを付けましょう。

ちなみにshallowオプションは使うべきではない派です。

resources :restaurants, only: %w[show], shallow: true do
  resources :reviews, only: %w[show]
  #これでレストランのレビュー一覧ページはマッピングできるけど、ユーザのレビュー一覧は?
  # それならRestaurant#ReviewsControllerとUser#ReviewsControllerにしたほうが良くない?
end

まぁas, namespace, pathあたりのオプションをちゃんと使えば良い話です。

クラスを継承してsuperメソッドを使う...

まずDevise使うのやめましょう。 あと、iOS使ってるとsuper.viewDidLoad()とか出てくるけどRailsでこれが出てきたら使うライブラリが間違ってるか設計がおかしいかのどちらかだと思う。

クラスをまたぐ処理はconcernに

concerns使うシーンがピンとこなかったんですが、モデルからデコレータに変換するメソッドだけを含むモジュールとかをconcernsにするとけっこう便利です。あとはpublished_atだけでModel#draft?, Model#published?, Model.published, Model#publish!などを付け足してくれるモジュールとか。

ただ、たまたま共通してるレベルのものをconcernsにするのは危険かなと思います。

scope

昔保守した案件で @article.visible.user_authenticated.high_quolity.(以下略)みたいに定義して、結局Article.publishedが抜けてたみたいな事故があり、案外scope定義しまくるのはリスクがあるというか、scopeがそんなに大量になる時点で何かがおかしい気がします。 後はアプリケーションの画面に強く関係するビジネスロジックをscopeにすべきではないです。

Helperメソッド

ページ数によってtitleタグを動的にとる程度であれば

- if @article.current_page > 1
  title "記事一覧 #{@article.current_page} ページ"
- else
  title "記事一覧"

とかで十分。どうしても欲しいなら@articleのデコレータ。これをヘルパーにしてるとメソッド名が枯渇する。

考え方として、Railsが提供してくれるlink_toとかの亜種を作りたいときにはいいと思う。

  def noindex_nofollow_tag
    "<meta content='noindex,nofollow' name='robots' />".html_safe
  end

とか。

Test

minitest使ってるのはいいですね!

おわりに

いろんな現場、いろんなプロジェクト、規模やセキュリティの重要性、リリース後の動きとかによって書くべきコードは変わると思います。 私もまだまだ勉強中です。

批判あればご指摘ください

クロネコヤマトの経営学

2年ぶりに電車通勤生活になったことで、電車の中ではKindleで本を読むようになった。 で、この3日ほど読んでたのがこれ。

www.amazon.co.jp

クロネコヤマトヤマト運輸2代目社長の回顧録。著者は創業者で父親の会社に入社しながら2代目に就任し、70年代に大口顧客の三越を切って一般顧客を対象に切り替えていく。要するにB向けのビジネスモデルを縮小して、C向けの宅急便という新規事業に打って出た話。

2代目ながら東大経済学部卒で論理的。当時としては非常にビジョナリーで現代的な経営をしていたのが分かる。 ちなみに個人的には労働組合との関わり方について非常に細かく気配りしたような書き方があった点(現在のベンチャーではほとんど労組との関係性について悩むことはない)、当時の労組は業種的にも相当に影響力があったんだなという時代柄を感じる。 あとは国内航空会社の出来レース的な価格体系が海外格安航空にパイを奪われたという話を援用して敵は外にいると説いてるんだけど、今後はヤマト運輸の強敵が佐川急便からAmazonのドローンやGoogleの自動運転車、Uberになるのではと思うと全く聡明な見識だと驚かされる。

まぁさすがに本文中に「いくらなんでも荷物が空を飛ぶことはできないので〜」という描写があって、ドローン配達までは非現実だと思っていたみたいだけど。

Kindleで読めるのでおすすめです。

余談

最近はてブでゲーム作って会社ぶっ潰した24歳みたいな記事がバズったんですけど、ああいう感じで失敗起業家になぜ失敗したかインタビューしていく本とかあれば読みたいですね。