週刊Railsウォッチ(20191021)Rails 6でhas_many関連の修正やSprockets 4.0対応、Shrine 3.0がリリース、Minitestスタイルガイドほか

こんにちは、hachi8833です。スマホで確定申告できるようになるそうです。


つっつきボイス:「スマホで確定申告したい人っているんでしょうか?😆」「スマホとかタブレットでやらないと間に合わないシチュエーションはあるかもですね☺️」

  • 各記事冒頭には⚓でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
  • 「つっつきボイス」はRailsウォッチ公開前ドラフトを(鍋のように)社内有志でつっついたときの会話の再構成です👄
  • 毎月第一木曜日に「公開つっつき会」を開催しています: お気軽にご応募ください

Rails: 先週の改修(Rails公式ニュースより)

今回はコミットリストから見繕いました。has_many関連の修正が目に付きました。

(master)belongs_toからhas_manyへのinverseをサポート

# activerecord/lib/active_record/associations/belongs_to_association.rb#L111
-       # NOTE - for now, we're only supporting inverse setting from belongs_to back onto
-       # has_one associations.
        def invertible_for?(record)
+         inverse = inverse_reflection_for(record)
+         inverse && inverse.has_one?
+         inverse_reflection_for(record)
        end
# activerecord/lib/active_record/associations/collection_association.rb#L288
+     def target=(record)
+       case record
+       when Array
+         super
+       else
+         add_to_target(record)
+       end
+     end

つっつきボイス:「belongs_toからhas_manyへのcollectionのinverseはありそうでなかったんですね😳」「ドキュメントの更新と実際の挙動が合ってなかったので修正したそうです」

「ところでこのr?という「合ってる?」表現↓、ちょっと便利かなと思いました😋」「right?をそこまで略すのはどうかと😆」「SNSのチャット感覚というか😆」「そのぐらいフルで書いてもいいのでは😆」「了解を『り』とか『りょ』と書くみたいな😆」


#34533より

(master)inverse_of:を指定したhas_manyのレコード追加で関連付けのコールバックが発火しないように修正

has_manyinverse_of:を追加した場合に関連付けのコールバックが走るのを止める。
上の#34533に関連して、has_manyリレーションでinverse_of:を静かに設定したい、つまり新たに追加したレコード用のロジックをトリガしたくない。
has_manyのinverseを設定すると既存のアプリケーションが壊れる可能性が非常に高いが、これが正しい動作。挙動を選べるようにするプルリクを別途投げて、アプリ側を調整する時間を取れるようにする。
同PRより大意

修正はわずか1箇所です↓。

# activerecord/lib/active_record/associations/collection_association.rb#L293
      def target=(record)
        case record
        when Array
          super
        else
-         add_to_target(record)
+         add_to_target(record, true)
        end
      end

つっつきボイス:「今回はhas_many関連の修正が多くて、特にこれは修正は1箇所だけですがbreaking changeになってますね」「ははぁ😳、こういう変更をバシッと入れるのがすごいな〜って」「さすがに影響大きそうなので、デフォルトではオフにするそうです↓」「使う側はこういう変更追いかけるの大変そう😅」

以下がその後に入った、挙動を選べるようにする修正ですね。config.active_record.has_many_inversingという設定(デフォルトはfalse)が追加されています。


なお、以下の記事では「Rails 4.1以降ではinverseの自動検出機能がある」「inverseの自動検出はhas_manyhas_onebelongs_toでのみ効く」「関連付けにそれ以外のオプションを付けると自動検出されなくなる」ともあります。APIのActiveRecord::Associations::ClassMethodsの「Setting Inverses」にも同じ記述がありました。

参考: Rails 4.1+ automatically detects the :inverse_of an association - makandra dev

Sprockets 4.0に合わせてテストスイートを修正


つっつきボイス:「先週取り上げたSprocketsのアップデート(ウォッチ20191015)に合わせてRails側も修正したようです」「ほほぉ〜😋」

  • application.cssapplication.css.erbを両方使うのは適切ではなくなった(ナイス変更!)
  • //= link_directory ../javascripts .jsでJavaScriptをデフォルトで再追加することでリンクするのを廃止
    • (これはデフォルトにしたい気がするが、今はWebpackerが望ましいのでJSのテストのためだけに一応足しておいた)
  • アセットのデバッグモードが変わった
    同PRより大意

「ついでにこんな記事↓も見つけたんですが、Rails 6がSprockets 4.0に対応する前にSprocketsを使ってみて、上の修正と同じような箇所でハマったようです😇」「急ぎすぎ😆」「ついでにSprockets 3と4の違いについても追っていますね☺️」

has_manyのeager loadingのエッジケースを修正

eager loadingの実行結果(のレコード)は重複解除される。
これはhas_manyのeager loadではできているが、できていない組み合わせのケースがあった。
同PRより大意

# activerecord/lib/active_record/relation/finder_methods.rb#L381
      def apply_join_dependency(eager_loading: group_values.empty?)
        join_dependency = construct_join_dependency(
          eager_load_values + includes_values, Arel::Nodes::OuterJoin
        )
        relation = except(:includes, :eager_load, :preload).joins!(join_dependency)

-       if eager_loading && !using_limitable_reflections?(join_dependency.reflections)
+       reflections = join_dependency.reflections + joins_values.map { |joins_value| reflect_on_association(joins_value) }.reject(&:blank?)
+       if eager_loading && !using_limitable_reflections?(reflections)
          if has_limit_or_offset?
            limited_ids = limited_ids_for(relation)
            limited_ids.empty? ? relation.none! : relation.where!(primary_key => limited_ids)
          end
          relation.limit_value = relation.offset_value = nil
        end
        if block_given?
          yield relation, join_dependency
        else
          relation
        end
      end
# activerecord/test/cases/finder_test.rb#1339
  def test_eager_load_for_no_has_many_with_limit_and_joins_for_has_many
    relation = Post.eager_load(:author).joins(:comments)
    assert_equal 5, relation.to_a.size
    assert_equal relation.limit(5).to_a.size, relation.to_a.size
  end

つっつきボイス:「またhas_many😆」「まただ〜😆」「SQLの結果では複数行になるけどinstantiateするときに1つになるのが本来で、エッジケースでそうならないバグがあったということか: テストコード↑と#37356の再現手順↓を見る方がわかりやすいかも🤔」

# #37356より
class Post < ActiveRecord::Base
  has_many :comments
  has_one :author
end

class Comment < ActiveRecord::Base
  belongs_to :post
end

class Author < ActiveRecord::Base
    belongs_to :post
end

class BugTest < Minitest::Test
  def test_in_batches_corner_case
    posts = 5.times.map do
      post = Post.create!
      post.comments << Comment.create!
      post
    end
    multiple_comments = posts[2]
    multiple_comments.comments << Comment.create!

    post_count = 0
    unbatched_query = Post.eager_load(:author).joins(:comments)
    unbatched_query.find_each(batch_size: 2) do |post|
      post_count += 1
    end
    assert_equal unbatched_query.to_a.count, post_count
  end
end

「eager loadingってこれですね↓」「deduplicateって口で言うの大変😅」「デデュプリケート😆」

参考: eager loadingって何? - おもしろwebサービス開発日記

参考: ActiveRecordのincludes, preload, eager_load の個人的な使い分け | Money Forward Engineers’ Blog

Rails: JOINすべきかどうか、それが問題だ — #includesの振舞いを理解する(翻訳)

キーが多数の場合のread_multi_entriesのパフォーマンスを改善

ActiveSupport::Cache::Store#read_multi_entriesを以下の3点について少々リファクタリングし、フェッチしたキーが増加したときのパフォーマンスを若干改善した。個人的には読みやすさも向上したと思う。

  • eacheach_with_objectに変更。これによってハッシュを冒頭で宣言して最後に返す必要がなくなった。
  • キャッシュエントリが見当たらない場合にローカル変数versionの算出を回避した。
  • 何もしない場合の条件を削除した。
    同PRより大意
================================== A few keys ==================================

Warming up --------------------------------------
          read_multi    12.831k i/100ms
     fast_read_multi    14.510k i/100ms
Calculating -------------------------------------
          read_multi    146.288k (±26.0%) i/s -    654.381k in   5.010593s
     fast_read_multi    172.428k (±25.9%) i/s -    783.540k in   5.023852s

Comparison:
     fast_read_multi:   172427.5 i/s
          read_multi:   146288.2 i/s - same-ish: difference falls within error


================================== Many keys ===================================

Warming up --------------------------------------
          read_multi   196.000  i/100ms
     fast_read_multi   279.000  i/100ms
Calculating -------------------------------------
          read_multi      1.984k (± 6.7%) i/s -      9.996k in   5.062818s
     fast_read_multi      2.823k (± 7.6%) i/s -     14.229k in   5.072824s

Comparison:
     fast_read_multi:     2823.1 i/s
          read_multi:     1984.3 i/s - 1.42x  slower
# activesupport/lib/active_support/cache.rb#L585
        def read_multi_entries(names, **options)
-         results = {}
-         names.each do |name|
-           key     = normalize_key(name, options)
+         names.each_with_object({}) do |name, results|
+           key   = normalize_key(name, options)
+           entry = read_entry(key, **options)
+
+           next unless entry
+
            version = normalize_version(name, options)
-           entry   = read_entry(key, **options)
-
-           if entry
-             if entry.expired?
-               delete_entry(key, **options)
-             elsif entry.mismatched?(version)
-               # Skip mismatched versions
-             else
-               results[name] = entry.value
-             end
+
+           if entry.expired?
+             delete_entry(key, **options)
+           elsif !entry.mismatched?(version)
+             results[name] = entry.value
            end
          end
-         results
        end

つっつきボイス:「割と読みやすいリファクタリングかなと思いました☺️」「names.each do |name|names.each_with_object({}) do |name, results|に変えたことでresults = {}を書かなくてよくなったと、なるほど😋」「余分な条件も削除した」「そして1.42倍速くなって読みやすくなった🎉」「冒頭にresults = {}みたいな空の変数初期化を置くのって何となく悔しいですよね😆」「たしかに😆」

Rails

Capistranoに対話処理を取り入れる(Hacklinesより)

# 同記事より
namespace :rails do
  desc "Start a rails console"
  task :console do
    exec_interactive("rails console")
  end

  desc "Start a rails dbconsole"
  task :dbconsole do
    exec_interactive("rails dbconsole")
  end

  def exec_interactive(command)
    host = primary(:web).hostname
    env = "RAILS_ENV=#{fetch(:rails_env)}" # add other ENV variables
    command = "cd #{release_path}; #{env} bundle exec #{command}"

    puts "Running command on #{host}:"
    puts "  #{command}\n\n"

    exec %(ssh #{host} -t "sh -c '#{command}'")
  end
end

つっつきボイス:「CapistranoはRuby製の自動化・デプロイツールでお馴染みですが、それに対話的処理を加えてみたという短い記事です」「Capistranoまだ使ったことなくて😅」「morimorihogeさんはCapistranoいいよって言ってました(ウォッチ20181210)」「お〜見てみます😋」

「バッチでえいやする代わりに対話的にやりたいときもあるんでしょうか?」「デプロイってだいたいバッチでえいやが多い気もしますけど😆」

「Rubyのは知りませんが、デプロイツールはいろいろ使いました☺️」「ちなみにどんなのをお使いでした?」「古いところではmavenとか↓」「おぉ知りませんでした😳」「Apache Antもそうかなと思ったらこっちはビルドツールだった😆」「どちらもJava方面なんですね」「何しろ昔からあるので古いといえば古いかな〜👴」「mavenって辞書見ると『物知り、専門家、達人、玄人、通、目利き、大御所』とか強そうな意味が並んでる😆」

参考: Apache Maven - Wikipedia


maven.apache.orgより

参考: Apache Ant - Wikipedia


ant.apache.orgより

Railsのビューでstrftimeを直書きするのはたぶん間違い

# 同記事より: config/initializers/time_formats.rb
Date::DATE_FORMATS[:stamp] = "%Y%m%d" # YYYYMMDD
Time::DATE_FORMATS[:stamp] = "%Y%m%d%H%M%S" # YYYYMMDDHHMMSS

つっつきボイス:「この記事ではstrftimeをビューに直書きする代わりに、書式をグローバル定数に置いてるみたいなんですけど、それもどうなんだろうと思って」「お、最初自分もグローバル定数かと思ったけど、このDATE_FORMATSはどうやらRails組み込みの機能↓のようで、そこに:stampという独自の書式を追加していますね」「あ、そうでしたか😅」「グローバル定数で書くのは止めた方がいいけど、機能としてあるなら使っていいと思います😋」

DATE_FORMATS    =   { short: "%d %b", long: "%B %d, %Y", db: "%Y-%m-%d", number: "%Y%m%d", long_ordinal: lambda { |date| day_format = ActiveSupport::Inflector.ordinalize(date.day) date.strftime("%B #{day_format}, %Y") # => "April 25th, 2007" }, rfc822: "%d %b %Y", iso8601: lambda { |date| date.iso8601 } }
DATE_FORMATS    =   { db: "%Y-%m-%d %H:%M:%S", number: "%Y%m%d%H%M%S", nsec: "%Y%m%d%H%M%S%9N", usec: "%Y%m%d%H%M%S%6N", time: "%H:%M", short: "%d %b %H:%M", long: "%B %d, %Y %H:%M", long_ordinal: lambda { |time| day_format = ActiveSupport::Inflector.ordinalize(time.day) time.strftime("%B #{day_format}, %Y %H:%M") }, rfc822: lambda { |time| offset_format = time.formatted_offset(false) time.strftime("%a, %d %b %Y %H:%M:%S #{offset_format}") }, iso8601: lambda { |time| time.iso8601 } }

参考: Railsで日付/時刻のフォーマットを設定するTips - Rails Webook
参考: RailsのTime::DATE_FORMATS[:default]は変更しないほうがいい - Qiita

↑2番目の記事ではI18nの機能を使う方法も紹介されています。

スクリーンキャスト: 13分でわかるRails tipsいろいろ(Ruby Weeklyより)


つっつきボイス:「Railsのちょっとした便利ワザ集なんですが、スクリーンキャストって見ます?」「いや〜自分は見ませんけど☺️」(少し流し見)

「これが10分あまり続くんですね😅」「まあ10分ならまだ短い方かも: 1時間とかかかるのもざらにありますし😆」

「ところでparameterってプラミターとかプウァミターみたいに発音してるんですね😳」「割とそんな感じですね: 「ラ」を強く言うのがポイント」「果物のプラムかと思っちゃいました😅」「あとSQLもあっちの人はだいたいスィークォー(sequel)と言ってます😆」「エスキューエルって言うのは日本人ぐらい?」「たまに言う気もしますけどsequel多いですね☺️」

なお一般的な意味のsequelは「(ドラマなどの)続編」です。


「スクリーンキャストで思い出したんですけど、昔大学の先輩がライブコーディングをやってみせたときになかなかうまくいかなくて、あれはある意味特殊な才能が必要なんじゃないかって話になりました😆」「あ〜たしかに」「本番でいろいろハプニングが起きうることを見越してライブコーディングするのはホント大変😭」「録画を流す方がまだやりやすいかも: 前にも紹介しましたけど、jnchitoさんは銀座Railsのときに録画を倍速再生して見せてくれました↓」「お〜」

Shrine 3.0がリリース(Awesome Rubyより)


shrinerb.comより

もう3.0.1になっていますね。
コアの再設計以外はほとんどがプラグイン関連の変更のようです。

  • Shrine::Attacherを再設計
  • versionsプラグインを書き直し
  • mirroringプラグインを追加
  • ROMやHanamiとの統合を強化

つっつきボイス:「お、Shrineのアップグレードって前にもつっつきで見たような覚えありますね」「あ、アップグレード予告を取り扱ったような😅」

↓こちらでした。

週刊Railsウォッチ(20190902)Ruby 2.6.4セキュリティ修正リリース、スライド「All About Ruby in 2019」、Shrine gem 3.0に入る新機能ほか

「ともあれShrineが3.0でだいぶ強力になったようです🎉」「サイトデザインが新しくなったという見出しがトップ😆」「Attacherというクラスの設計をActive Recordから切り離して他でも使えるようになったり、プラグインを追加更新廃止したり」「ところでなぜShrineという名前なんでしょうね😆」「どの辺が神社仏閣なのかわかりませんし😆」

# 同記事より: 単独でも使えるように設計見直し
attacher = ImageUploader::Attacher.new
attacher.attach(file)
attacher.file #=> #<Shrine::UploadedFile>
attacher.url  #=> "https://my-bucket.s3.amazonaws.com/path/to/image.jpg"

shrine: 遺骨・遺物をおさめた箱、櫃(ヒツ)が原義


「Algolia?」「ShrineのサイトがAlgoliaで検索できるようになったと記事にありますね↓: AlgoliaについてはTechRachoにも記事がありますのでどうぞ😋」

Rails: 高速リアルタイム検索API「algolia-search-rails」gem README(翻訳)

その他Rails

Ruby

Minitestスタイルガイドが登場(Ruby Weeklyより)


minitest.rubystyle.guideより


つっつきボイス:「rubocopチームが作ってくれたそうですが、シンプルなのがいいなと思って😋」「たしかにあれっと思うぐらい短いですね」「RSpecのスタイルガイドは@willnetさんが日本語にしてくれています↓が、これと比べても短い」

参考: willnet/rspec-style-guide: 可読性の高いテストコードを書くためのお作法集

なお以下は中の人Batsovさんのブログです。rubocop-minitestは進行中のようです。

私はRSpecが大好きですが、Minitestのシンプルな設計にも大いに敬意を払ってます。
私たちRuboCopチームが現在rubocop-minitestに取り組み中であることをお知らせします。
同記事より大意

active_hash: ハッシュをActive Recordモデルっぽくリードオンリーアクセス

ruby-jp Slackで見かけました。


つっつきボイス:「RubyのハッシュをActive Recordみたいにするgemで★700超えてますが、どんな人が使うのかな?🤔」

こちらの記事では、都道府県のように更新されないデータをactive_hashで扱ってますね↓。

参考: active_hash[gem]でデータの入ったテーブル作成 - Qiita

ActiveHash::Baseを継承すると、ハッシュのキーがメソッドで生えてくるという」

# 同リポジトリより
class Country < ActiveHash::Base
  self.data = [
    {:id => 1, :name => "US"},
    {:id => 2, :name => "Canada"}
  ]
end

country = Country.new(:name => "Mexico")
country.name  # => "Mexico"
country.name? # => true

「クラスメソッドやインスタンスメソッドもいかにもActive Record風」「おほ、なるほどなるほど☺️」

# クラスメソッド
Country.all                    # => returns all Country objects
Country.count                  # => returns the length of the .data array
Country.first                  # => returns the first country object
Country.last                   # => returns the last country object
Country.find 1                 # => returns the first country object with that id
Country.find [1,2]             # => returns all Country objects with ids in the array
Country.find :all              # => same as .all
Country.find :all, args        # => the second argument is totally ignored, but allows it to play nicely with AR
Country.find_by_id 1           # => find the first object that matches the id
Country.find_by(name: 'US')    # => returns the first country object with specified argument
Country.find_by!(name: 'US')   # => same as find_by, but raise exception when not found
Country.where(name: 'US')      # => returns all records with name: 'US'
Country.where.not(name: 'US')  # => returns all records without name: 'US'
# インスタンスメソッド
Country#id          # => returns the id or nil
Country#id=         # => sets the id attribute
Country#quoted_id   # => returns the numeric id
Country#to_param    # => returns the id as a string
Country#new_record? # => returns true if is not part of Country.all, false otherwise
Country#readonly?   # => true
Country#hash        # => the hash of the id (or the hash of nil)
Country#eql?        # => compares type and id, returns false if id is nil

# 以下はメタプロで生える
Country#name        # => returns the passed in name
Country#name?       # => returns true if the name is not blank
Country#name=       # => sets the name

「こういう書き方ってしたい方ですか?」「いやぁ〜、今見たときはふむふむと思いましたけど、このgemが入ってきたらまた書き方覚えないといけないのかなって😅」「まあ業務コードに入れるなら確認取ってからでしょうね😆」

「Rubyだとハッシュのキーを.で呼べないのが悲しいって言う人をそこそこ見かけたりしますけど、Ruby自身にこういうのは入れないのかな?🤔」「どうでしょう😆、求められているなら入るかもしれませんけど、私は.でハッシュキー呼べなくても別にいいじゃんって思いますし☺️」

後で探すと、frozen_recordという少し似た感じのgemがありました。

Ruby 2.7のArrayにintersectionuniondifferenceが追加(RubyFlowより)

# 同記事より
[ "a", "b", "z" ].intersection([ "a", "b", "c" ], [ "b" ])  # => [ "b" ]
[ "a", "b", "c" ].union( [ "c", "d", "a" ] ) #=> [ "a", "b", "c", "d" ]
[ 1, 4, 7, 8, "a", :t ].difference([ 4, :t ]) #=> [ 1, 7, 8, "a" ]

つっつきボイス:「Ruby 2.7のArrayに集合論っぽいメソッドが入るそうです」「RubyのSet的なことがArrayでもできるようになったと🤔」「しょっちゅうは使わなくても、たまに欲しくなりそう😆」

参考: class Set (Ruby 2.6.0)

parallel: Rubyで並列処理(Ruby Weeklyより)

# 同記事より
# 2 CPUs -> work in 2 processes (a,b + c)
results = Parallel.map(['a','b','c']) do |one_letter|
  expensive_calculation(one_letter)
end

# 3 Processes -> finished after 1 run
results = Parallel.map(['a','b','c'], in_processes: 3) { |one_letter| ... }

# 3 Threads -> finished after 1 run
results = Parallel.map(['a','b','c'], in_threads: 3) { |one_letter| ... }

つっつきボイス:「parallelっていうgemは見たことありそうでなかったので」「このgemは前からありそうな雰囲気ですけど既に標準だったりしません?」「標準ライブラリのリストにはありませんでした」

後で調べると、parallel gemは2009年からありました。

「Rubyで並列的なことをやる方法って他にもいろいろありそうですけど?」「標準ライブラリにThreadとかFiberとかありますね↓😋」「なるほど」

参考: class Thread (Ruby 2.6.0)
参考: class Fiber (Ruby 2.6.0)

「そういえばちょっと前のQuoraで『現状のThreadは直したい』というMatzからの回答↓があったのを思い出しました」「並列系って自分もそもそもほとんどやってこなかったし、ちゃんと勉強してからやらないときっとハマりそう😭」「私もGo言語のgoroutimeまだ自分ではやれてないです😅」

参考: Rubyを作り直すとしたら、変更を加える箇所はありますか? - Quora

「Active Recordでもやれるようです↓」「これでテストを速くできるならいいかも😋」「parallel gemのコントリビューターもめちゃ多いですね😳」

# reproducibly fixes things (spec/cases/map_with_ar.rb)
Parallel.each(User.all, in_processes: 8) do |user|
  user.update_attribute(:some_attribute, some_value)
end
User.connection.reconnect!

# maybe helps: explicitly use connection pool
Parallel.each(User.all, in_threads: 8) do |user|
  ActiveRecord::Base.connection_pool.with_connection do
    user.update_attribute(:some_attribute, some_value)
  end
end

# maybe helps: reconnect once inside every fork
Parallel.each(User.all, in_processes: 8) do |user|
  @reconnected ||= User.connection.reconnect! || true
  user.update_attribute(:some_attribute, some_value)
end

後で調べると、同じ作者のparallel_testsというgem↓はだいぶ前にウォッチで取り上げたことがありました(ウォッチ20171117)。gemspecでもparallel gemがruntime dependencyになっています。

その他Ruby



つっつきボイス:「川合史朗さんはScheme系言語のGaucheの作者ですね」「ガウシュ?ゴーシュ?😆」「セロ弾きのゴーシュとスペル同じですしゴーシュなのかも🤔」「この方はハワイ在住で俳優もやっていて、いくつか映画にも出演してるそうです🏝」「ソフトウェア開発者で俳優…なんと幸せな人生😊」

参考: Gauche - Wikipedia
参考: 17. Gauche Schemeの基本デザインの選択理由、オブジェクトデータベース、浮動小数点数の落とし穴 (川合史朗) — 映画出演の話にも触れられています

DB

Oracleから独自RDBへ


つっつきボイス:「Oracleから自社製RDBMSへの乗り換えニュースを2つ連続で見かけました」「これスゴいですよね〜、自社製のRDBMSがどんなものか触ってみたい気がしますけど」「お、アリババの方はソース公開されてるって記事にありますね😳」「お〜、このoceanbaseというのがそれですか↓: 誰か動かしてみないかな😋」「Amazonの方は名前もわからず😢」

ちなみにoceanbaseのドキュメントは中国語かつdocxのようです😭。

「oceanbaseについて探してたら、dbdb.io↓というサイトが出てきた」「いろんなRDBMSを一覧できるカタログサイトのようですね☺️」


dbdb.ioより


以下はつっつき後に見つけました。

参考: 世界1位になったアリババの独自開発DB OceanBaseとは何者か? - ブログなんだよもん

言語・ツール

言語人気の移り変わり


つっつきボイス:「こういうのって単純に楽しいですね😊」「どこ由来のデータかは知りませんけど😆」「大昔はFortranとCobolが人気だったまではわかるんですが、Pascalが1位だった時代ってあったんですか?」「Mac OS 9までのMacだとTurbo Pascalが割と多かった気がします」「そうこうしているうちにC言語トップになって2000年過ぎたあたりからJavaが1位に」「PHP元気だな〜😆」「Rubyもトップテンに」「直近はPythonがトップ」

参考: Turbo Pascal - Wikipedia

その他

キーボードの方がでかい


つっつきボイス:「ぱっと見Wi-Fiアンテナ付きダムハブみたいですけど😆」「あ、これPCですか😳: このスペック(Core i7-8665U 1.9GHz、メモリ16GB)で18万…やばい猛烈に欲しくなってきた❤️」「ハートに突き刺さる音が聞こえました😆」「NASつないじゃえば容量問題にならないし、う〜こっち買えばよかったか😭」「もう少しスペック下でもいいから軽くて安いのがあればDocker専用機にして持ち歩きたい😆」(以下延々)

番外

自然言語も移り変わる


つっつきボイス:「最後は言語学ネタで😆: 羽柴秀吉がファシンバ・フィンデヨシだったとか」「何を基準にしてたのかしら😅」「安土桃山時代のポルトガル人宣教師たちが作った日本語-ポルトガル語辞書で当時の発音がキャプチャされてたそうで、は行がɸ音(ph)だったとかかなり違ってますね」「ほぇ〜😳」「ついでに、日本語の濁点や半濁点も、その宣教師たちが必要に迫られてこしらえたのが後に日本語でも定着しちゃったんだそうです」「逆輸入😆」

参考: 日葡辞書 - Wikipedia

「そうなるとポルトガル人の発音も今と昔で違ってるでしょうから、そういうフィルタの影響を取り除いて研究するのは大変そう😆」「たしかに😆」「日本人もかつてイギリスをエゲレスとかアメリカンをメリケンとか言ってましたし、外人が日本人の名前を呼ぶときに訛るのと似てるようにも見えますけどね😆」「英語圏の人は『こんにちは』を『コニーチワ』って発音しがちですけど、その辺に通じるかも」「n音が連続するとつながるんでしょうね☺️」(以下延々)

江戸時代の長崎出島の通詞(=通訳)が幕末にオランダに渡ったとき、現地の人から「まるでうちのおじいさんが話しているようなオランダ語だ」と妙に感激されたという話を思い出しました。鎖国のせいでタイムカプセル的に保存されてたんでしょうね。

「自然言語もこんなに変わるんだからプログラミング言語も長年の間にがらっと変わったりするかなと」「いやいやプログラミング言語は発音関係ありませんから😆」


今回は以上です。

おたより発掘

バックナンバー(2019年度第4四半期)

週刊Railsウォッチ(20191015)スライド「Rails Performance issues and Solutions」を見る、dirtyに*_previously_was が追加、Sidekiq 6.0.1ほか

今週の主なニュースソース

ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSやruby-jp Slackなど)です。

Rails公式ニュース

Ruby Weekly

Awesome Ruby

RubyFlow

160928_1638_XvIP4h

Hacklines

Hacklines

Publickey

publickey_banner_captured

デザインも頼めるシステム開発会社をお探しならBPS株式会社までどうぞ 開発エンジニア積極採用中です! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833、GitHub: @hachi8833 コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。 これまでにRuby on Rails チュートリアル第2版の監修および半分程度を翻訳、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れて更新翻訳中。 かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。 実は最近Go言語が好きで、Goで書かれたRubyライクなGoby言語のメンテナーでもある。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

夏のTechRachoフェア2019

週刊Railsウォッチ

インフラ

ActiveSupport探訪シリーズ