育休中Webエンジニアのインプット方法

これは、MIXI DEVELOPERS Advent Calendar 2024 の23日目の記事です。

育休中の生活

こんにちは、minimo 事業部でフロントエンドエンジニアをしている @takaya1992 です。

2024年の夏に子どもが生まれ、あっという間に時間が経ち、子も5ヶ月になろうとしています。 子どもが生まれてから育休を取得し、12月末まで仕事をお休みしています。
育児だけでもそれなりに大変なんですが、教習所に通ったり引っ越したり忙しい日々を送っています。

育休に入る前は、育児もしつつ、積んでる本を読んだり新しい領域(ex: アプリ開発)に手を出したり自分の時間を取れるといいなと、キラキラした育休生活を妄想していたんですが、そんな暇はほぼありませんでした。
赤ちゃんの面倒を見るのはそんなに大変なのか……というとそういうわけではなく(もちろん大変ではあるんですが)、単に当初計画になかった引っ越しや自動車免許取得のための教習所とその勉強の時間に割かれて、ほかの時間が取れていないという当たり前の話です。

そんななかでも何かインプットができないかと思ってやっていることについて書いていきます。

耳からのインプット

子どもをあやしたり遊んだりするときは片手間になにかをやるというのはもちろん無理なんですが、ミルクをあげたり寝かしつけをしたりするときや家事をするときに、手と目は忙しいけど耳はあいています。
耳からのインプットと言えば Podcast じゃないか!と、Podcast を聴くことにしました。

もともと数年前から Podcast は聴いていて、主に通勤中などに聴いていました。
このときは「情報のインプット」というより単にトークを楽しむという部分が大きかったと思います。
今回は、より仕事やキャリアに役立ちそうな番組を中心に聴いています。

育児中に Podcast を聴くときにに気をつけていること

具体的にどんな番組を聴いているのかを紹介する前に、Podcast を聴くときにに気をつけていることを書きます。

まず前提として、イヤホンをして Podcast を聴いていて、イヤホンは AirPods Pro を使っています。

外部音取り込み

イヤホンをしていて、子どもの泣き声や異変に気づかなかったなんてことがあったら大変なので、AirPods Pro の外部音取り込み機能を有効にした状態で使用しています。

イヤホンは片耳だけ

外部音取り込み機能を有効にした状態でも両耳にイヤホンをして Podcast を聴いていると、妻の自分への声掛けが聞き取れない(何かを喋っているのは分かるがPodcast 内の会話とオーバーラップして聞き取れない)ことがあり、片耳だけイヤホンをつけるようにしています。

イヤホンを子どもの手の届かないところに置く

4ヶ月となると子どもは手の届く範囲のものはなんでも掴んで口に運ぼうとします。
これからは寝返り、ずり這い、ハイハイとだんだん動いて手の届く範囲が広がっていきます。

イヤホンに限ったことではないですが、誤飲の可能性のあるものは手の届かないところに置く必要があり、ポケットにしまう、背の高いテーブルや棚に置くなどしています。

聴いている Podcast

仕事ではWebフロントエンドチームのリーダーをしていることもあり、最近はEMにまつわる番組を中心に聴いています。
自分は iOSPodcast アプリで聴いていますが、試聴しやすいように各番組の Spotify のリンクを張っているので、興味があるものはぜひ試しに聴いてみてください。

EM系

EM.FM

open.spotify.com

エンジニアリングマネージャーの問題集

open.spotify.com

エンジニア・キャリア

Qiita FM

open.spotify.com

fukabori.fm

open.spotify.com

Webフロントエンド

mozaic.fm

open.spotify.com

UIT INSIDE

open.spotify.com

テック

vim-jp ラジオ

open.spotify.com

Rebuild.fm

open.spotify.com

backspace.fm

open.spotify.com

最後に

紹介した Podcast の番組はほんの一部で、他にもテックやキャリア、その他さまざまなテーマの Podcast がたくさんあるので、耳が暇だなってときには探して聴いてみてください。

vim-vsnip で複数のディレクトリからスニペットをインポートする

vimスニペットを使うために vim-vsnip を使いはじめました。

vim-vsnip はファイル形式ごとに JSONスニペットを定義します。

ex: typescript.json

{
  "ReactFC": {
    "prefix": "fc",
    "body": [
      "import React from 'react';\n",
      "const $1: React.FC = () => {",
      "  return (",
      "  );",
      "};\n",
      "export default $1;"
    ],
    "description": "React関数コンポーネントの雛形"
  }
}

このようなファイルを g:vsnip_snippet_dir に設定したディレクトリに置くと、スニペットとして展開できるようになります。

let g:vsnip_snippet_dir = expand($HOME . '/dotfiles/vsnip')

自分はこのファイルを dotfiles として公開しています。

github.com

しかし、そうすると公開できるような内容しかスニペットに登録できず、公開できないコード、例えば仕事でよく使うコードなどを登録できません。 それは不便なので、スニペットJSON ファイルを参照するディレクトリを複数登録したくなります。 そんなときはg:vsnip_snippet_dirs に配列で複数のディレクトリを渡すことで解決できます。

let g:vsnip_snippet_dirs = [expand($HOME . '/dotfiles/vsnip'), expand($HOME . '/dotfiles/vsnip-local')]

こうしたうえで、 vsnip-local/.gitignore に登録しておき、 vsnip-local/ に仕事等で使う公開したくないスニペットを保存します。 (自分は gitignore する前に vsnip-local/.gitkeep を Git 管理下に置いておいて、その後 gitignore して git clone しても vsnip-local/ が存在するようにしています)

iOS 13 ( Safari 13 ) 以降は -webkit-overflow-scrolling: touch の指定は必要ない

iOS Safari で慣性スクロールを有効にするために指定する -webkit-overflow-scrolling: touch だけど、 Safari 13 ( iOS 13 ) から慣性スクロールがデフォルトになったため、わざわざ -webkit-overflow-scrolling: touch を指定する必要がなくなった。

Safari 13 Release Notes #Layout and Rendering

Added support for one-finger accelerated scrolling to all frames and overflow:scroll elements eliminating the need to set-webkit-overflow-scrolling: touch.

-webkit-overflow-scrollingiOS Safari のみがサポートしているプロパティなので、iOS 13 未満のサポートをしないのであればスタイルシートから消してしまって問題ない。

developer.mozilla.org

Docker ( AmazonLinux2 ) 上で Perl から Headless Chrome を操作する

Perl で Headless Chrome を操作する日本語記事がほぼないし、しかもそれを Docker 内で動かすという例がなかったので書いておくことにする。

全部のファイルと、動かし方は gist にまとめておいた。

https://gist.github.com/takaya1992/6fc6878fb936559344fac068ab6e90f2

抜粋して一部を書いておく。

まずは、Dockerfile

FROM amazonlinux:2

WORKDIR /app

RUN yum update -y \
  && yum install -y perl perl-core perl-App-cpanminus gcc expat-devel \
  && rm -rf /var/cache/yum/* \
  && yum clean all \
  && cpanm Carton

COPY google-chrome.repo /etc/yum.repos.d/google-chrome.repo
RUN yum install -y google-chrome-stable unzip wget lsof ipa-gothic-fonts ipa-mincho-fonts

RUN CHROME_MAJOR_VERSION=$(google-chrome --version | sed -E "s/.* ([0-9]+)(\.[0-9]+){3}.*/\1/") \
  && CHROME_DRIVER_VERSION=$(wget --no-verbose -O - "https://chromedriver.storage.googleapis.com/LATEST_RELEASE_${CHROME_MAJOR_VERSION}") \
  && echo "Using chromedriver version: "$CHROME_DRIVER_VERSION \
  && wget --no-verbose -O /tmp/chromedriver_linux64.zip https://chromedriver.storage.googleapis.com/$CHROME_DRIVER_VERSION/chromedriver_linux64.zip \
  && unzip /tmp/chromedriver_linux64.zip chromedriver -d /usr/local/bin/

先に断っておくと、サンプルとしてわかりやすく書いているので、Dockerfile を書く上でのベストプラクティスは守っていない。 前半は、Perl とそれに必要なパッケージのインストールなのでとくに説明はしない。

重要なのは後半の Chrome と ChromeDriver のインストール部分で、Chrome のインストールから説明していく。

Chrome のインストール

まずは、Chromeリポジトリを追加するために設定ファイルをコピーしてくる。google-chrome.repo の中身は以下のようになってる。

[google-chrome]
name=google-chrome
baseurl=http://dl.google.com/linux/chrome/rpm/stable/$basearch
enabled=1
gpgcheck=1
gpgkey=https://dl-ssl.google.com/linux/linux_signing_key.pub

これを /etc/yum.repo.d/ 以下に置くことで、yum のパッケージ検索対象になる。 Chromegoogle-chrome-stable というパッケージ名で登録されている。

残りの Chrome と一緒にインストールしてるパッケージは、次の ChromeDriver のインストールに必要なもの ( unzip, wget )と、Chrome を起動するのに必要なもの ( lsof ) 、Chrome で日本語を表示する際に必要なフォント ( ipa-gothic-fonts, ipa-mincho-fonts ) 。

ChromeDriver のインストール

Chrome を外から操作するために ChromeDriver を使う。
ChromeDriver はブラウザを操作するための WebDriver という仕様に基づいて実装されており、ChromeDriver を起動すると HTTP サーバーが立ち上がり JSON API でブラウザを操作できる。
他のブラウザ、例えば Firefox では geckodriver というドライバーが用意されている。
この WebDriver を使って各ブラウザを操作できるのが Selenium である。

話がそれたけど、ChromeDriver をインストールする。 ChromeDriver は Chrome のバージョンに合ったバージョンをインストールする必要がある。 そのため、 Chrome のバージョンを確認しそのバージョンに対応する ChromeDriver のバージョンを取得し、ダウンロードしている。

Perl から Headless な Chrome を操作する

直接 Docker を実行するのも面倒なので、docker-compose.yml を用意して Docker Compose で操作できるようにしてある。

$ docker-compose build

でビルドして、

$ docker-compose run --rm app /bin/bash

で Docker コンテナ内に入る。

cpanfile を用意しているので Docker コンテナ内で以下のコマンドを実行して必要なパッケージ ( Selenium::Remote::Driver ) をインストールしておく。

$ carton install

以下のスクリプトcarton exec -- perl selenium_chrome_test.pl で実行すると、 Google と表示されれば成功。

use strict;
use warnings;
use utf8;

use feature qw/say/;

use Selenium::Chrome;

# Selenium を介さず直接 chromedriver 経由で Chrome を操作する
my $driver = Selenium::Chrome->new(
    extra_capabilities => {
        'goog:chromeOptions' => {
            args => [ 'headless', 'disable-gpu', 'window-size=1920,1080', 'no-sandbox' ],
        }
    }
);

$driver->get('https://www.google.com');

say $driver->get_title();  # => Google

$driver->shutdown_binary();

Headless な Chrome として実行するポイントは、Selenium::Chrome->new 時のオプションで headless を指定すること。

順番に説明していく。
まず、インストールした Selenium::Remote::Driver にはいくつかのパッケージが含まれていて、 Selenium::Chrome もその一つ。
Selenium::ChromeSelenium を介さずに前述した ChromeDriver に直接アクセスし、API をコールして Chrome の操作を行う。

Selenium::Chrome に渡した goog:chromeOptions は、ChromeDriver へセッションを作成する際に渡され、 goog:chromeOptions 内の args 配列は Chrome 起動時の引数として設定される。
headless を指定するとヘッドレスな Chrome として起動される。
disable-gpuheadless 指定時に追加で指定することが推奨されるオプションである。
window-size はその名の通りウィンドウのサイズを指定している。これは必須ではない。
最後に no-sandboxChromeサンドボックスを無効化するオプション。詳しく調べられていないけど、これをつけないと実行できなかった。セキュリティはゆるくなるので信用できないサイトを開かないように注意する。

【脱jQuery】jQuery の width, height の取得を Pure JavaScript に置き換える

jQuery は window や document 、element に対して幅 ( width, innerWidth, outerWidth ) と高さ ( height, innerHeight, outerHeight ) の取得ができる。 element に対して width や height を取得するための互換コードを紹介してる記事が多いが、 windowdocument に対しての取得について触れてる記事がなさそうだったので、調べてみた。

jQuery 3.5 をベースに調査している。

$(window) に対しての width, height の取得

jQueryソースコードではこの部分 https://github.com/jquery/jquery/blob/7a0a850f3d41c0412609c1d32b1e602d4afe2f4e/src/dimensions.js#L23-L29

$(window).width

document.documentElement.clientWidth

window に対しての width の取得なのに、いきなり document が出てくるのでびっくりすると思うが、間違いではない。

window には width プロパティはなく、 innerWidthouterWidth しかない。 また、window.innerWidthスクロールバーを含む ウィンドウのビューポートの幅を返す。

https://developer.mozilla.org/ja/docs/Web/API/Window/innerWidth

たいていの場合、取得したいのは描画が可能なエリア、つまりスクロールバーを除いた幅なので、その利用者側の意図と JavaScript の使用の差を jQuery が吸収してくれている結果。

逆に、スクロールバーを含めたウィンドウのビューポートの幅を取得したい場合は window.innerWidth を使うことになる。

$(window).innerWidth

document.documentElement.clientWidth

$(window).innerWidth で取得できる値は、 $(window).width と同じである。

$(window).outerWidth

window.innerWidth

$(window).innerWidth はスクロールバーを含めた幅が返ってくる。

window.outerWidth はブラウザの外側の幅(サイドバーやその他ブラウザのUIを含めたもの)を返すので注意する。

$(window).height

document.documentElement.clientHeight

詳細は $(window).width と同じで、widthheight に読み替えれば大丈夫。

$(window).innerHeight

document.documentElement.clientHeight

$(window).innerHeight で取得できる値は、 $(window).height と同じである。

$(window).outerHeight

window.innerHeight

詳細は $(window).outerWidth と同じで、widthheight に読み替えれば大丈夫。

$(document) に対しての width, height の取得

jQueryソースコードではこの部分 https://github.com/jquery/jquery/blob/7a0a850f3d41c0412609c1d32b1e602d4afe2f4e/src/dimensions.js#L32-L42

$(document).width

Math.max(
  document.body.scrollWidth, document.documentElement.scrollWidth,
  document.body.offsetWidth, document.documentElement.offsetWidth,
  document.documentElement.clientWidth
)

$(document).innerWidth

$(document).width と同じ値を返す。

$(document).outerWidth

$(document).width と同じ値を返す。

$(document).height

Math.max(
  document.body.scrollHeight, document.documentElement.scrollHeight,
  document.body.offsetHeight, document.documentElement.offsetHeight,
  document.documentElement.clientHeight
)

$(document).innerHeight

$(document).height と同じ値を返す。

$(document).outerHeight

$(document).height と同じ値を返す。

友達の頼みでノートパソコンを見繕った

高校の時の友達から「パソコン買い替えたいんだけど、おすすめとか教えてくれない?」と連絡がきて「え〜俺も詳しくないし〜」とか思いつつ、なんだかんだ乗り気にヒアリングをしてよさげな端末を見繕ってしまった。

要望

  • スマホのバックアップ
  • 家で仕事(MS Officeを利用する)
  • 起動が速い
  • 小さい
  • 安い

要望を受けての想定スペック

  • HDDまたはSSD: 256GB以上
  • メモリ: 8GB(値段を抑えたければ4GB)
  • Office: あり。Office Home & Business であること
  • USB: USB type-A (USB type-C のみは避ける)
  • サイズ: 13〜15インチ (優先度低め)

選んだポイント

  • スマホのバックアップは子供の写真が多いだろうからできるだけストレージ容量の大きいもの。最低でも 256GB 以上がよさげ。
  • 速さにこだわるんだったら SSD 。ただし、容量に対して HDD よりは割高。コストを抑えつつストレージ容量を重視したい場合は HDD 。
  • メモリは 8GB 以上あれば Office の操作も快適。16GB はオーバースペック感。
  • 価格を抑えるためにメモリ 4GB という選択肢もあるけど、若干動作は遅くなる。
  • Office あり。Office Personal 2019 だと Powerpoint が含まれないので注意。
  • USB type-A のポートが最低1つ、できれば2つ以上あればOK。 type-Cは変換アダプタが必要な場面が多いので避ける。

選んだ商品

けっこうお高いのね。と言われ、スペックを落とせば少し価格も落ちるよといって、メモリを4GBに落としたもの。

それでもやっぱりそれくらいするのね。と言われ、MS Office の値段も含まれてるから本体価格にしたら普通に安いほうだよ。と言ったら、え。Officeって買うものなの?と聞かれ、なるほどーという気持ちになった。

そして、その高校の友達、高校生の頃にお付き合いをしたことがあり、さらに今のLINEのプロフィール画像が子供の写真になっていて、聞くといつのまにか結婚・出産をしておりとてもショックを受けた、ということを最後に記しておく。

GASでサイボウズ ガルーンの予定をSlackに通知する

今勤めている会社では、スケジューラーとしてサイボウズのガルーンを利用しています。
サイボウズにはKUNAIという公式のスマホアプリがあり、それが予定の更新や予定のn分前のリマインドを通知してくれます。
しかし、仕事中はスマホの通知には気づきづらく、それなりの頻度でガルーンをチェックする必要があります。

ガルーンが公式にブラウザ通知やSlack連携をサポートしてくれれば嬉しいんですがそんな機能もいまだなく、 またガルーンが提供するAPIはいままでSOAP APIしかなく、SOAPは扱いづらいためずっと自作も避けていました。

そんななか、いつのまにかガルーンのAPIREST APIが追加されていたので、予定のn分前になったらSlackに通知するGAS(Google Apps Script)を書いてみました。

Garoon Slack Notificator

github.com

使い方

使い方はGitHub Pagesで用意してみました。

takaya1992.com

サイボウズ ガルーンのREST APIを使ってみて

APIのユーザー認証方法がイケてないなと思いました。

developer.cybozu.io

ドキュメントを参照すると「パスワード認証」と「セッション認証」が用意されており、「パスワード認証」はIDパスワードを、:で連結した文字列をBASE64エンコードしたものをX-Cybozu-Authorizationヘッダーに乗せて、リクエストを送ります。 この「パスワード認証」のトークンの作り方はBASIC認証とまったく同じで、ただHTTPヘッダーが違うだけです。 生のIDとパスワードを扱うのはつらいので、リジェネレートしやすい別のAPIトークンを発行できたりとか、OAuthできるようになるととても嬉しいなと思います。