ちょっきんで

ブログとか、長文を書かなくなって久しいのだけれど、 つい先日、ひさびさに書く機会があった。会社のブログで。

久々すぎて、書き始めるまでのトピック決めでものすごい時間がかかった、 あーでもない、こーでもないと悩んで、トータル2週間ぐらいトピック極めに使った。 書き始めると簡単なのだけど。

普段から、こまめに考えとかまとめる癖つけないと、 急にやるのは、けっこう大変だった。

ということでもう少し癖をつけていきたい。

Yahooオークションで詐欺にあった話

f:id:onody_onody:20160710115732j:plain

先日、Yahooオークションで詐欺にあった。
(正確には出品者として詐欺にあい、商品は発送したが入金がされなかった。)

自分としては、ちょう普通な手順でいつもどおりの手続きしていたつもりで、
それでこんな詐欺にあうなんて。。。という驚きがすごくあった。
(もちろん、あとであそこをこうしておけば。。。的なのはあったわけだけど。)

あと、いままでA◯way的な勧誘も、創◯学会的な勧誘も、 敏感に察知して、回避してきていて 「そういうものにはひっかからん!!」的な自信がかなりあったので 逆にすごいショックだった。

そして何より、一番驚いたのは
諦めかけたところで、まさかの犯人逮捕?っぽい連絡が。。

ミラクル。。

ということで、自分の反省もふまえ、順を追って書いていく。
(時系列でのまとめは最後に書いてます)

もくじ

出品から落札

就職を機に、個人事事業主のときにつかっていたMacbook Pro
もう必要ないかも、ということで16.5万円で出品した。
即決価格は18万円。

1週間の予定で出品していて、
開始早々から「出品者への質問」欄には英語のメッセージで、
「Hey! 興味あるんだけど、直接取引きしない!?即決価格以上だせるけど!」的な
メッセージがたくさんきたけど、
「なんかあやしいしー」ということで全般無視していた。

で、最終日に即決価格18万で落札があった。

配送の準備、大きな勘違い

Yahooオークションでは落札後にとる手順は大概↓で、
今回もその通りに進めていった。

  1. 送料の確認
  2. 落札者の支払い
  3. 入金の確認
  4. 配送先住所、連絡先の確認
  5. 配送手続き

ただ、このふつーの手順のなかで、
おかしさに気づかずスルーしてしまった点、
まぁいま考えると防げたよなー的な反省点が3つあった。

反省1. とにかく急いでる

落札者のK(小林という名乗る人物だったが実は偽名だったっぽい)から、
落札から30分もたたないうちに立て続けに連絡があった。

f:id:onody_onody:20160710113033p:plain

配送元、配送先ともに東京とはいえ、
次の日にとどくためには、
そうとう急いで手続きしないと間に合わない。

急いでいると冷静な判断を間違う。
逆に、急がされたら疑うべきだよね。

反省2. 支払い確認

これが一番の反省。

今回はYahooかんたん決済という、
Yahooのシステムを利用した。

これは、Yahooにあらかじめ登録している口座で、
個人情報をやり取りしない形で決済できるサービスだ。

で、そこから以下のメールが来た。

f:id:onody_onody:20160710113259p:plain

「支払い受付」
これを自分は勘違いして、
支払い完了と受け取ってしまい配送手続きを進めたのだが、
実際は支払いたいという意思が表示されただけで
Yahooのシステム上では決済がされていない状態なのだ。

後ほど、以下のメールを受け取った。

f:id:onody_onody:20160710113410p:plain

Yahooかんたん決済は、かんたん言ってるけど
かんたんなものには落とし穴があるんだぜ。
よく調べておこうぜ!ってことです。。はい。

反省3. 連絡先の確認

宅急便の配送手続きをする際に、
配送先の電話番号を書かなければいけないので、
落札者からの電話番号を入力しようとしたところ、
番号が1ケタ足りなかった。
たぶん意図的。

f:id:onody_onody:20160710113859p:plain

1桁たりなかったものの、
結局これあとでわかるのだけど、
まったくの嘘っぱち電話番号。
あとでかけたときには「現在使われておりません」だった。

このときにかけていれば、、
配送を止められたかも。

発覚、警察とのやりとり

配送して翌日、そろそろ届いているはずだよなーという時間なのに一向に連絡なし。

ちと怪しいと思い、電話をかけたところ「現在使われておりません」

焦りだす。。とてつもなくやな気分になる。。

とりあえず、最寄りの警察に連絡。
刑事さんと話したのだけど、
「今の話だけだと、相手が商品を受け取ったかも、入金も手違いだなどと言われればそれまでなので」
とのことだったので、
とりあえず、内容証明を送って
その結果をもって、被害届だす・今後の対応をきめようとのことだった。

ただ、内容証明を送ると、結果が来るまでに1週間以上かかるので、
その間ただ待つのは、犯人を逃すことにもなるのでと思い、
いろいろ宅配業者などに電話をして、
荷物が受け取られたかを聞いたりした。

情報は得られたけど、
結局そこからは犯人特定にはいたらなかった。

  • 指定先の住所に届ける前に、配達担当の携帯に電話があった
  • 電話で通話しながら建物(マンション)に入ってきた配達担当とはなし、直接商品をうけとった
  • 配達担当の人から電話があった携帯の番号を聞いた

気になる点1. 宅配業者

宅配業者が、配達する際に基本的には本人確認をとっていない。
それはそれで問題なのだけど、
その住所を直接尋ねずに、付近で受け渡しをするのは
少し不用心すぎないか?

被害届を提出

内容証明が戻ってきた。
「あて所に尋ねあたりません」とのこと。

最寄りの警察署に連絡すると、これで被害届出せるとのことだったので、
魚拓や、書類一式、あと時系列での報告書的なものをメモしておいたので、
それをもって警察で説明、被害届を出した。

警察の人からは、
こういうケースで犯人見つかるのは難しいとのことだった。
宅配業者から聞いた番号も、照会かけるけど、
非正規のレンタルとかかもしれないからそっからは
たどれないかもなーだって。

気になる点2. 警察庁 サイバー犯罪対策

実は同時並行でYahooから、アカウント乗っ取りの連絡が来ていた。

f:id:onody_onody:20160710114127p:plain

乗っ取りの場合、警視庁のサイバー犯罪対策が動く可能性があるとのことで、
警察署の人が連絡をとってくれた。

ただ、乗っ取りの場合は、
そのやりとりに使ったPCがないと捜査ができないとのこと。
(オークションのやりとりをしたPC自体、落札者に送ったPCだったので手元にない)

ちょっとまってくれ、
やりとりのログってYahooのサーバ上なので、
ローカルのPCは関係ないでしょ?、Yahooさんとやりとして捜査すべき
的な説明をしたけど担当刑事には通じず。

結局、警視庁 サイバー犯罪対策のほうが動くことにはならなかった。

犯人逮捕?

事件からは2ヶ月ぐらいたったとき、
見慣れない番号から携帯に電話が。

折り返すと、警察の電話番号なのだけど、
最寄りではなく神奈川県のとある警察署からだ。

話をきくと、なんでも別件で逮捕した犯人の押収品から、
おれのMacBook Proが出てきていて、どういう経緯でおれのを犯人が持ってるのかをしりたくて
電話したとのこと!

きったーーーーー

とおもう反面ふつふつと疑問が。。

気になる点3. 警察内の情報共有?

刑事さんが頑張ってくれて犯人を捕まえてくれたのはうれしいのだけど、
被害届を別の東京の警察署で出されているという情報が
神奈川の警察の人には届いていない、もしくは届く術はあったのに調べられていないという事実は
ちと残念ではあった。

犯人がMacbookを配送時の状態を維持してもっていたから、
記録からおれの連絡先をつきとめられたわけだけど、
Macbook単品で、シリアルナンバーだけしか手がかりがなかったら
おれまでたどり着かなかったのではないか??
(apple側がおれの情報を提供できるか、そこまで刑事さんが辿ってくれるかはもちろんあるけど)

携帯の番号とか、盗品のシリアルナンバーとか、
検索で出るデータベースとかないのかなー。

警察の人の対応はすばらしく丁寧で言うことはなかったのだけど、
それは結果論で情報共有はただ残念な気持ちになった。

ざっくり時系列での流れ

4/5 23:17 出品開始。
4/9 10:49 即決価格にて、落札。
10:58 住所連絡あり。
11:22 Yahooかんたん決済での支払い受付連絡あり。同時にメールで支払い受付連絡あり。
13:00 Yahooかんたん決済での支払いキャンセル連絡あり。
13:00頃 ↑のメールを見落とし、商品を翌日午前中指定で発送。
4/10 13:30頃 商品の受け取り連絡がないことをヤフオクにログインして確認。
13:50頃 最寄りの警察署に連絡。経緯について説明。
14:12頃 刑事科のAさんから折り返しの電話あり。現段階では被害とどげを出しても受理できない旨を伺った。 内容証明を送って、2週間程度待って、状況が変わらない場合に、再度被害届の相談をして欲しいとのこと。
14:15頃 ヤマト問い合わせセンターに連絡。問い合わせセンターから配達を担当していた、配達担当の連絡先をもらう。↓配達担当の話。Kに配達する際に、Kと思われる人物からから配達の問い合わせ連絡を携帯で受けていた。電話を受けながら住所にあったマンションの入り口付近でKと思われる人物に荷物を受け渡した。その際の携帯の番号を入手した。170cmくらいで中性的な人だったとのこと。
4/11 9:00頃 内容証明送付。
4/12 13:21 Yahooから連絡あり。落札者のYahoo! JAPAN IDを登録したと名乗るお客様から、該当のオークションは第三者に不正に入札されたものである旨のお申し出がございました。
13:42 刑事課Aさんに↑を連絡。受け渡しがあったとのことで防犯カメラ等を調べてみるので、こちらでは引き続き内容証明に関する連絡を待って欲しいとのこと。
4/15 午前中 内容証明が返送されてくる。「あてどころに尋ねあたりません。」
12:27 刑事課Aさんに↑を連絡するも、不在のため伝言を残す。
4/18 14:35 刑事課Aさんに連絡するも、Bさんへ本件を引き継いでいるので、遅くともBさんより今週中には連絡あるので待っていて欲しいとのこと。
4/22 20:00 最寄りの警察署で被害届を出して受理される。
6/20 昼くらい 他の警察署で、別件で逮捕した犯人がMacbookを持っているので、その経緯をしりたいと連絡があった。

まとめ

  • とにかく急がせるやつは気をつけろ!
  • 利用する決済システムを理解して、正確な入金確認をしろ!
  • 連絡先が不審な電話番号のときは、一度電話をかけろ!

  • 宅配業者さん、届け先の人の本人確認は必要じゃないですか?

  • 警察さん、組織内での情報共有たりてますか?

犯罪者は頭くるけど、ある程度はいる前提で守りを固めることが大事だし、失敗から学びシステムを強固にする姿勢こそ、エンジニアとして大切にしなくちゃなんないんだぜ!

Strengthfinderを受けてみた

https://www.gallupstrengthscenter.com/

今回はTop5のStrengthがわかる$15のプランを受けました。

結果

  1. Restorative 復元力/修復力
    • 問題があったときに、原因みつけて、解決するのが得意なひと
  2. Individualization
    • 個性を発揮させる力
      • 人の得意/不得意を見極めて、チームの中で配置をするのが得意なひと
    • 自己中的な話かとおもったら違った
  3. Input
    • 興味範囲が広く、調べるのが得意なひと
  4. Learner
    • ↑とほぼ一緒。現状に満足せず、いろいろ調べるという上昇志向的な意味もあるみたい。
  5. Intellection 思考、概念、観念
    • 考え事が好きで、人の思考に興味がある。自分だけでなく他人の思考にも興味あって、多角的に考えるのが好き

感想

  • 1つの問いあたり20秒。質問を読んだ後に、ぱっと直感で答えて20秒きっかりだったので、結構考えられた時間設定だなと思った。
  • 質問が抽象的なので、そもそも考え込んだら負けみたいなところもある。(人生は幸福に満ちているか?とかそんなん多い)
  • 意外性はなかったけど、改めて言われたので、自覚が出た。
    • 面接とかでこういうの聞かれることが多いから、面接前とかに受けるといいかもね。30分くらいですぐおわるし。
  • Top5だけだけど、それぞれの説明のドキュメントは結構ボリュームあるし、内容しっかりなので、値段にないしては満足です。

新しい会社に入って1カ月の人の、適当な感想

f:id:onody_onody:20160403144931j:plain

広告配信プラットフォームの会社の開発部門に入って
一カ月が過ぎたので、この一カ月で思ったことを適当に書いてみる。

  • 思ったより広告配信は複雑

    • 普段目にすることがないので、イメージがわき辛い
      • なんか広告が妙に行動を見られていて気持ち悪いなーくらいにしか思っていなかった
    • 複雑が故に、割と省略した単語を、コンテキストで理解しわけている感
      • DSPSSP、アドネットワーク、DMPなど横文字イパーイ
    • ステークホルダー多め、業界力関係とか?

      • SSPとの接続で、ここは強く言えばいいけど、ここは引くべきなど
      • 業界ならではの力関係があるっぽい感
    • 時間かけて理解したいと同時に、人てきに今後会社がスケールするには、
      やっぱりここのハードル下げとかなー とは思う

  • データ量が多いので、ぬるい設計でやっていると死ぬ

    • 広告系はデータ量が死ぬほど多い。月1700億インプレッションとか、そんなレベルのデータ量。
    • ギガ、テラ系のデータを扱うのは日常で、下手するとペタ。
    • 局所てきに、すごい速さも求められるところある(RTBの100msでレスポンスのやつ)

    • エンジニアが泣いて喜ぶミッション、
      大量データをいかに効率的に高速にさばくかってことが
      ビジネス的にもプラスになる いいエコシステムがある気が。
      当然、よりコンピュータのコアの処理とか実装をおう必要があるので
      優秀なエンジニアも揃っている感じ

  • 受託の時の、今日やらないとやばい感、緊張感が減ってきた

    • 受託マインドだと見積もりスケジュールありきで、それに対する開発、着地は必須
      終わらないどうしよう →ちからわざ(じかんかける、技術的にだまくらかして逃げる、泣き落とし)

    • 今は他部署から要望や、システムてきなボトルネックをエンジニアが見つけたりしたものを、
      MTGで優先順位をつけてそれぞれ着手てきな感じ

    • よくわからん、本質的でない解決をしたりする時間は減ったので良かった

  • なんでこんな儲かっているかが謎感

    • これは、まだお金を生む構造がわかりきってないからだと思うけど

railsを起動するとgemはどのように読み込まれてんのか

railsを起動するとgemはどのように読み込まれてんのか

rails new new_application

をした後、

bundle install

のようにrailsアプリを動かすのに必要なgemをインストールするわけだけど、 インストールした後、

rails server

で起動した後にどのように gemをインストールされるかを追ってみる。

1. bin/rails

railsコマンドが実行されると、config/applicationが呼ばれる。

#!/usr/bin/env ruby
APP_PATH = File.expand_path('../../config/application', __FILE__)
require_relative '../config/boot'
require 'rails/commands'

2. config/application

一行目で、config/bootが呼ばれる。 そのあとにBundler.requireが呼ばれている。

require File.expand_path('../boot', __FILE__)

require 'rails/all'

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)
・・・省略

3. config/boot

config/bootでは主にbundler/setupを呼んでいる。

ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)

require 'bundler/setup' # Set up gems listed in the Gemfile.

4. bundler-1.11.2/lib/bundler/setup.rb

Gemfileの確認を行い、OKならBundler.setupを実行。

if Bundler::SharedHelpers.in_bundle?
  require "bundler"

  if STDOUT.tty? || ENV["BUNDLER_FORCE_TTY"]
    begin
      Bundler.setup
    rescue Bundler::BundlerError => e
      puts "\e[31m#{e.message}\e[0m"
      puts e.backtrace.join("\n") if ENV["DEBUG"]
      if e.is_a?(Bundler::GemNotFound)
        puts "\e[33mRun `bundle install` to install missing gems.\e[0m"
      end
      exit e.status_code
    end
  else
    Bundler.setup
  end

  # Add bundler to the load path after disabling system gems
  bundler_lib = File.expand_path("../..", __FILE__)
  $LOAD_PATH.unshift(bundler_lib) unless $LOAD_PATH.include?(bundler_lib)

  Bundler.ui = nil
end

5. bundler-1.11.2/lib/bundler.rb

load.setupを実行。

    def setup(*groups)
      # Just return if all groups are already loaded
      return @setup if defined?(@setup)

      definition.validate_ruby!

      if groups.empty?
        # Load all groups, but only once
        @setup = load.setup
      else
        load.setup(*groups)
      end
    end

load = Runtimeインスタンスですね。

    def load
      @load ||= Runtime.new(root, definition)
    end

6. bundler-1.11.2/lib/bundler/runtime.rb

specってのが、GemfileやGemfile.lockをパースしてオブジェクトにした
各gemの情報(依存関係も含む)になってる。
例えば、railsが依存しているsdocはjsonとrdocに依存しているけれど、 jsonやrdocまで$LOAD_PATHが通る感じ。

    sdoc (0.4.1)
      json (~> 1.7, >= 1.7.7)
      rdoc (~> 4.0)
    def setup(*groups)
      groups.map!(&:to_sym)

      # Has to happen first
      clean_load_path

      specs = groups.any? ? @definition.specs_for(groups) : requested_specs

      setup_environment
      Bundler.rubygems.replace_entrypoints(specs)

      # Activate the specs
      specs.each do |spec|
        unless spec.loaded_from
          raise GemNotFound, "#{spec.full_name} is missing. Run `bundle` to get it."
        end

        if (activated_spec = Bundler.rubygems.loaded_specs(spec.name)) && activated_spec.version != spec.version
          e = Gem::LoadError.new "You have already activated #{activated_spec.name} #{activated_spec.version}, " \
                                 "but your Gemfile requires #{spec.name} #{spec.version}. Prepending " \
                                 "`bundle exec` to your command may solve this."
          e.name = spec.name
          if e.respond_to?(:requirement=)
            e.requirement = Gem::Requirement.new(spec.version.to_s)
          else
            e.version_requirement = Gem::Requirement.new(spec.version.to_s)
          end
          raise e
        end

        Bundler.rubygems.mark_loaded(spec)
        load_paths = spec.load_paths.reject {|path| $LOAD_PATH.include?(path) }
        $LOAD_PATH.unshift(*load_paths)
      end

      setup_manpath

      lock(:preserve_bundled_with => true)

      self
    end

一応、require 'bundler/setup'が、ちゃんと$LOAD_PATHに変化を与えているかを検証してみた。

irb(main):002:0> $LOAD_PATH
=> ["/Users/onody/.rbenv/rbenv.d/exec/gem-rehash", "/Users/onody/.rbenv/versions/2.2.2/lib/ruby/site_ruby/2.2.0", "/Users/onody/.rbenv/versions/2.2.2/lib/ruby/site_ruby/2.2.0/x86_64-darwin15", "/Users/onody/.rbenv/versions/2.2.2/lib/ruby/site_ruby", "/Users/onody/.rbenv/versions/2.2.2/lib/ruby/vendor_ruby/2.2.0", "/Users/onody/.rbenv/versions/2.2.2/lib/ruby/vendor_ruby/2.2.0/x86_64-darwin15", "/Users/onody/.rbenv/versions/2.2.2/lib/ruby/vendor_ruby", "/Users/onody/.rbenv/versions/2.2.2/lib/ruby/2.2.0", "/Users/onody/.rbenv/versions/2.2.2/lib/ruby/2.2.0/x86_64-darwin15"]
irb(main):003:0> require 'bundler/setup'
=> true
irb(main):004:0> $LOAD_PATH
=> ["/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/web-console-2.3.0/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/uglifier-2.7.2/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/turbolinks-2.5.3/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/spring-1.6.4/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/sdoc-0.4.1/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/sass-rails-5.0.4/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/tilt-2.0.2/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/sass-3.4.21/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/rdoc-4.2.2/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/rails-4.2.5.2/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/sprockets-rails-3.0.4/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/sprockets-3.5.2/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/extensions/x86_64-darwin-15/2.2.0-static/mysql2-0.4.3", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/mysql2-0.4.3/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/jquery-rails-4.1.0/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/jbuilder-2.4.1/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/multi_json-1.11.2/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/concurrent-ruby-1.0.1/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/coffee-rails-4.1.1/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/railties-4.2.5.2/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/thor-0.19.1/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/coffee-script-2.4.1/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/execjs-2.6.0/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/coffee-script-source-1.10.0/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/extensions/x86_64-darwin-15/2.2.0-static/byebug-8.2.2", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/byebug-8.2.2/lib", "/Users/onody/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/bundler-1.11.2/lib/gems/bundler-1.11.2/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/extensions/x86_64-darwin-15/2.2.0-static/binding_of_caller-0.7.2", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/binding_of_caller-0.7.2/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/extensions/x86_64-darwin-15/2.2.0-static/debug_inspector-0.0.2", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/debug_inspector-0.0.2/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/bundler/gems/acts_as_bits-26fc7abed0af/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/activerecord-4.2.5.2/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/arel-6.0.3/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/activemodel-4.2.5.2/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/actionmailer-4.2.5.2/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/mail-2.6.3/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/mime-types-2.99.1/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/activejob-4.2.5.2/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/globalid-0.3.6/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.5.2/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/rack-test-0.6.3/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/rack-1.6.4/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/actionview-4.2.5.2/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/rails-html-sanitizer-1.0.3/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/loofah-2.0.3/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/rails-dom-testing-1.0.7/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/rails-deprecated_sanitizer-1.0.3/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/extensions/x86_64-darwin-15/2.2.0-static/nokogiri-1.6.7.2", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/nokogiri-1.6.7.2/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/mini_portile2-2.0.0/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/erubis-2.7.0/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/builder-3.2.2/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.5.2/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/tzinfo-1.2.2/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/thread_safe-0.3.5/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/minitest-5.8.4/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/extensions/x86_64-darwin-15/2.2.0-static/json-1.8.3", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/json-1.8.3/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/i18n-0.7.0/lib", "/Users/onody/Projects/test/rails_test/vendor/bundle/ruby/2.2.0/gems/rake-10.5.0/lib", "/Users/onody/.rbenv/rbenv.d/exec/gem-rehash", "/Users/onody/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/bundler-1.11.2/lib", "/Users/onody/.rbenv/versions/2.2.2/lib/ruby/site_ruby/2.2.0", "/Users/onody/.rbenv/versions/2.2.2/lib/ruby/site_ruby/2.2.0/x86_64-darwin15", "/Users/onody/.rbenv/versions/2.2.2/lib/ruby/site_ruby", "/Users/onody/.rbenv/versions/2.2.2/lib/ruby/vendor_ruby/2.2.0", "/Users/onody/.rbenv/versions/2.2.2/lib/ruby/vendor_ruby/2.2.0/x86_64-darwin15", "/Users/onody/.rbenv/versions/2.2.2/lib/ruby/vendor_ruby", "/Users/onody/.rbenv/versions/2.2.2/lib/ruby/2.2.0", "/Users/onody/.rbenv/versions/2.2.2/lib/ruby/2.2.0/x86_64-darwin15"]

ちゃんとなっている。

7. bundler-1.11.2/lib/bundler.rb

3〜6までのステップで、bundler/setupでは
Gemfile,Gemfile.lockを解析して$LOAD_PATHに追加することがわかった。

その後、2の処理に戻ってみると、
Bundler.requireをして、読み込んでいるのだけど、
それを追ってみよう。

    def require(*groups)
      setup(*groups).require(*groups)
    end

ここでは、setup(前に出てきたBundler::Runtime)のrequireメソッドを呼んでいる。 ポイントはgroup。Gemfileで指定したgroupのみをrequireしているところ。

group :test do
  gem 'faker'
  gem 'rspec'
end

8. bundler-1.11.2/lib/bundler/runtime.rb

以下でdependenciesを一つづつrequireしています。 ややこしいのが、 dependenciesがこのrailsが依存しているgem情報で、 specが各gemがさらに依存しているgemの情報です。 これらはGemfile.lockを見るとわかると思います。

def require(*groups)
      groups.map!(&:to_sym)
      groups = [:default] if groups.empty?

      @definition.dependencies.each do |dep|
        # Skip the dependency if it is not in any of the requested
        # groups
        next unless (dep.groups & groups).any? && dep.current_platform?

        required_file = nil

        begin
          # Loop through all the specified autorequires for the
          # dependency. If there are none, use the dependency's name
          # as the autorequire.
          Array(dep.autorequire || dep.name).each do |file|
            # Allow `require: true` as an alias for `require: <name>`
            file = dep.name if file == true
            required_file = file
            begin
              Kernel.require file
            rescue => e
              raise e if e.is_a?(LoadError) # we handle this a little later
              raise Bundler::GemRequireError.new e,
                "There was an error while trying to load the gem '#{file}'."
            end
          end
        rescue LoadError => e
          REQUIRE_ERRORS.find {|r| r =~ e.message }
          raise if dep.autorequire || $1 != required_file

          if dep.autorequire.nil? && dep.name.include?("-")
            begin
              namespaced_file = dep.name.tr("-", "/")
              Kernel.require namespaced_file
            rescue LoadError => e
              REQUIRE_ERRORS.find {|r| r =~ e.message }
              raise if $1 != namespaced_file
            end
          end
        end
      end
    end

まとめ

  • rails起動時は、bundler/setupと、Bundler.requireを実行している。
  • setup => 対象のgemのパスを$LOAD_PATHに通す。ただし、Gemfileで呼んでいるgemの、さらに依存しているgem(spec)もパスを通す。
  • require => Gemfileで呼んでいるgemを読み込む。その先は読まない。引数で指定したgroupのgemのみが読み込まれる。

エディタの選定基準

エディターを色々かえてきて、
どのエディタもシックリした感じがなく、
最近、もうそもそも色々変えること自体をやめたいなーと思っています。

そこで、改めて考えてみると 自分はいかに効率よくかけるかをベースに考えていたのですが、 それがそもそも間違っているのではないか?と。

プログラミング = コードを書いている時間とすると、
この時間はプログラマにとってすごい短い時間な気がします。

その観点で言うと、
プログラミングではないけど、プログラミングをするための準備時間
のほうが圧倒的に多い。

  • コードを読む
  • これから書くコードについて考える

など。 時間を計ると、だいたいこちらが7割くらい。

だとすると、コードエディタを選定する基準として、 いかに読む速度があがるか、を下敷きとして考えるべきかなーと。

書いているときにいろいろ制限されて書きづらいとストレスはでかいので、 それを重視してしまいがちだけど。。

一番良いのは、 書くようと、読むようをわけることなんだけど、 結局エディタ設定の管理コストとかも2倍とかになってくるから怠い。

ということで、 コードジャンプのようなものを素早く簡単にできるエディタが 一番作業効率の改善ができるきがするので、 自分はIDEがやっぱりいいのでは?という気がしてきて 最近はまたJetBrainsを使い始めています。

www.jetbrains.com

使っていると重くなるので、 キャッシュとかの問題かもしれない。 時間あるときに調べたい。

Reactのコード量を犠牲にして、コードの見通しを取る考え方

1500行ぐらいの軽めのAngularでつくられたwebアプリケーションを、 React(+手製Fluxっぽいモジュール)を使って書き直しました。ざくっと思ったことを書いておきます。Virtual DOMや性能的な話はなしで、コードの見通し・構造的な観点のみですが。

  • domエレメントと、その実装の距離がコード上で近くなったので、どこで何をやっているのかなどがわかりやすくなった。

  • 逆に、javascriptとhtmlがセットになった分、よくあるjavascriptは変えずにDOM構造変更、は気軽にできない。そういうオーダーがあとからこないかビクビクしている。

  • コード量が増えた。約3000行くらいだったので、倍になった。冗長なコードも多いかもしれませんが。

  • コンポーネントの状態(state)は、そのコンポーネントで持つか、親コンポーネントから継承(props)するか。コンポーネントで考えるときに、どのコンポーネントにどの状態を持たせるかという設計が、アプリケーション全体をシンプルでわかりやすい状態を保つために重要。

  • 最初、子コンポーネントから、親のまたさらにその親コンポーネントにどうやって状態変更を伝えるのか? を考えて、reactでやりきろうとpropsバケツリレー的な?ことやらかしまして、それから、どんどんおかしな方向に行っちました。。reactはあくまでも、状態と処理と結果ビューを1セットで扱う、ただのMVCのVなわけで、そこを勘違いしちゃうと、変な方向にいっちゃう。なんとか知り合いに聞いて、dispatcherとstoreを入れるflux的に解決で対応。 状態(state)はビューのデータを一時的に入れておく箱ぐらいに考えておいて、 アプリでグローバルなデータ/モデルなんかはstoreに持たせて、ビューはstoreをlisten、storeは変更をビューにemitするのがreact/flux的。

まとめ

マルチスレッド・プロセスの処理なんか書いたことないwebサーバサイド人間としては、
フロントのUIの非同期ばんばんの処理にはじめてぶち当たったときに、MVCでやりきろうとしてカオスになって死ぬ。。的なストーリーを地でいきかけたわけです。。

で、こういうReact的な解決方法は新鮮でした。

コード増えるけど、データの流れが決まっているので、
その流れに乗せるように開発してけば、見通しよくなるんじゃね?的な。

ただ、htmlとjsをくっつけたことでの弊害も色々あるので、
ケースバイケースです。

デザイナーがjs書けて、そこそこ規模の大きくて、運用しやすさも求めるならば、
向いているかも。

もちろん、別にVirtual DOM的な導入利点もあるかもしれませんが、
それは、Reactだけの話ではなくなるので。