2019/12/17

rsyncの悲劇 〜本番環境を消し飛ばす前に覚えておきたいこと〜


この記事は本番環境でやらかしちゃった人 Advent Calendar 2019 17日目の記事です。


はじめまして、ダーシノ(@bc_rikko)です。

突然ですが、懺悔します。
私は転職して10ヶ月で2回も本番環境をぶっ飛ばしました。お客様をはじめ、関係各位には多大なるご迷惑をおかけしたことを、ここでお詫び申し上げます。


1回目は2015年11月27日、入社27日目のこと。
gitの設定ミスにより壊れたブランチをmasterにforce pushしてしまい、CIが流れて本番環境が壊れた。原因はpush.defaultなのだが、詳しくはすでに記事を書いているのでそちらを読んでほしい。
2回目は翌年9月1日、入社してちょうど10ヶ月たった日のことだ。
またしても本番環境をぶっ飛ばした。しかも、前回より盛大に……。

タイトルにもあるようにrsyncコマンドが原因だ。
当記事では、この「rsyncの悲劇」を二度と繰り返さないために原因・対策を共有したい。


勘の鋭い方は「rsync」と「本番環境でやらかしちゃった」という組み合わせでオチにお気づきと思いますが、しばらくの間お付き合いください。

2019/12/09

CSS Custom Propertiesと良好な関係を築くための戦略


この記事はCSS Advent Calendar 2019 9日目の記事です。

CSS Custom Properties、ときにCSS変数やCSS Variablesとも呼ばれているプロパティがある。昨今のダークモード等のテーマ変更の需要の高まりとともに、多くのウェブサイトで使われるようになった。

たとえば、CSS Custom Propertiesを使うと以下のようにCSSだけでOSのテーマを判別し、ダークモード表示ができる。
/* Default / Light Theme */
:root {
  --color: black;
  --background-color: white;
}

/* Dark Theme */
@media (prefers-color-scheme: dark) {
  :root {
    --color: white;
    --background-color: black;
  }
}

body {
  color: var(--color);
  background-color: var(--background-color);
}

他にも以下のようにスタイルの管理がしやすくなる。
/* Before */
a {
  color: #0000EE;
}
a:visited {
  color: #800080;
}
a:active {
  color: #FF0000;
}

a.grayscale {
  color: LightSlateGray;
}
a.grayscale:visited {
  color: Silver;
}
a.grayscale:active {
  color: LightSteelBlue;
}
/* After */
a {
  --link: #0000EE;
  --link-visited: #800080;
  --link-active: #FF0000;
}

a.grayscale {
  --link: LightSlateGray;
  --link-visited: Silver;
  --link-active: LightSteelBlue;
}

a {
  color: var(--link);
}
a:visited {
  color: var(--link-visited);
}
a:active {
  color: var(--link-active);
}
参考: Patterns for Practical CSS Custom Properties Use | CSS Tricks


すごい、、、すごく便利そう!!


しかし、一見便利そうなCSS Custom Propertiesも使い方によっては闇を生み出してしまう。
ということで、当記事ではNES.css(CSSフレームワーク)開発で得た<知見>を元に、CSS Custom Propertiesのメリット・デメリットを理解し良好な関係を築く方法を紹介する。

2019/09/12

GitHub Actionsの使い方まとめ

9月上旬にGitHubから「You're in! Get started with GitHub Actions beta」というメールが届いた。どうやら以前した利用申請が通り、個人アカウントでGitHub Actionsのベータ版が利用できるようになったらしい。

ちょうどJSライブラリを開発していたので、そのリポジトリでGitHub Actionsを使ってCI(継続的インテグレーション)の設定をしてみたので、その使い方や解説をする。


GitHub Actionsとは


一言でいうと、GitHub上で完結するCI/CDサービス。
いままでCircleCIやTravisCI、Drone CIなど外部のサービスを使っていたところを、GitHub上で実行できるサービスだ。

昔はTerraformなどで使われているHCL(HashiCorp Configration Language)を用いて設定ファイルを書いていたらしいが、2019年9月30日に廃止されYAML構文に一本化される。そのため、CircleCIやTravisCIなどからも比較的簡単に移行することができる。

詳しくは公式ドキュメント参照。
▶ GitHub Actionsについて - GitHub ヘルプ

2019/09/10

TypeScriptの似ているようで違うvoid/never型とany/unknown型の比較

TypeScriptは業務で使っているが、脳内バージョンは2.x系で最新情報を追ってこなかった。その弊害として、never型とunknown型の意味がわからず、void/anyと何が違うの?状態だった。

そこで当記事ではvoidとnever、anyとunknownのそれぞれの型の特徴を一言、二言で表し比較する。

2019/08/19

情報特化型ツイートがフォロワー数に及ぼす影響と共感型ツイートの展望

概要


夏休みの自由研究として本研究を行った。
先行研究(※1)よりTwitterのフォロワー数を増やす初期段階は、ユーザーに価値(情報)を提供するツイート(以下、「Information特化型ツイート」という)が効果的だと言われている。本研究では、2019年8月12日〜15日の4日間、Information特化型ツイートをすることでフォロワー数がどれくらい増加するか実験を行った。


第1章 はじめに

1.1. 研究背景

「何者かになりたい!」誰もが一度は考えたことがあるだろう。SNS映えやバイトテロ、炎上商法と呼ばれるSNS上で注目を浴びるための行動からも言えるように、自己顕示欲は暴走しやすい側面を持っており問題視されている。
たしかにこれらの行為は一時的に注目を浴びることができるかもしれないが、「炎上行為をした」という印象を変えるのは困難だ。そこで本研究ではSNS上で正攻法で信頼を勝ち取りつつ、影響力を高めフォロワー数を増やすにはInformation特化型ツイートは有用かを検証した。

2019/07/31

本気でCSS芸やりたい人のためのbox-shadow講座

2019年7月24日にUIT meetup vol.7 - 集まれ!(タブン)実務では使わないフロントエンド芸発表会に、CSS芸人として登壇した。

UIT meetupとは、ReactやVue.js、BFFなどのフロントエンド技術を扱った至ってマジメなイベントだ。そんな中、主催者から「次はテーマをかえてフロントエンド芸人を集めたイベントがしたい」とお誘いがあり、CSS芸人として参戦してきた。


当記事は、UIT meetupで発表した内容をスライドと共に文字起こししたものである。

※ 当記事には多くの画像が貼られているため、読み込みに時間がかかる可能性があります。

公式レポート記事: https://engineering.linecorp.com/ja/blog/uit-meetup-vol7/

2019/04/16

Canvas上のオブジェクトがクリックされたか検知する

ブラウザゲームなどを開発するとき、Canvas上に描画されたオブジェクト(図形など)をクリックしたいときがある。ただEventTarget.addEventListener('click', listener)のように簡単に処理を追加できるわけではない。

そこで当記事では、「Canvas上にある四角と丸のオブジェクトをクリックしたら色がかわる」というサンプルを元に、オブジェクトのクリック判定やクリックされたときに処理を実行する方法について解説する。

2019/04/15

Nuxt.js+TypeScriptでプラグインの型定義を作成する

Nuxt.jsには簡単にプラグインを追加できる仕組みがある。createdやmothodsなどを拡張するmixinタイプや、ElementUIなどコンポーネントタイプ、vueインスタンスにコンテキストを注入してthisを拡張するタイプなどがあるのだが、TypeScriptと併用するとProperty $logger does not exist on type 'Store<RootState>'のようなエラーが発生する。

今回はvueインスタンスを拡張し、vueファイル(SFC)とstore内でthis.$xxxにアクセスするための型定義の作り方について紹介する。

2019/03/27

手を動かして学ぶ Redis 入門

会社でRedisを使っているサービスがあり、そのメンテナーになった。RedisがIn-Memory Databaseということは知っていたのだが、その他の特徴や操作方法などまったくわからないので、チュートリアルを中心に手を動かしながら学んだことをまとめていく。またNode.jsからRedisにアクセスする方法もあわせて紹介する。


Redis の特徴


Redisはメモリー上にデータを保存するKey-Value型のNoSQLデータベースのひとつ。用途はデータベースだけにとどまらず、キャッシュやメッセージブローカーとしても利用される。

2019/03/26

details要素を使ってHTML/CSSのみでドロップダウンメニューを実装する

HTML5からdetails要素が追加された。この要素は折りたたみ可能なウィジェットを作成するもので、open状態になったときだけ子要素(summary要素など)を表示することができる。
このdetails要素を使えばHTMLだけでアコーディオンメニューが簡単につくれるようになる。

今回はこのdetails要素に手を加え、JavaScriptを使わず、HTML/CSSのみでドロップダウンメニューを実装する方法を紹介する。

完成予想図

2019/03/19

Transifexとvue-i18nで国際化対応のコラボレーション環境を構築する

国内向けのサービスであっても在日外国人が使うこともある。そういった背景から昨今、国際化対応(多言語化対応)の重要度が増している。とはいえフロントエンドエンジニアがウェブアプリケーションを開発しながらメッセージ翻訳を行うには限界がある。できれば翻訳作業はローカリゼーションチームに任せたい。

しかし、ローカリゼーションチーム(非エンジニア)にgitを使って言語ファイルをダウンロード、JSONやYamlファイルを見ながら翻訳、終わったらPull Requestを作ってもらうというのは少し酷だろう。もちろんJSON→Excel→翻訳→JSONなんてことはしたくない。

そこで当記事ではTransifexとvue-i18nを使って、国際化対応におけるフロントエンドチームとローカリゼーションチームのコラボレーション環境の構築方法について紹介する。あわせて実運用で得たノウハウを共有しようと思う。
また、当記事ではNuxt.jsをメインに紹介するが、Vue.jsでも同様のことはできるので読み替えてほしい。

環境は以下の通り。
  • macOS Mojave
  • Nuxt.js@2.4.5 / Vue.js@2.6.8
  • vue-i18n@8.8.2
  • transifex-client@0.13.6

2019/03/15

Nginxのlocationとproxy_passの末尾スラッシュによる挙動の違いを理解する

Nginxでリバースプロキシの設定をするとき、いつもlocationとproxy_passの末尾スラッシュ(Trailing Slash、トレイリングスラッシュ)による挙動の違いを忘れてしまう。ということで、locationとproxy_passのURIに末尾スラッシュをつけた場合、つけない場合でどのような挙動になるか実験した。その結果についてまとめる。

Nginxのリバースプロキシ設定は以下の4パターンになる。
パターンlocationproxy_pass
1/path/reverse-path
2/path/reverse-path/
3/path//reverse-path
4/path//reverse-path/


これに対し、4パターンのリクエストを投げて実験を行った。
  1. http://example.com/path
  2. http://example.com/path/
  3. http://example.com/path-test
  4. http://example.com/path/test

2019/02/25

ドメイン駆動設計の用語と解説(DDD入門ガイド)

中〜大規模アプリケーションを開発するノウハウを持っておらず、どのようにシステム設計するのが良いのかわからなかった。そのため、1週間ほどドメイン駆動設計(Domain-Driven Design)について勉強した。

当記事では、勉強中に得たドメイン駆動設計をわかった気になれるのに必要な用語のまとめや、実装でどのように使われるかをまとめる。

筆者は「実践ドメイン駆動設計」を読んだわけでも、完全に理解したわけでもない。しかし、雰囲気を掴むための情報はわかっている状況なので、間違っている箇所があったら指摘していただきたい。


ドメイン駆動設計とは?


ドメイン駆動設計(DDD、Domain-Driven Design)を一言で説明すると「現実世界の業務をドメインモデルに詰め込んでソフトウェアに深く反映させる設計手法」だ。

詳しい説明は後述するが、ドメイン駆動設計の全体図は下図のような感じだ。

2019/02/21

transform: scale()で要素が重なってしまったときのmarginのとり方

Chromeでは10px未満のときにfont-sizeが適用されなくなる事象が発生する。
※ ユーザ環境設定に依存するのですべてのChromeではない

そのときの対処法としてtransform: scale()を使うことがある。しかし、そこには落とし穴がある。下図のように並べた要素のボックスサイズが拡大/縮小されずに要素が重なってしまうのだ。

対処法は以下のとおり。

2019/02/18

指定範囲からランダムで重複なしのn個の値を取得する(JavaScript)

JavaScriptで指定範囲からランダムな値を任意の個数取得する方法を通常とワンライナーの2種類紹介する。たとえば、「1〜100からランダムかつ重複なく50個の値を取得する」ようなことだ。


指定範囲からランダムで一意なn個の値を取得する


const pickN = (min, max, n) => {
  const list = new Array(max-min+1).fill().map((_, i) => i + min);
  const ret = [];
  while(n--) {
    const rand = Math.floor(Math.random() * (list.length + 1)) - 1;
    ret.push(...list.splice(rand, 1))
  }
  return ret;
}

const list1 = pickN(1, 100, 30);
console.log(list1);
// [47, 69, 19, 73, 27, 35, 68, 21, 88, 41, 86, 14, 50, 42, 94, 26, 2, 43, 83, 76, 57, 31, 97, 45, 84, 99, 46, 22, 9, 81]

const list2 = pickN(500, 800, 10);
console.log(list2);
// [714, 557, 523, 760, 750, 677, 632, 566, 798, 587]

new Array(max - min + 1).fill().map((_, i) => i + min)は、min〜mixまでの値が入った配列を生成している。そして、ret.push(...list.splice(rand, 1))でさきほどの配列からランダムな位置の1つの値を取得し、結果用の配列に追加している。

2019/02/12

position:stickyでスクロール可能なテーブルの行・列ヘッダを固定する

テーブルに表示する情報が多いとき、行ヘッダや列ヘッダを固定して表示したいときがある。そんなときにはposition: stickyを使うと簡単に実装できる。
ただしIEは対応していないため、ポリフィルが必要となる。

完成予想イメージは以下のとおり。

2019/02/04

Firefoxでbackground-imageなどに指定したInline SVGで色が反映されない

NES.cssの開発をしているときに、特定のブラウザ(Firefox)だけSVGの色が反映されないバグを発見した。IE、Safari、Chromeでは再現しない。
background-imageborder-imageにInline SVGを指定したときに発生する。Inline SVGとは以下のように、url("data:image/svg+xml;...")で指定する方法を指す。
.item {
  /* 色が反映されない */
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg'><path d='M10 10 H 80 V 80 H 10 L 10 10' fill='#ff0000'/></svg>");
}

2019/01/25

Canvasで任意の色に近い色をカラーパレットから取得し画像を減色する

Canvasで表現できる色は、RGBがそれぞれ0〜255の値を取るので、256*256*256の16,777,216種類ある。(※Alphaについては考えない)
そのまま表示すれば実物に近い画像になるのだが、減色したいときもある。(レトロ感をだす画像処理フィルターとか)

そこで、任意の色に近い色をカラーパレットから取得し画像を減色する方法をまとめる。

2019/01/16

Canvasでカメラの映像に画像処理フィルターをかけて表示する方法

カメラの映像をリアルタイムに処理しドット絵っぽくしたくて、年末から画像処理学んでいき欲が再燃した。
今回はWebカメラやラップトップパソコンのカメラを使って映像を取得し、適当な画像処理フィルターをかけ、ブラウザに表示する方法をまとめる。(筆者環境はMBP)


基本: カメラの映像をブラウザに表示する


単純に表示するだけの場合は、video要素(HTMLMediaElement)MediaStreamを使う。
<video id="camera"></video>
async function main() {
  const video = document.querySelector("video#camera");
  // MediaStreamを取得する(Promiseが返る)
  const stream = await navigator.mediaDevices.getUserMedia({ video: true });

  video.srcObject = stream;
  // MediaStreamが取得できたら再生する
  video.onloadedmetadata = () => video.play();
}

main();
今回は映像だけを使いたいので、mediaDevices.getUserMedia{video: true}を指定したが、音声も使いたい場合は{video: true, audio: true}のように指定する。

詳細はMediaDevices.getUserMediaを参照してください。
※ 執筆時点では日本語ドキュメントが古いため、英語ドキュメントを読んだほうが良い。

2019/01/10

[golang]任意の値、要素数で配列を初期化する方法

Go言語の練習がてら「プログラマ脳を鍛える 数学パズル」をやっていた。

そこでひとつの疑問が生まれた。
一発で任意の値、要素数で配列を初期化できないのか?

そんなことをツイートしたらリプライをいただいたので実際に試してみた。


任意の要素数の配列を生成する


make関数を使って配列(正確にはslice)を生成する。
// すべてfalseの配列ができる
list := make([]bool, 1000)

// すべて0の配列ができる
list := make([]int, 1000)

make(型, 要素数, 容量)で任意の型と要素数でsliceを生成する。しかし型がboolならすべてfalse、intならすべで0のスライスができる。

2019/01/09

Chromeでボタンの背景色を白(fff)にできないときの対処法

NES.cssを開発しているときに、Chromeだけなぜかボタンの背景色(background-color)に白(#fff)が指定できないことに気づいた。FirefoxやSafariだと問題ない。
いろいろ実験したので、ボタンの背景色を白するための対処法をまとめる。


2019/01/08

2018年活動報告と2019年行動指針

2018年はお世話になりました。
2019年もひきつづきダーシノ、当ブログともによろしくお願いします。

過去の記事


2018年のBlack Everyday Company


まずは当ブログについての総括を。

ブログ 96.6万PV

2018年の1年間で、966,291PVあった。

前半は副業、後半はOSS活動などで忙しかったため投稿数は過去最少の33記事。PVはほぼ横ばいだ。ありがたいことに書いた記事がバズることが数回あり、3月、10月、11月は 約8.9万PV/月まで伸びた。