selmertsxの素振り日記

ひたすら日々の素振り内容を書き続けるだけの日記

2017年棚卸し

今の会社のエンジニアの人と、2017年の棚卸しをしようじゃないかという話しになりまして、この記事にまとめました。

2017年の目標

2017年は、下記3点の目標を持って仕事していました。

  • Ruby以外の言語でもサービスを作れるようにする
    • 2016年当時は、Ruby以外は正直なところちょいちょい摘む程度だった
  • AWSのインフラを使って、サービスを自分1人で作れるようにする
    • 2016年当時、ほとんど触ったことが無かった
  • OSSに関して、ちょっとばかり参加する
    • 2016年時点では、gemを3つ作ったくらい

Ruby以外の言語に関してはnodejsでサービスを1つ作りましたし、AWSについてもちょいちょい勉強会でお話しさせて頂くことができました。また、OSSについては、自作のOSSを一つ作ったのと、ドキュメント修正をちょいちょいやったりしました。

※ 自作OSS

※ ドキュメント修正 (一部抜粋)

読んだ技術書

他にも10冊くらい読んだ気がするのですが、読んでる最中に飽きてしまって読みきれませんでした。 上にあるのは、ちゃんと読み切ったやつです。上からおすすめ順になってます。

ビジネス書

サービスとして何を作るべきか悩んでいた時期に、このあたりの本を読んだりしていました。 上2つについては、まだ手元に置いてます。

発表

AWS Startup tech meetup

speakerdeck.com

【開催報告】第10回 AWS Startup Tech Meetup | Amazon Web Services ブログ

Rails Developers Meetup

speakerdeck.com

Rails Developers Meetup #3 (東京会場) - connpass

JAWS UG night

speakerdeck.com

ASCII.jp:JAWS-UG NightはパネルやLT、クイズまで欲張らナイト!|JAWS-UG広報ユカリンの部屋

備考

2017年おすすめ本です。よかったらポチってください :pray:

JestにおけるbeforeAllの実行タイミングについて

TL:DR

Jestにおいて、describe内外にbeforeAllを複数用意した場合の評価タイミングを確認した。その結果、beforeAllは上から順番に実行されていることが分かった。

モチベーション

beforeAllを上書き指定できれば、綺麗に書けるテストを書いていた。 そのため、beforeAllの優先順位や実行順序などが気になって検証した。

実行内容

コード

beforeAll(()=>{
  console.log("out of describe");
});

describe('sample describe 1', () => {
  beforeAll(()=>{
    console.log("inside of describe 1");
  });

  describe("sample describe 2", () => {
    beforeAll(() => {
      console.log('inside of describe 2');
    });

    test('sample test', () => {
      expect('hoge').toEqual('hoge');
    });
  })
});

ターミナル

$ yarn test __tests__/test.spec.ts
yarn run v1.3.2
$ yarn build && yarn jest __tests__/test.spec.ts
$ yarn tsc
$ /path_to_dir/node_modules/.bin/tsc
$ /path_to_dir/node_modules/.bin/jest __tests__/test.spec.ts
 PASS  __tests__/test.spec.ts
  sample describe 1
    sample describe 2
      ✓ sample test (5ms)

  console.log __tests__/test.spec.ts:2
    out of describe

  console.log __tests__/test.spec.ts:6
    inside of describe 1

  console.log __tests__/test.spec.ts:10
    inside of describe 2

というように、上から順番に実行されていることが分かった。

parameter storeで環境変数管理したら便利だった

モチベーション

GitHubで管理できないパラメータの管理。めんどうですよね。昔は.envrc.localで管理していたんですけれども、チームで開発するときは、ちょっといじると周りに共有しなければならなくて手間でした。そうしなくて済む方法をawsparameter storeで作ってみました。

Parameter Storeってなんだ

AWS のサービスの一つで、パスワード、データベース文字列、ライセンスコードなどのデータをセキュアに扱うためのものです。

Systems Manager パラメータストア - Amazon EC2 Systems Manager

Parameter Storeへのデータ設定方法

下記のコマンドを叩いて、parameter storeにデータを突っ込んでいきます。

aws ssm put-parameter --name SlackToken --type String --value xxxxx 
aws ssm put-parameter --name IAMRole --type String --value xxxxx 

put-parameter — AWS CLI 1.14.16 Command Reference

コード

#!/bin/sh
SlackToken=(`aws ssm get-parameters --names SlackToken --query "Parameters[*].{Value: Value}"  --output text`)
IAMRole=(`aws ssm get-parameters --names IAMRole --query "Parameters[*].{Value: Value}"  --output text`)

echo "export SlackToken=${SlackToken}" >> .envrc.local
echo "export IAMRole=${IAMRole}" >> .envrc.local

ホントなら一回のリクエストで済ませたいのですが、複数パラメータを扱おうとすると、jsonを扱ったりする必要があって、ちょい手間なのでこんな感じですませちゃいました。

あと、.envrc.local を .gitignoreに追加しておきましょう。

実行

bin/setup.sh

を実行すると、下記のように .envrc.local が生成されます。

export SlackToken=xxxx
export IAMRole=xxxxx

という感じで、簡単にパスワード管理ができるようになりました。

おひとりさま開発基盤グループでの業務の進め方

はじめに

この記事は Speee Advent Calender の23日目の記事です。

こんにちは!ロボット大好き系エンジニア、開発基盤グループ所属の森岡です。 ガンダムF91とクロスボーン以外はほぼ全て視聴済み、フロントミッションも携帯ゲーム以外は全てコンプリート。フロントミッションアーマードコアの最新作をずっと待ち続けています。好きなMSはリックドムです。

さて、僕が所属している開発基盤グループですが、グループという名前が付いているものの、実際に所属しているのは現在森岡1人だけで、完全におひとりさまグループとなっております。この記事では、1人で開発基盤グループを進めていくためにやっていることについて、ご紹介させていただきます。

開発基盤グループのお仕事

開発基盤グループは Speee全社におけるwebサービスの技術的な品質向上 をミッションとして業務を行っています。具体的な業務としては、下記のようなものが挙げられます。

  • 全社的に利用されているDatadog, Sentry, Sidekiq Proなどのツールの導入・管理
  • 開発に関するガイドラインの作成
  • 全社のサービス品質を向上するための各種ツールの作成

tech.speee.jp ※ 1部、Speee Cafe Meetupでお話しさせていただきました

現在、このような業務を進めている開発基盤グループですが、過去は異なるミッションを持って仕事を進めていました。

"全社的な開発効率の向上"から"サービスの技術的な品質向上"へ

先月(2017年11月)まで、開発基盤グループのミッションは、全社的な開発効率の向上でした。 そのミッションに従って、僕たちはRevieeeという確認環境の自動構築ツールを作っていました。

tech.speee.jp

しかしながら、このツールは現在開発を停止しています。その理由は下記の通りです。

  • 人の異動などで、恩恵を受けられるプロダクトのエンジニアが少なくなった
  • AWSのインフラが大きな役割を持つwebサービス増え、Revieeeでそれらをカバーすることが難しくなった

また、弊社で採用している言語、フレームワークが多様化してきたこともあり、Revieeeのような Railsに特化した確認環境構築ツールは、現在のSpeeeにおいて 多くのエンジニアに価値があるとは言い難い ものになってしまいました。

このように開発効率の向上というミッションは、採用する技術や、そのときの人の配置に依存する部分が大きく、開発基盤グループが1人という現状では達成することが難しいものでした。そこで、2017年11月にミッションの見直しを開始しました。

新しく作るミッションは、人の入れ替わりや利用している技術に依存せずに価値を出せる必要があります。それが何かと考えたときに、弊社が運用している 全てのサービスの技術的な品質向上 が適切であると考えました。

このミッションを進めていく手順は下記のようになっています。

f:id:selmertsx:20171222204619p:plain

これだけでは具体的なイメージが湧かないと思うので、現在行っている業務内容を例に説明させていただきます。

画像圧縮の全自動化

現在、開発基盤グループでは、Speeeにおける全てのwebサービスにおいて、ユーザーにとって最適な画像を配信する ことを目的として、デザイナーやフロントエンドエンジニアの人たちと一緒に、その仕組みづくりを進めています。

なぜ 画像の最適化 を最初の施策として選んだのかと言うと、現状パフォーマンスの向上に最も寄与し、画像を用いる全てのサービスにおいて有効で、ページの表示速度を早くしたいという事業の意図とも合致するものであったからです。 画像の最適化 ができる仕組みを作るために、下記の内容で仕事を進めています。

  1. 画像取扱ガイドラインの作成
  2. サイトの評価ツールの作成
  3. 画像を自動圧縮するツールの作成
  4. CIでの未圧縮画像検知

画像取扱ガイドライン

ガイドラインの作成にあたっては、Googleの資料を参考にさせて頂いています。

Image Optimization  |  Web Fundamentals  |  Google Developers

ガイドラインには下記の項目を記載しています。

  • JPG、PNGSVG、GIFの選定基準
  • JPG、PNGの圧縮ツールおよび、圧縮レベル

Googleの資料においては、PNGではなく WebPの使用を勧めていますが、現状の対応ブラウザ状況を見ると、WebPへの完全移行を進めることは難しい状態にあります。そのあたりは僕たちで判断しガイドラインの作成をしております。その詳細については、またどこかのタイミングで発表させていただこうと思います。

未圧縮画像の検知ツールの作成

さて、ガイドラインが出来たら次に必要になってくるのは、僕たちのサイトの評価ツールです。 評価ツールは、slackのslash commandがインターフェースとなっており、下記のような方法で利用できます。

f:id:selmertsx:20171223184619p:plain

実行すると、slack上で改善点や、改善した場合にどの程度容量を圧縮できるか教えてくれます。 slackを利用した理由は、エンジニアだけでなく全ての職種の人に結果を見てほしかったからです。

f:id:selmertsx:20171223185232j:plain

この機能は AWS API GatewayAWS Lambdaを使って実現しています。 Lambdaの中で headless Chromeを使ってページを閲覧し、分析を行っています。 詳細については、また別の機会に説明させていただきます。 もう少し調整が出来たら、OSSとして公開しようかなと考えています。

その他、開発予定のツールについて

ここから先はまだ未着手のものですので、構想だけのお話しになります。 ここまでで、ガイドライン、そして評価ツールを作りました。 次に必要になってくるのは、手軽に画像を圧縮できるツールと、未圧縮の画像がコミットされたときに、それを検知できるCIツールです。rubocopもrspecも、CIで実行されるようにならなければ、きっとこれほど価値を出すことができなかったでしょう。

画像の圧縮については、Gitフックを使って実装しようと考えています。コミット時に自動で圧縮されるので、特に意識せずとも圧縮した画像をGitHubで扱えるようになるかと思います。

WE ARE HIRING

以上、「お一人様開発基盤グループでの業務の進め方」について記載させて頂きました。まだまだ歩き初めたばかりのミッションなので、荒削りな部分や修正するべき点などもあるかとは思います。人が増えて、ミッションの形も変わってくることもあるかもしれません。

開発基盤グループでは、全社的なサービスの品質向上に一緒に取り組んでくれる、またはより良いミッションについて一緒に考えてくれる、そんなエンジニアを絶賛募集中です!!!ご興味を持って頂けた方がいましたら、ぜひwantedlytwitterなどで連絡をください!ご連絡お待ちしております!

www.wantedly.com https://twitter.com/

selmertsx (@selmertsx) | Twitter

24日目の記事は、iida-hayato より、「MercariARハッカソンで優勝したので技術的なまとめ」です!

おまけ

この取組みに関する考え方は SRE本の4章から拝借しました。

parcelでd3jsを扱うことが出来ない (v1.2.1 で解決済み)

エラー内容

➜  image-guideline git:(d3js) ✗ yarn parcel jpg_report.html
yarn run v1.3.2
$ /Users/shuhei_morioka/project/dev_opt/design-guideline/image-guideline/node_modules/.bin/parcel jpg_report.html
⏳  Building...
Server running at http://localhost:1234
🚨  /Users/shuhei_morioka/project/dev_opt/design-guideline/image-guideline/node_modules/xmlhttprequest/lib/XMLHttpRequest.js: Could not statically evaluate fs     at evaluate (/Users/shuhei_morioka/project/dev_opt/design-guideline/image-guideline/node_modules/parcel-bundler/src/visitors/fs.js:164:11)
    at CallExpression.path.get.map.arg (/Users/shuhei_morioka/project/dev_opt/design-guideline/image-guideline/node_modules/parcel-bundler/src/visitors/fs.js:31:21)

原因

🐛 d3 import: Could not statically evaluate fs call · Issue #298 · parcel-bundler/parcel · GitHub

npm libraries can specify alternative main fields in their package.json, we resolve the "module" and "jsnext:main" in priority of "browser" to get the full dependency tree. libraries like d3.js specifies node.js specific files in the "main" which breaks the build

対処方法

Resolver.jsを直接書き換えて回避した。

# parcel-builder/src/Resolver.js

    return resolver(filename, {
      filename: parent,
      paths: this.options.paths,
      modules: builtins,
      extensions: extensions,
      packageFilter(pkg, pkgfile) {
        // Expose the path to the package.json file
        pkg.pkgfile = pkgfile;

        // npm libraries can specify alternative main fields in their package.json,
        // we resolve the "module" and "jsnext:main" in priority of "browser" to get the full dependency tree.
        // libraries like d3.js specifies node.js specific files in the "main" which breaks the build
        const main = pkg.module || pkg['jsnext:main'] || pkg.browser;

        if (main) {
          pkg.main = main;
        }

        return pkg;
      }
    });

追記

現在では、下記のPRがマージされ、v1.2.1 でリリースされているので、問題無く扱うことができる。

Resolve "module", "jsnext:main" and "browser" before "main" by fathyb · Pull Request #299 · parcel-bundler/parcel · GitHub Comparing v1.2.1...master · parcel-bundler/parcel · GitHub

TypeScriptにおいて継承先のclassのプロパティはオブジェクトの生成時には利用できない

概要

表題のとおり。継承先のプロパティは、オブジェクトの生成時には利用できなかった。 このあたりの仕組みが気になる。やり方があれば、ご紹介頂けると幸いです!

確認のコード

class A {
  protected hoge = 3;
  constructor () {
    console.log(this.hoge);
    this.hoge;
  }

  hage() {
    return this.hoge;
  }
}

class B extends A {
  protected hoge = 4;
}
console.log("-------construct-----");
const a = new A();
const b = new B();
console.log("-------call function-----");
console.log(a.hage());
console.log(b.hage());
➜  typescript ts-node override.ts
-------construct-----
3
3
-------call function-----
3
4

ES6において strict modeになる条件

モチベーション

code reviewをして貰ったときに、「ES Modulesを使うと、暗黙的に 'use strict' 付きますよ」というコメントを頂いた。'use strict' になる条件を全然把握していないので、ちょっと資料を読んでみた。

読んだ資料

ECMAScript® 2015 Language Specification

http://www.ecma-international.org/ecma-262/6.0/#sec-strict-mode-code

分かったこと

  • Global codeが、Strict Directive ( 'use strict' のこと )を含むDirective Prologueで始まるなら、strict mode codeである。
  • Module codeはいつでも strict mode codeである。
  • ClassDeclaration、またはClassExpressionの全ての部分は、strict mode codeである。
  • strict directive を含む場合、evalの中身も strict modeになる。
  • 関連する FunctionDeclaration, FunctionExpression, GeneratorDeclaration, GeneratorExpression, MethodDefinition, ArrowFunctionがstrict mode codeを含んでいるならば、functionのcodeも strict modeなcodeになる。
  • 引数にcode strictされているfunctionがある場合、それを受け取るfunctionもcode strictになる