こんにちは、hachi8833です。2週間ぶりのご無沙汰でした。暑さでもうろうとしています。
各記事冒頭にはでパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
今回のつっつきも、BPSの福岡拠点であるウイングドアの皆さまと画面共有しながら行いました。いつもありがとうございます。
【お知らせ】週刊Railsウォッチ「公開つっつき会 第1回」を8/2(木)に開催
週刊Railsウォッチを日頃ご愛顧いただきありがとうございます。
ウォッチを出す前に毎週木曜に社内で「つっつき会」を催していますが、このたび8/2(木)に「公開つっつき会 第1回」を開催するはこびとなりました。以下のTECH PLAYページからエントリーいただけますので、つっつき会を覗いてみたい方はお気軽にご参加ください。普段から質問や発言も自由な気楽な集まりとして行っていますので、普段なかなかできない質問やツッコミなどもお気軽にどうぞ。
- エントリページ: 週刊Railsウォッチ 公開つっつき会 第1回|IT勉強会ならTECH PLAY[テックプレイ] — 詳しい内容はエントリページにてご確認ください。
- 参加対象: Web/Ruby/Rails開発者、およびそれらに興味のある学生
- 定員: 5名
- 開催日時: 8月2日(木) 19:30〜21:00(開場は19:15〜)
- その後の懇親会で軽食をご用意いたします
- 開催場所: BPS株式会社 会議スペース
- 参加費: 無料
- 持ち物: 特に必要なものはありません
特集: Rails Developer Meetup 2018 Day 3 Extremeその後
おつかれさまでした。なんとか無事終わってホッとしました。 #railsdm
— 徳用カルパス (@yoshi_hirano) July 14, 2018
- イベント: Rails Developers Meetup 2018 Day 3 Extreme|IT勉強会ならTECH PLAY[テックプレイ]
- kamipoさんへの質問: [特別講演] Rails 6 に向けた ActiveRecord の改善 | AMA
- 動画チャンネル: Rails Developers Meetup - YouTube
このボリュームを一日でやるとは…今週のウォッチはその分後半のエントリを意識的に減らしました。
つっつきボイス: 「文字どおりエクストリームなボリュームでしたね…キャンセル待ちもならず」「スケジュールの密度ちょっと高いかなー」「今年3月のRailsdmのときは自分たちも発表しました↓が、タバコ吸ったら休憩時間終わっちゃう感じでした」「ともあれ、Railsdmは技術プレゼンの質もいいし、それでいて技術系に限定されないバラエティ豊かな点も貴重」「」「あと現場のつらみの話をいろいろ聞けるのもいいですねー: 単なる新しい技術の話とかはググれば済むけど、試してはまった話は実際にやってみた人じゃないとできないので」「毎回出席は体力的に大変ですが」「後追いで興味のあるプレゼンのスライドやYouTube動画で確認するだけでも役に立つし」「ストリーム中継の時点でYouTubeだからそのまま動画として残ってるのはありがたいです」
kamipoさん動画のさわり
つっつきボイス: 「とりあえずkamipoさんのActiveRecord話を見たかったので後追いでごくあっさりとチェックしてみました: 冒頭『何にも準備しなくていいと聞いてたんで』と言ってたぐらいで、その場でコミット眺めながら進めてました」
Q: 仮にMySQLだけをサポートするARを作れるとしたらどんな最適化ができそう?
A: RDBMSを絞れば確かに最適化はしやすい: mysql2 gemは既にいろいろやりすぎてて線引きがしにくいけどpg gemはやりすぎてないのでこれに絞れるなら最適化の余地は大きそう。
14:38
「PostgreSQLのRails向け拡張って結構いろいろあるし便利な機能が本当にいっぱいあるんだけど、Railsにそういうのを導入するとPostgreSQLでしか動かなくなっちゃうのでRails標準でやるのは難しいでしょうねー」「やはり」「個人的にはポスグレで行って欲しいけどねっ」
Q: #30000の次にキリ番ゲットしたら直したいARは?
A: もし取れたら、ロールバックしたときにdirty valueもロールバックしたい(今は4種類のステートだけロールバックされる)。
19:05
「dirty valueというものがあったとは…」「dirty value、自分はなるべく使わないようにしてるんだけどな…どこでどう変わるか予測しきれないことあるし」「」「1つ手前に戻すぐらいならいいんだけど、コミットとかし始めるとどこまで確実にロールバックできるのか正直不安だし」「それもそうですね…」「自分は直接dirty valueを触るよりは別の変数に取っておきたい派」
Q: MySQLのdefault character setをutf8からutf8mb4に変えるというのはどうでしょう?
A: MySQLのinnodbにはkey prefix lengthの制限があるので厳しいです: この問題をユーザーに押し付けていいんだったら変えられる。
22:25
「key prefix lengthの件はそのとおりで、MySQLだとinnodbのkey prefix lengthをケアしないとインデックス付けた瞬間にコケるとかあるんですよ」「ありゃー」「MySQLをバージョン8にすればいいんじゃね?っと思ったけど、database.ymlでデフォルトでutf8
って書かれたらダメだろうし…実際はどうだったかな?」(RubyMineで探し始める)「あったあった: あー、やっぱりymlテンプレートのデフォルトエンコーディングはutf8
か↓」「残念」「誰もが新しいバージョンのMySQLを使ってくれていれば問題なくデフォルトをutf8mb4
に変えられるんですけど、MySQL 5.6の初期バージョンあたりを使う人たちはkamipoさんの言うようにkey prefix lengthの問題を踏むことになっちゃうので、5.7より前のサポートを打ち切るとかしないとねー」
# https://github.com/rails/rails/blob/bd7b61aefb4382f3cf2113c883f12bc5a3e99ae5/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml#L14
default: &default
adapter: mysql2
encoding: utf8
pool: <%%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: root
password:
...
Q: 非推奨にしたいActiveRecord APIは?
A: 6.0までにということだったらscoping
(クラスメソッド)を殺したい(#32380の例を参照)。他にも片手ぐらいある。
24:12
Q: ActiveRecordにぜひ入れたいまったく新しい機能は?
A: 若い人に任せたい気持ちだけど、1つあるとすれば#12937。typecastしないpluck
が欲しい。(年に数件は同じようなissueが上がる)。
34:56
「kamipoさんがリモート参加だったらしく音声がちょっと聞き取りにくくて、最初crackって言ってるのかなと思ったらpluck
だったみたいです」「(issueを見ながら)あー、たとえばsum
したものをpluck
すると勝手にtypecastされちゃうってやつか」「なのでtypecastしないバージョンのpluck
が欲しいということなんですね」「確かにSQLのSELECTを手動でカスタマイズしているときなんかは生のSQL結果に近いデータが欲しいことが多いし、そういうときに余計なtypecastやられると邪魔なんですよね」
Q: 「これを殺したら速くなる」機能は?
A: (中略)たぶんdirty tracking(before_type_cast
)を殺せばインスタンス生成がものすごく減ると思う。(中略)つまりAttributes APIをなくせばいい()。ちなみにDiscourseのSam Saffronが作ってるいろんなgemは、使ってないARの機能を殺すことで速くしている。
40:17
「dirty trackingは余分なこといろいろやってそうではある」「上は相当端折ってますが、dirtyに対応するために相当いろんなインスタンスが生成されてるみたいです」「でしょうねー: でないとあんなにたくさんのdirty attributesに対応できるはずがないし」「Attributes APIをなくす云々はギャグで言ってる感」「そこにありますからね」
「Sam SaffronさんはTechRachoでも翻訳記事いくつか出してます↓」「使わないARの機能を殺すというのはそれはそれでありかもね」「後でRailsをアップグレードするのが大変そう」「アップグレードよりは、他のgemがその機能を使ってるかもしれないからそのあたりをケアしないといけないのが面倒かも」
Form Objectの話
Rails DM Day3 で話した資料です!! / “フォームオブジェクトとの向き合い方/Grow Form Objects up – Speaker Deck” https://t.co/HtO0pQCYlt
— MOROHASHI Kyosuke (@moro) July 14, 2018
「全部追う時間はないので他にとりあえず気になったものとしては諸橋さんのForm Objectの話: 以前のウォッチでForm Objectの必然性がひとつ減ったかもという話が出てたので」「RailsのForm Objectは、それがうまくはまるときに使えばいいんじゃないかな: 特に最近はフォームが複雑なときはVue.jsなどのSPA的なライブラリで作ることが増えたので、その意味でもForm Objectの活躍の機会は減りつつあるかも」「」「フロントエンジニアが組み立てたJSONオブジェクトがPOSTされるから、Form Objectを作る必要はあまりないし、Form Objectを使う大きな理由のひとつはフォームヘルパーを使いたいからだけど、フォームヘルパーを使わなくてもフォームを生成できるなら正直どちらでやっても大差ないかなと」「確かにー」「最近Form Objectを使う人が減っているのはそういう理由もあるんじゃないかなー」「」「Form Objectの立ち位置はやや中途半端になりつつある感があるけど、個人的には全部サーバーサイドでやれるという点でForm Objectは好き」
Rails: 先週の改修(Rails公式ニュースより)
2週間分になってしまいました(´・ω・`)。
SQLite3アダプタの「ReadOnly」オプションに対応
アダプタ側で:readonly
オプションが追加されたことに対応したそうです。
# activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb#L15
module ActiveRecord
module ConnectionHandling # :nodoc:
def sqlite3_connection(config)
# Require database.
unless config[:database]
raise ArgumentError, "No database file specified. Missing argument: database"
end
# Allow database path relative to Rails.root, but only if the database
# path is not the special path that tells sqlite to build a database only
# in memory.
if ":memory:" != config[:database]
config[:database] = File.expand_path(config[:database], Rails.root) if defined?(Rails.root)
dirname = File.dirname(config[:database])
Dir.mkdir(dirname) unless File.directory?(dirname)
end
+ db_opts = config.symbolize_keys.merge(results_as_hash: true)
+
db = SQLite3::Database.new(
config[:database].to_s,
- results_as_hash: true
+ db_opts
)
...
#translate
メソッドが_html
サフィックスに対応
translate
(t
)メソッドでは_html
サフィックスが無視されていたために、html_safe
を使うべきでない場所でもhtml_safe
が乱用されがちだった。このPRでは訳文の配列のキーに_html
サフィックスがある場合にhtml_safe
をサポートする。
同PRより大意
# actionview/lib/action_view/helpers/translation_helper.rb#L60
def translate(key, options = {})
options = options.dup
has_default = options.has_key?(:default)
remaining_defaults = Array(options.delete(:default)).compact
...
if html_safe_translation_key?(key)
html_safe_options = options.dup
options.except(*I18n::RESERVED_KEYS).each do |name, value|
unless name == :count && value.is_a?(Numeric)
html_safe_options[name] = ERB::Util.html_escape(value.to_s)
end
end
translation = I18n.translate(scope_key_by_partial(key), html_safe_options.merge(raise: i18n_raise))
-
- translation.respond_to?(:html_safe) ? translation.html_safe : translation
+ if translation.respond_to?(:map)
+ translation.map { |element| element.respond_to?(:html_safe) ? element.html_safe : element }
+ else
+ translation.respond_to?(:html_safe) ? translation.html_safe : translation
+ end
else
I18n.translate(scope_key_by_partial(key), options.merge(raise: i18n_raise))
end
つっつきボイス: 「arrayに対してtranslate
するとhtml_safe
されてなかった…これはバグですねしかも場合によってはですが割とアブナイ」「」「yaml由来の内部データをtranslate
で変換するなら基本的に大丈夫だけど、yamlじゃなくてデータベースに入れて運用してたりする場合は要注意」
rails notes
コマンドの変更と一部非推奨化
- PR: Adds `Rails::Command::NotesCommand` and makes `rake notes` use it under the hood by anniecodes · Pull Request #33220 · rails/rails
-
rails notes:custom ANNOTATION=custom
がrails notes --annotations custom
を変更 rails notes:custom
、rails notes:fixme
、rails notes:todo
、rails notes:optimize
を非推奨化rake
からのnotes
コマンド呼び出しを非推奨化
つっつきボイス: 「rails notes
コマンドってそもそも初めて知りました」「ワイも: あー、これはFIXME
みたいなコメントも拾えるやつか: JetBrainsのIDEを長年使っている自分としてはIDEで簡単にチェックできるから直接使うことはまずないかなー」 「確かにー」
「まあコマンドでこういうコメントをチェックできるということは、たとえばCIサーバーなんかでFIXME
があったらマージを許さないように設定するみたいな使い方はあるかもですね」「」
新規にアップロードされたファイルを代入時ではなくsave時に保存するようになった
24ファイルも変更されています。
従来、アップロード済みファイルが
has_one_attached
やhas_many_attached
で追加されたライターメソッドによってレコードに代入されると、即座にストレージで永続化されていた。たとえば以下ではparams[:avatar]
内のアップロード済みファイルが保存対象になっていた。
@user.avatar = params[:avatar]
レコードに追加されたblobのバリデーションをサポートしたいが、無効なファイルの保存を防がないとまともなバリデーションができない。ファイルがストレージに投げられた後で無効だとわかってもほとんど意味がない。AWSの請求額を抑えるために事前にファイルサイズのバリデーションを行いたくても、バリデーション前にファイルが保存されてしまえばコストを削減できない。
このPRでは、レコードに代入されたattachableのActive Storegeへの保存を、即座にではなくレコードのsave後に行うようになる。そのためにActive Storageの添付ファイルのトラッキングを導入し、上述のライターメソッドが使われるときにレコード内の添付ファイルの変更保留をトラッキングする。この変更はレコードがsaveされるとアプリのデータベースで永続化され、関連するattachableはsaveトランザクションがコミットされたときに初めてストレージにアップロードされる。
ついでに添付ファイルAPIのテストを追加/再編成しておいた。
同PRより大意
つっつきボイス: 「テンポラリの添付ファイルをどのタイミングで永続化するかはいつも悩ましい問題ですね」「AWSの課金にも影響するでしょうし」「そっちよりはむしろゴミファイルが残ることなんかの方が問題でしょうね: 添付ファイルがテンポラリ領域にある限りは消し忘れても後で消えてくれるんですが、保存のタイミングが早すぎるとその後でエラーが起きたときにひとりでに消えてくれないし」「そっかー」
Railsのログの標準出力へのリダイレクトの挙動を上書きできるようにした
// productionでも標準出力をオンにする
rails server -e production -l
// developmentで標準出力をオフにする
rails server -e development -l false
# railties/lib/rails/commands/server/server_command.rb#L165
def server_options
{
user_supplied_options: user_supplied_options,
server: using,
- log_stdout: @log_stdout,
+ log_stdout: log_to_stdout?,
Port: port,
Host: host,
DoNotReverseLookup: true,
...
options[:early_hints]
end
+ def log_to_stdout?
+ options.fetch(:log_to_stdout) do
+ options[:daemon].blank? && environment == "development"
+ end
+ end
つっつきボイス: 「rails server -l
が使えるようになるのね、なるほどなるほど」
和暦にも使えるlabels_for_year_options
オプションをdate_select
に追加
kamipoさんのPRです。
# 同PRより
date_select('user_birthday', '', start_year: 1998, end_year: 2000, labels_for_year_options: ->year { "Heisei #{ year - 1988 }" })
<select id="user_birthday__1i" name="user_birthday[(1i)]">
<option value="1998">Heisei 10</option>
<option value="1999">Heisei 11</option>
<option value="2000">Heisei 12</option>
</select>
/* 略 */
つっつきボイス: 「これは個人的におおっと思っちゃいました」「ははー、年号のステップを刻めるようにしたってことか: 年号は和暦でも何でもお好きなものをどうぞってことで」「」「lambdaが使えるってのは結構よさそう」
「和暦というか元号対応って細かいところがいろいろ面倒なんですよねー: やったことあります?」「もうライブラリに任せてますー」「」「さりげに面倒なのが『平成1年』だけ『平成元年』って表示しないといけない場合: 『昭和64年』→『平成元年』の方はたいていのライブラリで対応できるんですけど、『平成1年』=『平成元年』の方を正規表現で無理やり何とかしようとしてもたまにカバーできなかったりとか: ちなみに上のコード例もそこは未対応ですね」「つらそう…」「我ながら何やってるんだろうと思いながら」「次の年号でもその手の対応が必要なところは多そうですね」
「あそうそう、その名もwareki
っていうgemありますよ」「欲しい人絶対いますよねー」「全元号対応といいつつそこまでではなかった気もするけど…あー今見ると対応元号めちゃ増えてる!」「ホントだー: マニア御用達の皇紀まであるし」「」「」「しかもいつの間にか1年=元年も対応してるし: やるなー」「うるうの表示まであるし」「元号対応を自前で実装するぐらいならwareki
を使うべき」
- リポジトリ: sugi/wareki — ruby 向け和暦ライブラリ。和暦と標準Dateの双方向変換をサポート。全元号対応。
# 同リポジトリより
require 'wareki'
Date.today.strftime("%JF") # => "平成二十七年八月二十二日"
Date.civil(1311, 7, 20).strftime("%JF") # => "応長元年閏六月四日"
Date.today.to_wareki_date # => Wareki::Date インスタンス
Wareki::Date.new("明治", 8, 2, 1).to_date # => 標準 Date インスタンス 1875-02-01
Wareki::Date.parse("正嘉元年 うるう3月 12日") # => Wareki::Date インスタンス
Date.parse("正嘉元年 うるう3月 12日)" # => 標準 Date インスタンス 1257-04-27
HTTP Cache-Controlサポートを追加
# actionpack/lib/action_dispatch/http/cache.rb#L205
- extras = control[:extras]
+ extras = control[:extras]
max_age = control[:max_age]
+ stale_while_revalidate = control[:stale_while_revalidate]
+ stale_if_error = control[:stale_if_error]
options = []
options << "max-age=#{max_age.to_i}" if max_age
options << (control[:public] ? PUBLIC : PRIVATE)
options << MUST_REVALIDATE if control[:must_revalidate]
+ options << "stale-while-revalidate=#{stale_while_revalidate.to_i}" if stale_while_revalidate
+ options << "stale-if-error=#{stale_if_error.to_i}" if stale_if_error
options.concat(extras) if extras
つっつきボイス: 「Cache-Controlヘッダサポートがさらに追加されたのか: stale-while-revalidate
とかstale-if-error
とか初めて見たし」
参考: RFC 5861 - HTTP Cache-Control Extensions for Stale Content
ActiveRecord::Relation#pluck
のメモリ割り当てを削減
# activerecord/lib/active_record/result.rb#L99
def cast_values(type_overrides = {}) # :nodoc:
- types = columns.map { |name| column_type(name, type_overrides) }
- result = rows.map do |values|
- types.zip(values).map { |type, value| type.deserialize(value) }
- end
+ if columns.one?
+ # Separated to avoid allocating an array per row
+
+ type = column_type(columns.first, type_overrides)
- columns.one? ? result.map!(&:first) : result
+ rows.map do |(value)|
+ type.deserialize(value)
+ end
+ else
+ types = columns.map { |name| column_type(name, type_overrides) }
+
+ rows.map do |values|
+ Array.new(values.size) { |i| types[i].deserialize(values[i]) }
+ end
+ end
end
つっつきボイス: 「#pluck
はよく使われるし、この最適化はありですね」
サービスURLのデフォルト期限をカスタマイズ可能にした
# activestorage/app/controllers/active_storage/blobs_controller.rb#L10
def show
- expires_in ActiveStorage::Blob.service.url_expires_in
+ expires_in ActiveStorage.service_urls_expire_in
redirect_to @blob.service_url(disposition: params[:disposition])
end
つっつきボイス: 「これはActiveStorageのファイルの置き場所のURLですね: それをサービスURLと呼んでるってことか」「ローカルならfile://
とかだったり」
AC::Parametersのtransform_values
の結果を修正
# actionpack/lib/action_controller/metal/strong_parameters.rb#L642
- def transform_values(&block)
- if block
- new_instance_with_inherited_permitted_status(
- @parameters.transform_values(&block)
- )
- else
- @parameters.transform_values
- end
+ def transform_values
+ return to_enum(:transform_values) unless block_given?
+ new_instance_with_inherited_permitted_status(
+ @parameters.transform_values { |v| yield convert_value_to_parameters(v) }
+ )
end
# Performs values transformation and returns the altered
# <tt>ActionController::Parameters</tt> instance.
- def transform_values!(&block)
- @parameters.transform_values!(&block)
+ def transform_values!
+ return to_enum(:transform_values!) unless block_given?
+ @parameters.transform_values! { |v| yield convert_value_to_parameters(v) }
self
end
つっつきボイス: 「AC=ActionController」「テストにassert_kind_of
がある↓ってことは、これまでの挙動がバグだったってことか」「おー」
# actionpack/test/controller/parameters/accessors_test.rb#L193
+ test "transform_values converts hashes to parameters" do
+ @params.transform_values do |value|
+ assert_kind_of ActionController::Parameters, value
+ value
+ end
+ end
+
+ test "transform_values without block yieds an enumerator" do
+ assert_kind_of Enumerator, @params.transform_values
+ end
+
+ test "transform_values! converts hashes to parameters" do
+ @params.transform_values! do |value|
+ assert_kind_of ActionController::Parameters, value
+ end
+ end
+
+ test "transform_values! without block yields an enumerator" do
+ assert_kind_of Enumerator, @params.transform_values!
+ end
touch
オプションの振る舞いをPersistence#touch
に合わせた
これもkamipoさんです。
increment!
(#27660)とupdate_counters
(#26995)に追加されたtouch
オプションの挙動がPersistence#touch
と同じでない。
touch
オプションを属性名に渡しても、Persistence#touch
のようにupdate_at
やupdate_on
属性が更新されない。
Persistence#touch
がincrement!
とtouch
オプションに変更されたために、counter_cache
で属性名が渡されるtouch
オプションでupdate_at
やupdate_on
属性が更新されないという問題が#31405で再発した。
この不整合は意図したものではないと思われるため、touch
オプションでupdate_at
やupdate_on
属性が更新されるようにして不整合を解消する。
同PRより大意
ちょうどRailsdmの動画でもkamipoさんがこのあたりに言及していました。
つっつきボイス: 「touch
はUnixのtouch
コマンド↓のアナロジーでしょうか?」「Railsのはupdate_at
なんかを強制的に適用やつなので、由来はたぶんそうですね: カウンタキャッシュのアップデートなんかにも使うし」
Rails
「データドリブンエンジニアリング」とは
つっつきボイス: 「Code Climateの久々の記事だったので」「定量的なデータを元に改善を着実に進めていこうっていう趣旨みたい」「Data-Driven Engineeringと対になる概念がNarrative-Driven(ストーリーに基づく)ってことみたいで、それよりもメリットが大きいぞってことですね」「上の認知バイアスのチャート、面白そうだけどめっちゃ細かくて読みづらい」
認知バイアス(にんちバイアス、英: cognitive bias)とは、認知心理学や社会心理学での様々な観察者効果の一種であり、非常に基本的な統計学的な誤り、社会的帰属の誤り、記憶の誤り(虚偽記憶)など人間が犯しやすい問題である。
Wikipediaより
Active Recordの読み書きを洗練させる
# 同記事より
class Product < ApplicationRecord
# executed daily
def self.recompute!
where("
announce_on = :today OR
preorder_on = :today OR
publication_on = :today
", today: Date.current).find_each do |p|
p.recompute_dependent_columns
p.save!
end
end
def self.visible
where(is_visible: true)
end
def self.buyable
where(is_buyable: true)
end
def visible?
is_visible?
end
def buyable?
is_buyable?
end
def publication_on=(val)
super.tap{ recompute_dependent_columns }
end
def preorder_on=(val)
super.tap{ recompute_dependent_columns }
end
def announce_on=(val)
super.tap{ recompute_dependent_columns }
end
def recompute_dependent_columns
self.is_buyable = [
preorder_on,
publication_on
].reject(&:nil).min <= Date.current
self.is_visible = [
announce_on,
preorder_on,
publication_on
].reject(&:nil).min <= Date.current
end
end
つっつきボイス: 「普通の書き方、書くのは少し面倒だけど読みやすい書き方、さらにシンプルな書き方↑という順序で説明しています」「ふむむー、気持ちはわかるけど最終的なコードを見た感じはちょっとオーバーキルだよなー: と思ったら記事にも同じこと書いてるし↓w」「」「」
Depending on your preferences this might seem even easier than the previous solution. Or, it might look ugly or like an over-kill.
同記事より
ActiveRecordとArelでクエリの流れを追う(Ruby Weeklyより)
つっつきボイス: 「いいこと書いてありそうなタイトルだったので」「ふむむー、ARとArelの関係をもっと掘り下げるのかなと思ったら#to_sql
すればだいたいわかるようなチュートリアル的内容ですね」「その分初級中級向けにはいいのかも?」
Apache SolrとElasticsearchを比較する
2018年5月のおすすめ情報↓
- Solrはこんなときに
- Javaプログラマーが多い
- ZooKeeperを既に使ってる
- Javaを既に使ってる
- 特定のニュアンスの関連度が必要な検索アプリを作る
- eコマース/求人情報/製品の検索エンジンを作る
- 検索機能を機能やエクスペリエンスの中心に据えたい
- Elasticseachはこんなときに
- Ruby/PHP/Pythonフルスタックプログラマが多い
- JSONがないと生きていけない
- Kibana/ELKでログを管理している
- 分析機能が中心のアプリ
- 悩み中の人に
- 私がこれまで手がけた高度な検索アプリはどれも検索ワークフローをカスタマイズ/チューニングしないといけなかったし、現時点でもElasticsearchはそのためにがっつりハックが必要。迷ったらSolrをどぞ。
つっつきボイス: 「solr-vs-elasticsearch.comってドメインをわざわざ取ってたので」「最近こういう感じのドメイン名を使ったサイトちょくちょく見かけますね」「どういうときにどっちを選ぶかという目安を上に雑に訳してみました↑」「だいたいこのとおりで、Solrは検索エンジンを自分たちで作るという要素が強くて、Elasticsearchはデータ処理系につなぐときに結構便利」「サービスの中核としてカスタム検索エンジンが欲しいときはSolr、Elasticsearchはカスタマイズが大変って書いてますね」「カスタマイズしたいならSolrでないとつらい: でも現場レベルではデフォルトで使う方が多いですけどね」
Cucumberをおすすめしない理由(Ruby Weeklyより)
このCode with Jasonというサイトはよさそうでした。
- サイト: Cucumber
つっつきボイス: 「Cucumberへのヘイトがたまってそうな記事でした」「Cucumberはねー、英語ネイティブにとってはまだいいんですが日本語でテスト書こうとするともろに地獄」「やっぱりー」「日本語で書くならturnip↓の方がまだまともに書けた気がする: 一応更新もされてるみたいだし」「turnip、以前使ったことあったそういえば」「ま、今ならシステムテストでいいんじゃね?って思うけど」
- リポジトリ: jnicklas/turnip
コントローラアクションのパフォーマンス改善記事とORMパフォーマンス測定論文(RubyFlowより)
- 元記事: Part I: How not to structure your database-backed web apps
- 論文: How not to structure your database-backed web applications: a study of performance bugs in the wild
つっつきボイス: 「上の論文を記事の方で絶賛しつつ引用していたので」「ICSE(International Conference on Software Engineering) 2018の論文か: ICSEの位置付けが知りたいなー」
- サイト: ICSE Home Page
「(しばらくググって)ざざっと調べた感じICSEはランキングも割と高いしかなりちゃんとしたカンファレンスみたい」「おー、そうやって信頼度を調べるんですね」「あんまりマイナーなカンファレンスの論文をありがたがって読んでもしょうがないんで」
- サイト: * ICSE 2018 * — スウェーデンのヨーテボリ(Gothenburg)で5月に開催されたそうです。
「アブストラクトをざっと見たところ、ORMのいくつかの実装についてパフォーマンスを計測・調査した論文ですねこれは」「」「しかもこれかなり面白そう: 会議論文として査読も通ってるはずだし、時間のある人はちゃんと読むととても参考になるんじゃないかな」「おー」
「で記事の方はコントローラのアクションのパフォーマンスを落とすアンチパターンとそれを特定する方法についてみたいです」「Scoutで測定してますね」「そういえば以前ウォッチでも取り上げたことありました」
switch_point: master/slaveデータベース接続で負荷分散
- リポジトリ: eagletmt/switch_point
つっつきボイス: 「お、switch_point」「今日のBPS社内勉強会で言及されてたので」「↓図を見れば一目瞭然ですが、たとえばslaveデータベースはリードオンリーで、masterデータベースは書き込み可能でというふうにできる: しかもuse_switch_point
でモデルごとに接続先を指定できる↓のが地味に便利」「使いみちは?」「レプリカに対して使うものなので、基本は負荷分散のためですね: メンテもされているはずだし結構優秀なgemです」「」
# 同リポジトリより
class Article < ActiveRecord::Base
use_switch_point :blog
end
class Category < ActiveRecord::Base
use_switch_point :blog
end
class Comment < ActiveRecord::Base
use_switch_point :comment
end
「以前はActiveRecordのデータベース接続はグローバルにしか持てなかったのでswitch_point
みたいなものを使わないとこういうことがまともにできなかったんですが、確かRails 5.1のあたりでデータベース接続を複数持てるようになったので以前よりはやりやすくなってるはず」
久々のを進呈いたします。おめでとうございます。
その他Rails
- 元記事: Rails API + JWT auth + VueJS SPA: Part 3, Passwords and Tokens management(RubyFlowより)
- 元記事: 11 Books Every Ruby on Rails Developer Should Read | Netguru Blog on Ruby/Ruby on Rails(RubyFlowより)
- 元記事: How to Learn Ruby on Rails in 2018, the Ultimate Guide - Mix & Go(RubyFlowより)
- 元記事: JavaScript-sprinkled Rails Applications | AppSignal Blog
- Podcast: RR 353: Removing Business Logic from Rails Controllers with Aaron Sumner | Devchat.tv
Ruby trunkより
Rubyのパターンマッチング構文の提案
# 同issueより
case expr
in pat [if|unless cond]
...
in pat [if|unless cond]
...
else
...
end
pat: var # Variable pattern. It matches any value, and binds the variable name to that value.
| literal # Value pattern. The pattern matches an object such that pattern === object.
| Constant # Ditto.
| var_ # Ditto. It is equivalent to pin operator in Elixir.
| (pat, ..., *var, pat, ..., id:, id: pat, ..., **var) # Deconstructing pattern. See below for more details.
| pat(pat, ...) # Ditto. Syntactic sugar of (pat, pat, ...).
| pat, ... # Ditto. You can omit the parenthesis (top-level only).
| pat | pat | ... # Alternative pattern. The pattern matches if any of pats match.
| pat => var # As pattern. Bind the variable to the value if pat match.
# one-liner version
$(pat, ...) = expr # Deconstructing pattern.
つっつきボイス: 「zverokさんもパターンマッチングを提案してましたが、これは別の方でした」「あー、Rubyコードに対するパターンマッチ式を記述する構文を作ろうみたいな話ね」「zverokさんのときもMatzが『やるならなるべくいい構文にすべき』ってissueに書いてたと思います」「構文が変わるとなるとあのめちゃ長いparser.yとの格闘がつらそう」
zverokさんの記事は近々翻訳を公開します。
Ruby
Staytus: アプリのステータスを表示するサービス(Ruby Weeklyより)
- サイト: The Open Source Status Site - Staytus
- リポジトリ: adamcooke/staytus
- デモ: Welcome - The Widgets Status Site
つっつきボイス: 「Staytusは『ステータス』と読ませたいみたい?」「あーなるほど、AWSのService Health Dashboard)↓みたいなのを表示できるサービスってことね」「ですです: 自分で作り込むよりは楽そう」「値段次第ですね」
Bash/Zshのタブ補完をRubyで書く(Ruby Weeklyより)
# 同記事より
def matches(command_line)
prepare_argv!(command_line)
parse_and_consume_options!
project_name_prefix = extract_project_name_prefix
project_names = find_project_names
filtered_names = filter_names(project_names, project_name_prefix)
puts filtered_names
rescue GetoptLong::InvalidOption
# getoptlong prints the error automatically
exit(1)
rescue => error
STDERR.puts error.message
exit(1)
end
つっつきボイス: 「Gobyのコントリビュータのsaveriomiroddiさんの記事だったので拾ってみました」「これは何をしようとしてるのかな…?ははあ、Bashとかのタブ補完をRubyで書いているのかなるほど: 自分でタブ補完書いてみたい人に」
Wkhtmltopdfは有害(RubyFlowより)
- 元記事: Wkhtmltopdf Considered Harmful
- サイト: wkhtmltopdf
つっつきボイス: 「Wkhtmltopdfって私は知りませんでしたが、昔からあるヤツですか?」「ですです: これ今でも使ってる人いるんだろうか」「ビルドが面倒とかJavaScriptがないとページ番号扱えないとかドキュメントが貧弱とかつらみが書かれてますね」「Wkhtmltopdfはマジ古くからあるからまあいろいろあるでしょうね: 一応速いんじゃなかったかな?」「よく見るとビルドにQtが必要って書いてある」「マジで!?」「QtのGUI表示は本当にきれいなんですがめちゃでかくてビルド大変」
- サイト: Qt | Cross-platform software development for embedded & desktop — Qtの発音は「キュート」だそうです
Rearmedシリーズ(RubyFlowより)
- リポジトリ: westonganger/rearmed-rb
- リポジトリ: westonganger/rearmed_rails
- リポジトリ: westonganger/rearmed-js
# westonganger/rearmed-rbより
hash.join{|k,v| "#{k}: #{v}\n"}
hash = {foo: 'foo', bar: 'bar', other: 'other'}
hash.only(:foo, :bar) # => {foo: 'foo'}
# or without monkey patch: Rearmed.hash_only(hash, :foo, :bar)
hash.only!(:foo, :bar)
hash.to_struct
# or without monkey patch: Rearmed.hash_to_struct(hash)
# Only monkey patched if using Ruby 2.2.x or below as this method was added to Ruby core in 2.3.0
items = [{foo: ['foo','bar']}, {test: 'thing'}]
items.dig(0, :foo, 1) # => 'bar'
# or without monkey patch: Rearmed.dig(items, 0, :foo, 1)
# Only monkey patched if using Ruby 2.3.x or below as this method was added to Ruby core in 2.4.0
hash.compact
# or without monkey patch: Rearmed.hash_compact(hash)
hash.compact!
つっつきボイス: 「これはどうやらActiveSupport的なものを自分で作ってみた感じ」「オレオレモンキーパッチというか」「RubyとRailsとJSとそれぞれ作ってますね」「業務で使うのはちょっと考えるなー: こういうパッチは割と簡単に書けますけどね」
フィボナッチヒープをRubyで実装(RubyFlowより)
- リポジトリ: mudge/fibonacci_heap
require 'fibonacci_heap'
heap = FibonacciHeap::Heap.new
foo = FibonacciHeap::Node.new(1, 'foo')
bar = FibonacciHeap::Node.new(0, 'bar')
baz = FibonacciHeap::Node.new(2, 'baz')
heap.insert(foo)
heap.insert(bar)
heap.insert(baz)
heap.pop
#=> #<FibonacciHeap::Node key=0 value="bar">
heap.decrease_key(baz, 0)
heap.pop
#=> #<FibonacciHeap::Node key=0 value="baz">
つっつきボイス: 「フィボナッチヒープというデータ構造をRubyで実装したそうで、ダイクストラアルゴリズムと相性がいいそうです」
参考: フィボナッチヒープ - Wikipedia
参考: ダイクストラ法 - Wikipedia
Ruby 2.6のString#split
はブロックを渡せる
# 同記事より
fruits = []
input_str = "apple, mango, potato, banana, cabbage, watermelon, grapes"
input_str.split(", ") { |value| fruits << value if is_fruit?(value) }
=> "apple, mango, potato, banana, cabbage, watermelon, grapes"
fruits
=> ["apple", "mango", "banana", "watermelon", "grapes"]
つっつきボイス: 「久々のBigBinaryさん記事でした」「おー、split
後の結果処理をブロックで渡せるのはナイスなショートハンドかも」「split
の後でeach
するよりラク」
mrubyの「Hakoniwa」とは
Link: Haconiwa for web development? : ruby: https://t.co/sAaSusWez7
— Yukihiro Matsumoto (@yukihiro_matz) July 18, 2018
# 同サイトより
Haconiwa::Base.define do |config|
config.name = "new-haconiwa001" # to be hostname
config.cgroup["cpu.shares"] = 2048
config.cgroup["memory.limit_in_bytes"] = "256M"
config.cgroup["pid.max"] = 1024
config.add_mount_point "/var/another/root/etc", to: "/var/your_rootfs/etc", readonly: true
config.add_mount_point "/var/another/root/home", to: "/var/your_rootfs/home"
config.mount_independent_procfs
config.chroot_to "/var/your_rootfs"
config.namespace.unshare "ipc"
config.namespace.unshare "uts"
config.namespace.unshare "mount"
config.namespace.unshare "pid"
config.capabilities.allow :all
config.capabilities.drop "cap_sys_admin"
end
つっつきボイス: 「Hakoniwaという名前がいかにもコンテナな感じ」「あーこれどこかで見たナ」「コンテナ設定をmrubyのDSLで書けるみたい」
クラウド/コンテナ/インフラ/Linux/Serverless
OpenAPI(旧Swagger)
- サイト: The Best APIs are Built with Swagger Tools | Swagger
- 仕様: About Swagger Specification | Documentation | Swagger | Swagger
つっつきボイス: 「Swaggerも今日のBPS社内勉強会で話題が出たので」「SwaggerというかOpenAPIはそろそろ知っておかないとヤバイですね: 使ったことはなくても名前ぐらいは押さえておきたい」
参考: Swaggerの概要をまとめてみた。 - Qiita
参考: Rails + swagger-blocks で OpenAPI 形式の API ドキュメントを作成する - Qiita
swagger: {自動} : 威張って歩く、自慢する
read
コマンドでパスワードを履歴に残さないようにする
つっつきボイス: 「read
コマンドを知りませんでした」「read
コマンドをバッチにすると知らずにそこで止まっちゃうことあるので個人的にはあまりこの使い方は好きではないです: バッチにするなら対話的なものは含めない方がいいと思うし」
参考: readコマンド(標準入力から読み込んで変数に格納する) : JP1/Advanced Shell
Amazon Translateに日本語など追加
// 同記事より
import boto3
translate = boto3.client("translate")
lang_flag_pairs = [("ja", "🇯🇵"), ("ru", "🇷🇺"),
("it", "🇮🇹"), ("zh-TW", "🇹🇼"),
("tr", "🇹🇷"), ("cs", "🇨🇿")]
for lang, flag in lang_flag_pairs:
print(flag)
print(translate.translate_text(
Text="Hello, World!",
SourceLanguageCode="en",
TargetLanguageCode=lang
)['TranslatedText'])
つっつきボイス: 「ほほーAmazon Translateなんてのがあるとは」「今ならこういうAPIがあっても不思議でない」「ちなみにこの手の機械翻訳をチェックする時は割と長めの文章を食わせて下の方を見るようにしてます: 長文の出だしは整ってても下に行くと崩壊しているとかよくあるので」「今なら翻訳エンジンも複数選べるし、候補のひとつとして押さえておくのはいいと思う」
SQL
pgmongo: MongoDBをPostgreSQLに置き換える(Postgres Weeklyより)
- リポジトリ: thomas4019/pgmongo
まだproduction readyではないとあります(´・ω・`)。
つっつきボイス: 「MongDBをポスグレに置き換えるってもしかしてJSONBに入れてるだけなんじゃ?と思ったらどうもそれっぽい↓」「」「」「どんな人が使うんだろか?」「うっかりMongoDBにしちゃったけどPostgreSQLに引き返したい人なんじゃ?やっぱり」「」「諦めて作り直す方が早いきっと」「諦めが肝心」
# 同リポジトリより
db.createCollection('users') -> CREATE TABLE IF NOT EXISTS "users" (data jsonb)
db.users.find({ lastLogin: { $lte: '2016' } }) -> SELECT data FROM "users" WHERE data->>'lastLogin'<='2016'
db.users.update({}, { $set: { active: true } }) -> UPDATE "users" SET data = jsonb_set(data,'{active}','true'::jsonb)
db.users.find({}, { firstName: 1 } ) -> SELECT jsonb_build_object('firstName', data->'firstName', '_id', data->'_id') as data FROM "users"
db.blogs.insert({ title: 'first post', comments: [] }) -> INSERT INTO "blogs" VALUES ('{"_id":"5b45b641eb4bd93896d57888","title":"first post","comments":[]}'::jsonb)
db.blogs.remove({ 'state.trash': true }) -> DELETE FROM "blogs" WHERE data->'state'->'trash'='true'::jsonb
JavaScript
JSXとは何か(JavaScript Weeklyより)
<!-- 同記事より -->
<div><span>Hello</span> <span>World</span></div>;
React.createElement("div", {
children: [
React.createElement("span", null, "Hello"),
" ",
React.createElement("span", null, "World")
]
});
// Note: babel uses the third argument for children:
React.createElement(
"div", // type
null, // props
// children are the rest:
React.createElement("span", null, "Hello"),
" ",
React.createElement("span", null, "World")
);
つっつきボイス: 「今更ですがJSXって何だったかなと思って」「JSXはReactと一緒に使うヤツで、前からありますよ: ただねー、JSXの記法↑は個人的にどうにもキモくて…この書き方どう思います?」「いやーそうでも…使ってみるとなかなかいいヤツですよ」「結構好みが分かれてるみたい」「長らくPHPやってからRubyに来たときに『カンマがない!』って思ったのとちょっと似てるかなーって」「そうですかー、自分は個人的にスクリプト全体が{ }
か何かで囲まれてないとシームレスすぎてどうにも不安になるんですよ: Reactで一番耐え難かったのがこのあたり」「どっちもわかるわー」「ズボンの下にパンツ穿いてない気持ちになりそう」「jQueryなんかでも書こうと思えばこうやって書けそうな気がしないでもない」「とはいえJSXって既にかなり普及してるし、今からBackbone.jsやるよりは全然いいですけどね」
参考: JSX - Wikipedia
追記
オッと思って読んだところ、ReactのJSXの話とDeNAが作ったJSXの話が混ざっている。前者の説明をしたかったんだろうなとは思う。 https://t.co/wlt4zgymE5
— しんのき (@konoki_nannoki) July 23, 2018
JSXがいくつもあったとは…失礼いたしました。https://jsx.github.io/がDeNAによるJSXというAltJS言語なんですね。
参考: 「JSX」って名前のものが色々あって混乱する - Qiita
CSS/HTML/フロントエンド/テスト
負荷テストツール8種比較(RubyFlowより)
以下のツールのメリットとデメリットが紹介されています。
- JMeter
- Locust
- Loader.io
- BlazeMeter
- Radview WebLOAD(有料)
- Micro Focus LoadRunner(有料)
- IBM Rational Performance Tester(有料)
- SmartBear LoadUI Pro(有料)
つっつきボイス: 「こういうツールの名前をとりあえず知っておくと後で探せますね」
「とりあえずJMeterは筆頭で歴史もとても長い: ちょうど最近BPSに入社したインフラエンジニアの人も今使ってますね」「おー」「そしてJMeterはめちゃめちゃ重いw」「重いんですか?負荷テストツールなのに?」「負荷テストやってるとたいていクライアントが先に音を上げて死ぬという: かなり強いサーバーをJMeterの負荷で落とそうとするとJMeterをクラスタ化したりしないといけなかったり」「はりゃー相打ちというか」「ただJMeterはプロキシモードで使えるというメリットがあって、JMeterのプロキシサーバー経由でブラウザ画面をぽちぽち操作するとその操作でシナリオを作れるんですよ」「それはありがたい」「負荷テストのちゃんとしたシナリオ、それもステートフルなシナリオが作りやすいのがJMeterのいいところ: まあ今ならRailsのシステムテストがあるからそっちでもやれますけどね」「」「それがなかった頃はJMeterは重宝しました」
「後はあんまり知らないなぁ…BlazeMeterはJMeterと連携できるのか…おや?よく使われるAB(Apache Benchmark)とかskipfishとかがこのリストにないなあ」「AB?また探しにくそうな」「ABはひたすらPOSTリクエストをもの凄いレートで投げられるんで、一瞬でサーバーを落とすことすら可能」「すげー!」「skipfishは?」「skipfishはGoogleのツールで、セキュリティチェックが主だから負荷テストとは少し違うといえば違うかな: WordPressサイトなんかを目がけてかければいろいろ結果を出してくれる」「へー!」
参考: ab - Apache HTTP server benchmarking tool - Apache HTTP Server Version 2.2
参考: セキュリティチェックツールskipfish入門 | apps-gcp.com
Zeplin: PhotoshopなしでPSD確認/コメント付け
- サイト: Zeplin
つっつきボイス: 「この間の新入社員歓迎会の席で話題になってたZeplinです: PhotoshopのPSDファイルをPhotoshopなしで開けるしコメントも付けられるしで、いつの間にかBPS社内で結構使われてるので」「ZeplinはWindows版もありますしね: この種のツールはSketchとかAdobe XDとかInVisionとか他にも山ほどあるんですが、最終的に大事なのはデザイナーが使っているツールときちんと連携できるかどうかがポイント」「そういえば今日も別のよく似たツールの話してたのに、そのツールの名前が思い出せない…」「何しろほんといっぱいあるから」「ともあれZeplinみたいなツールは、今やないとデザイナーと共同作業やってられないぐらいには必要ですね」
↓割とよく間違えられますがこれは「ヒンデンブルグ号」です。
参考: ヒンデンブルク号爆発事故 - Wikipedia
参考: ツェッペリン - Wikipedia
追いかけボイス: 「ちなみに類似ツールを探すときはツール名 alternative
でググると探しやすいです: こんなサイトもあったりしますし↓」
参考: Zeplin Alternatives and Similar Software - AlternativeTo.net
言語よろずの間
RubyistもElixirを学ぶべき理由(Ruby Weeklyより)
つっつきボイス: 「台湾だとRubyとElixirがよく合同でカンファレンスやってますよね」「ウォッチでも何度か取り上げました↓」
Artifact 2.0: Rustで書かれた設計ドキュメント化ツール
- 元記事: Artifact 2.0 Rust Full Stack Web And Cli Application
- リポジトリ: vitiral/artifact
- ドキュメント: Introduction - Simple Quality with Artifact
designという語を見ると「(ソフトウェア)設計」なのか「デザイン」なのか毎度身構えます。
つっつきボイス: 「こういうのはまず間違いなく『設計』でしょう」「ですよね」「↑プロモーション動画が凝ってる」
Go言語のガベージコレクタを徹底解説(公式ブログ)
つっつきボイス: 「Go言語のロゴが変わったからGopherくんいなくなったのかなー?可哀想に…と思ったらちゃんといた↓」「えかったえかった」「元はスライドみたいですがめちゃめちゃ長いです」
その他
VS IntelliCodeのAIサジェスチョンが強化
- 元記事: Visual Studio IntelliCode now infers coding conventions for consistent code | The Visual Studio Blog
つっつきボイス: 「何でも今回のアップデートではコーディング規約まで推測するらしくて: 『あなたのところはきっとこんなルールでやってるのよね』って感じで推測するのかなと」
「ちょうど今目についたんだけど、コーディング規約といえばEditorConfigに機能が増えるべきだよなと常々思ってる」「EditorConfig?: もしかしてそれってエディタを超えて使えるんですか?」「そうですよ、たぶんどのエディタでもこのファイルがあれば読み込んでくれる: 知りませんでした?」「知らなかったー」
- サイト: EditorConfig
# 同サイトより
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
# Matches multiple files with brace expansion notation
# Set default charset
[*.{js,py}]
charset = utf-8
# 4 space indentation
[*.py]
indent_style = space
indent_size = 4
# Tab indentation (no size specified)
[Makefile]
indent_style = tab
# Indentation override for all JS under lib directory
[lib/**.js]
indent_style = space
indent_size = 2
# Matches the exact files either package.json or .travis.yml
[{package.json,.travis.yml}]
indent_style = space
indent_size = 2
「標準のEditorConfigってシンプルなコンベンションしかなくて機能がまだまだ足りないんですよ: Rubyで言うなら通常の2スペースのインデントまではできても、行が長くなりすぎて折り返したときのインデント(コンティニュエーションインデント)を自分は4スペースにしてブロックと区別したいのにそれが設定できない: JetBrainsのIDEになら当然のようにある設定なのに…」「ありゃー」「EditorConfigは言語とも独立しているし汎用性重視だからだと思うんですけど、やっぱり物足りない」
参考: どんなエディタでもEditorConfigを使ってコードの統一性を高める - Qiita
参考: コーディングをAIが支援してくれる「Visual Studio IntelliCode」がアップデート。既存コードからコーディング規約を推測し、適切な設定ファイルを生成 - Publickey
新型Macbook Proはアツい?
参考: 新MacBook Pro+Core i9でマシンがアチアチになるとの報告 | ギズモード・ジャパン
つっつきボイス: 「さて新型Macbook Proに70万かけるべきかどうか」「高!」「それだけかけてもデスクトップマシンよりは速くならないだろうし」
番外
自転車向け新型シャフトドライブ
つっつきボイス: 「これは動画を見る方が早いです: 伝達効率99%がアツい」「へー」「大根をおろせそうなギアも」
参考: 斬新なギア構造が決め手! 動力の伝達効率が99%のシャフト・ドライブ自転車 | ギズモード・ジャパン
AIによる自律的殺人兵器非開発の誓約書
つっつきボイス: 「ターミネーターは作りません、みたいな?」
参考: 「AIによる自律的殺人兵器非開発の誓約書」発表。Google Deepmind設立者やイーロン・マスクら署名 - Engadget 日本版
今回は以上です。
バックナンバー(2018年度後半)
週刊Railsウォッチ(20180702)Ruby 2.2メンテ正式終了、Ransackがつらくなるとき、書籍『Domain-Driven Rails』、GitHubの高可用MySQLほか
- 20180622 Railsの需要未だ巨大、Unicode 11.0リリース、WebDriverがW3Cで勧告、Flutter.io、2封筒問題ほか
- 20180615 TTY gemとHTTPClient gemは優秀、Rubyの謎フリップフロップ、ちょいゆるRubyスタイルガイドほか
- 20180608 特集「RubyKaigi 2018後の祭り」、
Enumerable#index_with
は優秀、コントローラから@
を消し去るほか
今週の主なニュースソース
ソースの表記されていない項目は独自ルート(TwitterやRSSなど)です。