2017年の春から開発者として働き始める人が読むべき技術書

わたしがソフトウェア開発者として働くようになってからもう何年も経ちますが、通読した技術書は0です。技術書を読まなくてもソフトウェア開発者として働き続けることはできます。

この技術書を読まなければならないといったことを半ば強制的に言ってくる人の言葉には耳を貸さなくても大丈夫です。

もし、強く技術書を買うよう要求してくる人がいるのであればその人に本を買ってもらいましょう。そういうことができるのは若者の内だけです。

技術書を読めと言うのならば、そうした責任を持つべきです。とくに働き始めの人はまだお金も少なく、ほかの書籍と比べると高価な技術書を購入することは難しいのですから。

WebSocketでタイムラインを表示させるだけのウェブアプリケーション「tweet receiver」を作っている

tweet receiverというウェブアプリケーションを作りました。

Twitterでフォローしている人のツイートをUser streamsを介して取得し、それをWebSocket (RFC 6455) を経由させてリアルタイムに表示させるだけの機能しか有していません。ツイートを投稿することはできませんし、できるようにするつもりも今の時点ではありません。純粋に人のツイートを見るだけです。

User streamsを活用したウェブアプリケーションを別に開発していて、その検証のために簡単なものを作ろうと思って作り始めたものです。ですが、動かしてみたところ思ったよりも便利なので、もう少し見た目の体裁を整えて常用に耐えるものにしようと考えています。

ViVid Strike! #05.5にかける期待感

ViVid Strike! #05.5にかける期待感

ViVid Strike! は全体的に見るとかなりしっかり作られていて好感の持てるとても良い作品である。しかしそれでもまったく不満がないというわけではない。全十二話という少ない尺の関係もあるだろうが主人公であるフーカ・レヴェントンが一足飛びに強くなっているように感じられてしまっていた。フーカが自身を鍛える描写といったものが話の比率として少ないからそう感じられてしまっていたのだろう。

そのような思いを抱いていたところ、来月発売されるBlu-ray Vol.2に収録される新作OVAの予告映像が公開された。

#05.5、そう5.5話である。#05と#06の間を補完してくれるストーリーである。つまりウインターカップがはじまる直前の話が描かれるのである。さらに公式の情報によればBlu-ray Vol.3には#05.75が収録される。これはどうしても期待せざるをえない。

もう一人の主人公であるリンネ・ベルリネッタに焦点を当てた話が比率として多かった。嘔吐するまで練習を繰り返しコーチと二人三脚で苦しみながらも泥臭く努力をしていたリンネ。和気藹藹と笑いながら同門の仲間たちと練習をし、そして練習のあとに仲良くみんなと温泉に行ったりと楽しげに過ごすフーカ。残酷なまでのこの対比。

フーカの練習も過酷なものであったこと登場人物たちの会話から予想できる。しかしあまりにも凄惨に描写されていたリンネとどうしても比較してしまうのでフーカの苦労というものが感じられない。そう考えていたので今回のこの映像特典の報せは待望と言っても過言ではない。非常に楽しみである。

import()を使ったHTTP/2時代のフロントエンド実装

import()を使ったHTTP/2時代のフロントエンド実装

この記事はhttp2 Advent Calendar 2016の二十三日目の記事である。

今年……2016年はHTTP/2が大いなる躍進を遂げた年であったと感じる。

Amazon CloudFrontも今年の九月にHTTP/2の対応が追加された (Amazon CloudFront now supports HTTP/2)。またFastlyでも十一月から一般利用が可能となった (HTTP/2 is now in General Availability)。

これまではNginxApache HTTP ServerなどのHTTP/2に対応したHTTPサーバーをフロントとして自身で運用しなければならなかった。Contents Delivery Network (CDN) サービスの恩恵を享受できず、また運用の手間をかける必要もあった。

しかし今年 多くのCDNサービスがHTTP/2に対応したため、手間をかけることなく誰もがHTTP/2の恩恵を気軽に享受できるようになった。今後HTTP/2で配信されるウェブページが増えていくことであろう。

HTTP/2が策定される以前のHTTPの規格であるHTTP/1.1では同一のホスト名に対して同時にリクエストできる数には制限がある。そのため、複数のスクリプトファイルが埋め込まれたウェブページはページ全体の読み込みが完了するまでに時間がかかってしまっていた。それを解決するために複数のスクリプトファイルをwebpackBrowserifyといったバンドルツールを用いて結合させるといったことが、半ば当たり前のこととなっていた。

HTTP/2ではリクエストとレスポンスのストリームが多重化されている。並列して複数のリクエストを送信できるようになったため、これまで当たり前のことであったスクリプトファイルの結合の必要性は薄くなった。

// src/client.jsx

import React from 'react';
import ReactDOM from 'react-dom';

function render(element, container) {
  return new Promise((resolve, reject) => {
    try {
      ReactDOM.render(element, container, resolve);
    } catch (error) {
      reject(error);
    }
  });
}

async function main() {
  const App = await import('./components/App');
  const container = document.getElementById('root');
  try {
    await render(<App />, container);
  } catch (error) {
    // eslint-disable-next-line no-alert
    alert(error.message);
  }
}

main();

のようにimport()で別のスクリプトファイルを指定すると実行時にそのスクリプトファイルが読み込まれるようになる。import()Promiseを返すので、ECMAScript 2017から仕様に追加されるAsync Functionsとの相性が極めて良い。

import()はこの記事を執筆している時点 (2016年十二月二十三日) ではstage 3であり、正式な仕様となっているものではない。そして実装されているウェブブラウザーもまだ存在していない。しかしwebpack (v2.1.0-beta.28以降) を使うことによって、期待するような効果が得られる。

webpack単体でもimport()に対応しているが、Babelも一緒に使うのであればBabelで処理させるためにbabel-plugin-syntax-dynamic-importというBabelのプラグインを導入させなければならない。

またBabelはCommonJSに対応していないので、webpackから読み込んでも実体はそのまま返されない。defaultという名前のプロパティーを含むobjectが返されるため、(await import('./components/App)).defaultのような形で呼び出さなければならず、いささか煩雑である。これはbabel-plugin-add-module-exportsを使うことによって解決できる。babel-plugin-add-module-exportsはその名前の通り、module.exportsを追加するBabelのプラグインである。これによりwebpackの想定するCommonJSに対応する形へのトランスパイルが可能となる。

最終的にwebpackの設定 (webpack.config.js) は次のようになる。

// webpack.config.js

const BabiliPlugin = require('babili-webpack-plugin');
const HtmlPlugin = require('html-webpack-plugin');
const path = require('path');
const merge = require('webpack-merge');

const clientConfig = {
  devtool: 'source-map',
  entry: {
    main: path.join(__dirname, 'src', 'client.jsx'),
  },
  module: {
    rules: [
      {
        exclude: /node_modules/,
        options: {
          babelrc: false,
          plugins: [
            'add-module-exports',
            'syntax-dynamic-import',
          ],
          presets: [
            ['env', {
              debug: true,
              targets: {
                browsers: [
                  'Chrome &gt;= 55',
                ],
              },
            }],
            'react',
          ],
        },
        test: /\.jsx?$/,
        loader: 'babel-loader',
      },
    ],
  },
  output: {
    chunkFilename: '[id].[chunkhash].js',
    crossOriginLoading: 'anonymous',
    filename: '[name].[chunkhash].js',
    path: path.join(__dirname, 'build', 'public'),
    publicPath: '/',
  },
  plugins: [
    new HtmlPlugin({
      template: path.join(__dirname, 'src', 'templates', 'index.ejs'),
    }),
  ],
  resolve: {
    extensions: [
      '.js',
      '.jsx',
    ],
  },
};

module.exports = (env) => {
  switch (env) {
    case 'production':
      return merge(clientConfig, {
        plugins: [
          new BabiliPlugin(),
        ],
      });
    default:
      return merge(clientConfig, {
        output: {
          chunkFilename: '[id].js?[chunkhash]',
          filename: '[name].js?[chunkhash]',
        },
      });
  }
};

今回 書いたコードの全体はykzts-sandbox/try-dynamic-importにある。MITライセンスで公開しているので自由に使ってもらって構わない。

今後、HTTP/2での通信はより一般的なものになっていくと予想される。HTTP/1.1時代の常識のままでいては良くないだろう。フロントエンドに携わるソフトウェア開発者でも、HTTPについてある程度の知識と理解を持ち、よりユーザーの方向を向いた適切な開発を心がけて行きたい。

ピクシブ株式会社を退職します

ピクシブ株式会社を退職します

現在有休消化期間中ですが、2016年十二月三十一日をもってピクシブ株式会社を退職します。ピクシブに入社したのは2014年十二月です。まるまる二年、勤めていたことになります。

二年の内、2015年十一月から2016年十月までは株式会社アニメイトラボに出向していて、またピクシブに入社してからアニメイトラボに出向する以前もアニメイトラボの仕事のお手伝いをしていました。そのため実はピクシブの仕事自体はほとんどしていません。

アニメイトラボではアプリケーションエンドエンジニアとしてフロントエンド (JavaScript、CSS、HTML) からサーバーサイド (Ruby、PHP、Node.js) まで触っていて、またAmazon Web Service (AWS) を使ったインフラ面の構築も行っていました。設立されたばかりで社内にいるソフトウェア開発者の人数が少ない段階で関わることでき、幅広い領域の仕事をすることができました。

いろいろと思うところがあり、アニメイトラボへの出向はおわり、またそれにともなってピクシブも辞めます。今後についてはまだなにも決まっていませんが、有休消化はまだしばらく残っているため、のんびりと過ごそうと考えています。

もし、わたし山岸和利といっしょに働きたい! と思ってくださる会社がありましたら、ykzts@desire.shまでご連絡ください。FacebookメッセージやTwitterのダイレクトメッセージですと、親しい方以外は流れてしまって見落としてしまう可能性が高いためメールでのご連絡のほうが助かります。

TVを作っています

最近、TVを作っています。TVといっても映像を受信して映す機械を作っているわけではありません。TVのように映像を再生して、見ることのできるウェブサービスを開発しています。

そのウェブサービスの名前はBaberuTVです。その名前の通りにbaberu.tvというドメイン名で公開しています。

公開しているとはいえ、まだ開発者であるわたしが日常的に使って困ることが程度の機能がようやく実装しおえたという段階です。使いかたの説明はまだなにも用意できていません。見た目もまだ洗練させられていませんし、おいおい進めて行こうと考えています。

BaberuTVとは

名前の由来はバベルの塔です。天にも届く技術力を得たいというわたしの個人的な思いを込めた命名です。

正しいスペリングである「Babel」ではなく「Baberu」としているのは、かたかな語のようなチープさを出したかったためです。またGoogle検索などの検索エンジンで「Babel」で検索するときのノイズとなってしまわないようにという思いも込めています。

BaberuTVではHLSの動画のURIをテキストフィールドに入力し、「Play」と書かれたボタンを押すことによって動画の再生を開始させられます。ただしBaberuTVがHTTPSで配信されているため、HLSの動画もHTTPSで公開されているものでなければなりません。また使用しているライブラリーの都合上、HLSがネイティブに動作しないウェブブラウザーではHTTPヘッダー「Access-Control-Allow-Origin」で適切な値が返されていないと動画の受信ができません。これ仕様上の問題ではありますが、わたしが使う範囲では困らないため、修正する意欲は薄くなってしまっています。

なぜ作りはじめたのか

サイバーエージェントとテレビ朝日の出資によって設立された株式会社AbemaTVによって、同名のウェブサービス「AbemaTV」が今年 公開されました。AbemaTVはReactやHLSといった比較的に新しい技術を使っています。

そう、「比較的に」なのです。

Reactが公開されたのは2013年です。今から三年も前です。HLSはReactよりもさらに古く、2009年から存在しています。七年前です。そう七年前なのです。

ひるがえって自分はどうでしょう。自分は何年も似たような技術を使い、そして似たようなウェブサービスばかり作っています。ウェブアプリケーション開発者としてこのことに危機感を覚えざるをえません。

そしてAdobe Flashがレガシーな存在であるとさけばれるようになってから、もう何年も経ています。だというのにいつまでもAdobe Flash Playerがユーザーの環境にインストールされていることを前提としたウェブサービスはなくなりません。それどころかわたし自信もそうしたウェブサービスにたずさわりつつも、なにもできずにいました。ユーザーに対する不誠実を許容することに対する歯がゆさを感じつつも、ウェブサービスにたずさわる一人の人間として、なにもできない無力さを痛感させられていました。

くやしい。

くやしい。

くやしい。

AbemaTVのサービスがはじまって以来ずっと、ずっとずっとそう思わされていました。思わせられ続けていました。

そんな折、勤め先でいろいろなことがあり時間が生まれたので、BaberuTVの開発に着手しました。

なにを使っているのか

BaberuTVでは、できる限り最新の流行を踏襲することを大前提としています。

ビルド関係

JavaScriptはいわゆるES.nextの構文やAPIをふんだんに使い、webpackを用いてバンドルを行っています。まだStage 4にもなっていない構文も使っているため、多くのウェブブラウザーとNode.jsでは当然動きません。なのでwebpackでのバンドルを行う際に、多くのウェブブラウザーとNode.jsで動かせられない構文はBabelを使って、ECMAScriptの最新の仕様であるECMAScript 2016に合致するようにトランスパイルさせています。

バンドル後のスクリプトファイルはECMAScript 2016の仕様に準拠させているため、最新のウェブブラウザーでなければ動作しません。ですが個人で開発しているウェブサービスなので気にすることではないでしょう。

HTTP/2での接続を前提としていてバンドルさせる意義は薄いのですが、現状のJavaScript周辺のエコシステムがバンドルさせることを前提としているため、そちらにあわせました。最新技術をキャッチアップするという目的意識から外れるようなことをあえてする理由もありません。

UI

UIを構築するためのライブラリーとしてReactを使っています。これは流行しているから、というだけではなくAbemaTVを踏襲しました。

ただAbemaTVではFluxの実装としてFluxibleを使っていますが、BaberuTVではなにも使っていません。contextを子孫コンポーネントに引き渡して、コンポーネントをまたいだ処理を行っています。

これは小規模に済ませ、あまり複雑になりすぎないようにということを意図していますが、大規模になるとまわらなくなるのである程度のタイミングでAbemaTVと同様にFluxibleを使おうと考えています。

またHLSの再生はSafariとMicrosoft Edge以外のウェブブラウザーではネイティブ動作しないため、hls.jsを使っています。

おわりに

BaberuTVはGitHubで開発と運用をしています。現状コミットをしているのはわたしだけですが、まずはじめにIssueを作り、Projectで進行状況の確認ができるようにしています。そしてPull Requestを作ってコミットをマージすることによって関連するIssueをクローズさせるという運用をしています。これは普通のソフトウェア開発を踏襲させたかったためです。普通が一番効率が良いものであるとわたしは固く信じています。

BaberuTVのレポジトリーはbaberutv/baberutvです。前の段落にもある通り、現状はコミットをしているのがわたしだけですがMIT LicenseのOSSです。誰でもご自由にPull Requestをお送りください。心より歓迎いたします。

ペンと剣

「ペンは剣よりも強し」という格言がある。この格言はペン (言論) は剣 (暴力行為) に勝るという意味を持つ。

しかし今の日本では剣を持つのは難しく、また剣を使わない状態であっても暴力行為を行って肯定されることはまず起こり得ない。

情報化社会となり、多くの人間がスマートフォンなどの情報端末を日常的に持ち歩くようになっている。多くの人間が広く世界に流布する情報を発信できるペンを持つ時代となっている。

剣による力の誇示がほしいままに行えなくなった今、ペンこそが力なのではないだろうか。

ペンで他者や自分自身を陥れることが容易にできるようになっている……なってしまっているのではないかと感じる。このことは頼もしいことではあるが、おそろしくもある。

すべての人がペンという「武器」を手にしていると言ってしまっても過言ではないだろう。