2018/12/21 気になった記事まとめ
2018年も年の瀬。今年は一時期エンジニアやってなかったり、転職したり、転職したてですぐ炎上してたりと、仕事面では刺激的な一年でした。来年はもっといい一年になるといいなぁ、と思う次第。
面白いの評価は難しい
記事の本文見て真っ先に考えたのは、「面白いをどう判断するか?」の部分ですねー。 ダジャレに絞って言えば、似たような音韻を重ねるという特徴があるのでいわゆる分かち書きでやってるのかな?と思いましたが、それだとうまく解析できないケースがあるんですね。
しかし、以前に比べて機械学習もかなり普及してきましたねー。ちょっとした学習モデルを作るくらいなら特に難しい数式を使わずにできるようになってきてますね。近々画像の分類周りで触る可能性があるので試してみなくちゃなー(´・ω・`)
複数環境を docker-composeしているときよく困る
可視化についての学び。こうしてすぐ試せる環境を作れるのもDockerの強さですね。DockerをECSでプロダクション運用する際のモニタリングに悩んでいたんですがこの辺参考にできそう。実際に自分で環境組んでみるのが一番効率よく理解できるので、年末年始でちょっと触ってみようかと思います。
非常に理解しやすい強化学習の実装面の話
強化学習の資料をいろいろ目にする機会はあったんですが、ダントツに理解しやすい資料ですね。あんまり知識ない人でもこれなら雰囲気掴めるんじゃないんでしょうか?しかし、学習のやり方もいろいろありますねー
USキーボードを使い始めて半年がたちました
以前から度々チャレンジして来てしっくりこなかったUSキーボード。7月の転職を機にUSキーボードに切り替えて半年使った結果、今では逆にUS以外だと操作がおぼつかなくなってます_(:3」∠_
今回使い始めたのも割と偶然で、それまで仕事で使っていたキーボードが寿命を迎え、新しく買い直す必要に迫られたんですよね。使いやすくて良いキーボードだったんですが、充電式電池の流通が減ってきたのと、基盤がヘタって電源切れたり入ったりを繰り返すようになったので廃棄処分(´・ω・`)
LOGICOOL ワイヤレス ソーラーキーボード K750r
- 出版社/メーカー: ロジクール
- 発売日: 2012/11/22
- メディア: Personal Computers
- この商品を含むブログ (3件) を見る
せっかく買うなら自宅と同じキーボードにしたくなるわけですよ。家と仕事の環境はなるべく合わせるの大事ですし(`・ω・´)
- 出版社/メーカー: FILCO
- 発売日: 2013/09/20
- メディア: Personal Computers
- この商品を含むブログを見る
今の会社に転職した翌々日くらいに時間に余裕ができたので秋葉原まで足を伸ばし、いくつかの店舗を覗いた結果、まあ普通にヨドバシが(ポイント加味したら)最安値なので、サクッと購入。 このキーボード、値段が比較的お安いんですがしっかりしたキーボードで、本体が重めでどっしりして安定して入力できるため、大変好みです。
購入した翌日、梱包そのままにして会社に持ち込み、出社後即開封を決めます。
USA Majestouch MINILA Air 67 Key Click Action Bluetooth Keyboard FFBT67MC/EB by Filco [並行輸入品]
- 出版社/メーカー: Diatec
- メディア: エレクトロニクス
- この商品を含むブログを見る
封を開けたら鎮座するUSキーボード( ゚д゚)
見事に買い間違えてました。新たな職場に投入される慣れないUS。一瞬返品しようと思ったんですが、ぶっちゃけ自分の過失で買い間違えた結果なので、申し訳なくそのまま使うことになったんですよね( ̄・ω・ ̄)
最初はキー配置が完全に頭に入ってなかったので、キートップを見ながら入力する始末だったわけなのですが、それを繰り返していった結果USの方が入力早くなりました、やはりITエンジニア稼業、記号入力がしやすいUSが大正義だったわけですね。(`・ω・´)
なれていないツールでも使い続ければ順応していくんだなぁ、と改めて感じた学び。あとはカーソルキー依存体質さえ脱せれば、気の迷いで買ったっきり使ってない、この変態キーボードも使えるようになるのではないか?
MiSTEL BAROCCO MD600 分離式 メカニカルキーボード 日本語配列 66キー CHERRY 静音赤軸 PBTキーキャップ ブラック MD600-PJPPSGAA1
- 出版社/メーカー: MiSTEL
- 発売日: 2017/10/19
- メディア: Personal Computers
- この商品を含むブログを見る
たぶん(´・ω・`)
2018/12/20 気になった記事まとめ
日課の投稿です。欠かさず習慣化大事( ・`ω・´)
うちの四歳児に期待して買ったことがある(´・ω・`)
うちも子どもにこれさせようと思って、ラズパイ3が鎮座しております_(:3」∠)_ 当時四歳児にはまだ無理でした。そりゃそうだ。小学校入った後くらいに再試行しようかと思ってます。
コンピュータの教育の取っ掛かりとしてとても良く説明された投稿ですね。( ・`ω・´)しかし、最近の子供達は何かと恵まれてますね。人類の進化が急速に発展していっている気がします。彼らが大人になったころにはどんな世の中になってるんでしょうかね?楽しみです。
プロダクトを運用している以上避けられないSREとの付き合い方
基本的な考え方や、何をするべきか?についてまとまっている記事。ここにはあんまり触れられはいませんでしたが、システム運用の自動化や運用フローの整備といった業務改善を積極的に行うことも含まれます。
そもそも問題が起きにくい作りにして信頼性を高める。意図的に(サービス影響ない程度の)障害を引き起こして常日頃から復旧に慣れておく。等、やるべきことは数多く(´・ω・`)
そういった体制や環境を常日頃整備して行けば、運用に手を取られずビジネス要件の開発に集中できるため、結果として安定した高速でリリースし続けられるプロダクト開発が実現できるようになります。
SRE サイトリライアビリティエンジニアリング ―Googleの信頼性を支えるエンジニアリングチーム
- 作者: 澤田武男,関根達夫,細川一茂,矢吹大輔,Betsy Beyer,Chris Jones,Jennifer Petoff,Niall Richard Murphy,Sky株式会社玉川竜司
- 出版社/メーカー: オライリージャパン
- 発売日: 2017/08/12
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る
家具のレンタルサービスって正直どうですか?
来年引っ越す予定なんですが、家具費用に回せるお金がなかった時に、一時的に使おうと思います。 購入だとどうしても気に入ったものが見つかるまで手が出せないんですが、これならテキトーに借りて生活しつつ、気にいるものが見つかったら即切り替え、みたいな使い方ができるかなぁと( ・`ω・´)
AuroraからOutfile S3で出力したpartファイルを1つに結合したかった話
# 本記事の環境 ruby: 2.5.0 Rails: 5.1
Amazon Auroraには、実行したクエリの結果をそのままS3に出力する機能があります。
Aurora v1.13くらいから使えるようになった機能で、弊チームではデータ分析基盤に流し込むために使っています。Selectした結果をTSVにしてS3として保存してくれるので、出力さえしてしまえば世の中の大方の分析環境で使えるのがいいですね( ・`ω・´)
実際に使うときは、こんな感じ(Aurora側にS3に吐き出すための権限が付与されているかつ、SQLの実行ユーザーにSELECT INTO S3のGrant設定をする必要があり。詳しくは↑のリンク)
SELECT * FROM table WHERE created_at > DATE_ADD(CURRENT_DATE(), interval 1 day) INTO OUTFILE S3 's3-us-west-2://bucket/dir/key' OVERWRITE ON
楽ちん。これだけでS3にファイルをはきだせるので、ちょっとしたデータをサクッと集めたいときに便利そうですね。
この機能を使って全テーブルの全データを一日1回S3に投げつけようとします。Railsであれば対象となるModelに対し、columnsを駆使してSQLを組み立てればいけます。
model = User query = <<~SQL SELECT #{model.columns.map(&:name).join(',') } FROM #{model.table_name} INTO OUTFILE S3 's3-us-west-2://bucket/dir/#{model.table_name}' OVERWRITE ON SQL model.connection.execute(query)
確かこんな感じで行けるはず( ・`ω・´)
適切な権限があり、Bucketが作成済みであればこれでS3にファイルが出力されます。17000行、6.2MBくらいのデータで出力に700msほど時間がかかりましたが、そこまで遅くはない印象。
今回の困ったこと
さて、今回の本題はここから。
この方法で、例えばbucket/dir/users
として出力した場合、実際には以下の名前で出力されます。
bucket/dir/users.part_00000
名前の後ろに勝手にpart_xxxxxがついてしまいます。S3への出力オプションを見ても制御する設定はなかったので、おそらく常にこの形式の名前で吐き出される模様(´・ω・`)
名前を見て想像できる通り、データセットのサイズが大きすぎる場合にファイル分割して出力されます。Amazonのドキュメントに記載されている内容をみると、
Amazon S3 バケットに書き込まれるファイルの数は、SELECT INTO OUTFILE S3 ステートメントで選択したデータの量と Aurora MySQL のファイルサイズのしきい値によって異なります。デフォルトのファイルサイズのしきい値は 6 GB です。ステートメントで選択したデータがファイルサイズのしきい値より少ない場合は、1 つのファイルが作成されます。それ以外の場合は、複数のファイルが作成されます。
とあり、6GBを閾値としてファイル分割するみたいです。
複数ファイルに分かれてしまう。特に事情がなければそのまま使ってもいいんですが、複数ファイルに分割すると分析基盤に取り込む際に考慮しなくてはいけないので、可能な限り1ファイルに固めたいもの。
そこで、マルチパートアップロード
S3には、大きすぎるファイルを転送する際、ファイルを複数に分割して送信しS3側で1つにまとめる『マルチパートアップロード』という機能がサポートされています。今回の1ファイルに固める際はこれを使います。
マルチパートは、基本的に以下の手順でファイル送信 + 結合を実現しているようです。
- AWS::S3::Client.create_multipart_uploadで、バケット名と出力ファイル名を渡す。実行結果として1つのMultipartを指すOrderIdが取得できる
- AWS::S3::Client.upload_partでファイルを送信する。保存できたらetagという固有のIDを返却する。
- ファイルをすべて転送した後、2で取得したetagとpart_numberを送信して、ファイルを結合する
これが基本の流れ。Auroraから吐き出したデータをこれに食わせて1ファイルに結合できればすべて解決できそうな気がします。Railsから試すには、gem aws-sdk-3
をGemfileに追加します。
まず、今回はAuroraからS3への出力を行っているため、ファイルが存在しています。2の工程はスキップできそうです。後、3の工程で必要なetagですが、以下のコードで取得できます。
def bucket @bucket ||= Aws::S3::Resource.new( client: ::Aws::S3::Client.new(region: "us-west-2") ).bucket("bucket") end # キー名をprefixに指定すると、.part_xxxxxの要素が引っかかる。それのetagとpart_number etag_and_partnum = bucket.objects(prefix: "dir/users").to_a.map{|obj| {etag: obj.etag, part_number: obj.key.match("\d+$").to_s.to_i})
この取得したetag指定してmultipartを実行します。
shared_options = { bucket: bucket.name, key: "dir/users" } create_result = bucket.client.create_multipart_upload(shared_options) # complete_multipart_upload: https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Client.html#complete_multipart_upload-instance_method bucket.client.complete_multipart_upload( shared_options.merge( multipart_upload: { parts: etag_and_partnum }, upload_id: create_result.upload_id ) )
これでいけるかと思いきや、無残に失敗します(´・ω・`)マルチパートのetagじゃないぞ、というお怒りだったはず。
やはり正しく1,2,3の工程を実施する必要はありそうです。upload_partでファイルを送信し直すなんで、なんのためにOutfile S3をやったのかという気持ちになりますね(´・ω・`)
そんな折、こんなQiitaをみつけました。
つまり、upload_part_copyメソッドを用いて、バケットに存在するOutfile S3で出力したファイルをcopy_sourceに指定することで、改めてファイルを送信せずに目的にことが実現できる、ということになります。
最終的に、以下のコードで実現できました。
def join_multipart_object(s3_path_key) # upload_part_copyのcopy_source指定のため、出力キーの一覧を取得しておく upload_object_keys = bucket.objects(prefix: s3_path_key).to_a.map(&:key) return if upload_object_keys.blank? shared_options = { bucket: bucket_name, key: s3_path_key } crete_result = bucket.client.create_multipart_upload(shared_options) begin # 一度上げたものを結合することはできないので、コピーを元に生成する etag_and_partnum = upload_object_keys.map.with_index(1) do |updated_key, idx| upload_result = bucket.client.upload_part_copy( shared_options.merge( copy_source: "#{bucket.name}/#{updated_key}", part_number: idx, upload_id: crete_result.upload_id ) ) {etag: upload_result.copy_part_result.etag, part_number: idx} end # 分割したファイルを結合する bucket.client.complete_multipart_upload( shared_options.merge( multipart_upload: { parts: etag_and_partnum }, upload_id: crete_result.upload_id ) ) rescue # 処理失敗の場合は、abortを叩いてマルチパートを終了させる bucket.client.abort_multipart_upload( shared_options.merge(upload_id: part_struct.upload_id) ) raise $! end # マルチパートを合成したら、元のファイルを削除して完了 bucket.delete_objects( delete: { objects: upload_object_keys.map { |key| {key: key} } } ) end def bucket @bucket ||= Aws::S3::Resource.new( client: ::Aws::S3::Client.new(region: "us-west-2") ).bucket("bucket") end
2018/12/18 気になった記事まとめ
ここ数日の日経の調子が良くなく、私の懐具合も寂しくなってきました_(:3」∠)_含み損がっ!
バッチ高速化よくあるネタ
遅いバッチの理由の割と大きな部分を占める、配列のincludesが大量に呼ばれる問題。よくありますね(´・ω・`)前職でも散々振り回されました。
要素数が増えるに従って線形に遅くなっていくんですよね...大方Hashにすれば改善されるのもよくある話で。
しかしDTrace便利ですね。Stackprofとか言う手もありますが、Dtraceはプロセスに対して外から計測できるのがポイント高い。あ、調べたいな、と思ったときに即取れるのは強い(`・ω・´)
サクッと社内ツールを作るのに使えそうなjavascriptライブラリ
自力で実装しようとするとかなり大変な機能がサクッと適用できるのはありがたいですね。前職ではw2uiとか使っていたんですが、あれもそれなりに便利でしたねー。
ただ使い勝手とか見るに、tabulatorの方がモダンで良さげです。新しくなにか作るときはこれ使うと思います。
セキュリティコードの入力制限は意味を持ちませんでした(´・ω・`)
Visaカードの有効期限やセキュリティコードを数秒で割り出す「分散型推測攻撃」 - CIOニュース:CIO Magazine
PayPayの不正利用等で話題になっていた施行回数制限。複数のWEBサービスに分散させて処理させればいくら1サービスで制限かけても意味がないという記事。カードブランドのシステム単位で制限しないと結局は何度も施行されてしまいますな(´・ω・`)
なお、MasterCardだけは一元管理しているらしく、並行して複数のサイドでセキュリティコードトライしても弾いてくれるそうです。
2018/12/17 気になった記事まとめ
特に書くことがないときの日課です。 今年もあと数日出勤すれば終わりという現実が見え隠れしており、一年すぎるのマジ早くなったなーと感じる次第です。(´・ω・`)
アカウント削除をどう考えるのか
意味がない、という記事。実際にはデータの保持義務なりいろいろあるので、完全削除は現実難しいですな。論理フラグが良い、実削除が良い、と色々意見がある話ではあるのですが、一番は、
ユーザーは退会してどうなってほしいのか?
を真っ先に考えることですかね。サービスなりシステムを提供している相手が一番メリットを感じられることをやることを目指しましょう、というのが私の考え方です。
なので、自分なら
- 決済履歴等、保持義務があるものはそのまま保持
- 保持期限なくても、後から返金できるか?みたいな問い合わせくることあるのでつらい
- サービス利用に関わる情報で個人が特定できる情報をマスクして、履歴を別ディスクに退避(例えばS3)
みたいにやるんじゃないかなーと考えてます。
Non-attribute arguments will be disallowed in Rails 6.0
えっ?
この記事で知りました(´・ω・`) 記事の内容より、タイトルで上げたことが気になって仕方ありません。あんまり使ってる所ないとはいえ、全部書き換えるの面倒だなぁ_(:3」∠)_というお気持ちに。
記事の本文についてですが、結論、SQLインジェクションを防ぐために、paramsの値を直接where条件に突っ込むのやめましょうねーって話だと認識してます。
入力値は必ずFormオブジェクトを作成してvalidationし、そこから引っ張る形を取るようにしています。あとでテストも書きやすいのでおすすめです。
class xxxForm include ActiveModel::Model include ActiveModel::Attributes attribute :aaa, Integer attribute :bbb, String validates :aaa, presence: true, numericality: {only_integer: true, greater_than_or_equal_to: 0} validates :bbb, presence: true def initaialize(**params) params.each {|k, v| send("#{k}=", v) } end end # controller if (form = xxxForm.new(params)).invalid? raise InvalidParamError(form.errors) end
多分こんな感じ(動かしてない)
キモは事前に入力値を検証して正しいものだけ通す。これができていれば後工程で雑に扱ってもある程度は防げると思います。ただし、文字列をActiveRecordの条件式にする場合はちゃんとplaceholder を使いましょう(´・ω・`)インジェクションこわい
機械学習のコスト計算で考えたいこと
学習はGPUほぼ必須なのは理解していましたが、学習結果を元に推論するだけならCPUで十分いけるんですね、という学びがありました( ・`ω・´)
それにしても1500万/yearの削減は凄まじいですね。わりとコスト計算おざなりになりがちなので、必要十分な性能をうまく見極められるスキルがほしいですねー(´・ω・`)
トランザクションとか、クラッシュ時対応とか、胃が痛くなりそうな設計
個人開発であれば、この内容でも、まあ動くとは思います。自分はやりたくないけど。
バックアップとかどうしてるんですかねー。巨大なしかも書き込みロックされているcsvをまんまコピーとか、タイミング次第では地獄を見そうな予感しかしないんですが_(:3」∠)_
とあるユーザーの決済履歴の一覧を表示させたいとして、どうやって探すんでしょうかね。全文検索ですかね。
と、いろいろつらみを感じさせそうな設計。何事もなく運用できることを祈ってあげたいお気持ちです。
リーン開発での『決定を遅らせる』がやっと理解できた話
リーン開発を学ぶ状況において、これまであんまり理解しきれてなかったものに、『決定を遅らせる』があります。
これ字面だけ見て全く意味が読み込めなかったんですよねー(´・ω・`) え?意思決定を遅れさせるってどういうことさ?
そのヒントはこの本にありました。
エンジニアリング組織論への招待 ~不確実性に向き合う思考と組織のリファクタリング
- 作者: 広木大地
- 出版社/メーカー: 技術評論社
- 発売日: 2018/02/22
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (2件) を見る
今年の春先くらいに話題になった本ですね。買ったっきり積読してたのですが、何気なく開いた先に知りたかったことが書かれてました。└('ω')┘いいですね。
本書では『決定を遅らせる』(本書では、遅延した意思決定、と表記)を説明するのに、ポジション取引の例が使われていました。先物取引とか呼ばれるアレです。株とか詳しくない人向けに雑な説明をすると、実際の商品を取引するのではなく、将来の売買する権利を扱うものですね。権利の償却時期が来たときに、その時の相場などを見て最終的な買う買わないの選択ができます。
すぐに商品買ってしまうより、後から買える権利だけを買っておいて、実際に儲けが出るときだけ取引すればよい。これをプロダクト開発に当てはめてみます。
- すぐ決定する場合
- 開発するプロダクトの内容が決まり、すぐに開発開始します。人的リソースを最初から大量投入して、素早く製品をリリースします。
- 『決定を遅らせる』場合
- 開発するプロダクトの内容が決まり、顧客ニーズや価値を測れる最低限の機能だけを、数人で作り試します。試した結果うまくいく感覚がつかめたら、人的リソースを投入し、製品をリリースします。
すぐ決定する、『決定を遅らせる』を比較した場合、うまく成功するケースでは、すぐ決定する方が少ないコストでリリース出来ます。『決定を遅らせる』では事前の検証+開発が必要で、トータルでみると作業量は増えるためです。
ただ、これが失敗する可能性が高かったり、何が成功かわからない状態で開発するとします。
プロダクト開発において、最初から勝ち筋が見えている戦いは多くありません。概ね何が当たるかわからない不確実性が高い状態から始まります(だからこそ成功するプロダクトは多くないわけで(´・ω・`))
すぐ決定し、最初から全力リソース投下した結果失敗した場合、開発費が丸々ドブに流れます。
一方、『決定を遅らせる』場合は、事前の検証分だけが損失となります。すぐ決定する場合と比較して、小さい損失で済むため、失敗を活かした再挑戦が可能になり、その分試行回数も増やせるため成功する確度を高めることを期待できます。
まとめ
『決定を遅らせる』とは、まず小さく仮説検証を繰り返して精度を高め、より成功率高くプロダクトを提供していくための方法論だった(`・ω・´)