kitak's blog

Kみたいなエンジニアになりたいブログ

13デイズを観た

WOWOW で放送してたので作業しながら観た。

13デイズ [Blu-ray]

13デイズ [Blu-ray]

小学生の頃、金曜ロードショーでやってたのを一度観たんだけど、政治的な駆け引きが当時の自分には難しくてあまり面白く感じなかった。歳を取ってから見ると面白かった。

一番おもしろかったのは、物語の開始直後、航空写真でミサイルが確認され、ケネディ兄弟と主人公のオドネルが初手を迫られるシーンだった。 彼らは、対応策を考えるために、各省の精鋭数名からなる機関を立ち上げる。その判断を下す際のやりとりで以下のような意図や思惑が見えた。

  • 不確実性が高い状況においては、人数を増やせば増やすほど意思決定に時間がかかり、かつ、得られる結論もとんがった部分のない平凡なものでまとまってしまう
  • 大統領の顔色を伺わないように、機関のミーティングには、必要なとき以外、大統領を呼ばない。これは心理的安全の確保に繋がる

その後は、後のケネディ暗殺の黒幕が軍部であることを匂わせるような演出があったり、ケネディ(兄)のカリスマ性に酔って酔って酔いまくってください、というかんじだった(あんまりちゃんと観てなかった)。

WebComponent を Vue コンポーネントツリーの末端として使う

JSフレームワークの末端がWebComponentsになるのか、なれるのか、検証してみた - Qiita の記事を読んで、Vue だとどうなるかな、と思って軽く検証した。自分の手に馴染んているのが Vue というだけの理由で、決して React dis ではないです( React は React で、そのうちいいかんじの仕組みが入るような気がする )。

結論、問題なく使えると思う。

そもそも WebComponent を末端で利用するモチベーションは?

現状、CSS フレームワーク、UI フレームワークがあり、そのフレームワークをラップして View フレームワーク( React, Vue, Angular )のコンポーネントとして提供するライブラリをよく見かける( react-xxx とか vue-xxx みたいなの )。こういったライブラリの組み合わせは、UI フレームワークの数を M, View フレームワークの数を N とすると M * N の組み合わせになる。
各 View フレームワーク向けに 1 から UI フレームワークコンポーネント化して、このようなライブラリを提供するのは効率が悪い。
また、View フレームワークの機能や仕様の差があるため致し方ない部分もあるが、提供されるコンポーネントの I/F が統一感のないものになってしまう。

これらの問題は、再利用可能な単位で WebComponent( Custom Element )を定義すれば、解決するような気がする。View フレームワークから直接利用してもよいし、そのコンポーネントを View フレームワークコンポーネントしてラップしたライブラリを提供する場合でも、以前ほどのコストはかからず、フレームワーク間である程度統一された I/F になる。

ここでの WebComponent は、Python でいう アプリケーション・サーバーとフレームワークの間を取り持つ WSGIRuby でいう Rack のような立ち位置に近い。

Vue で WebComponent を使う

WebComponent で独自の要素を定義して使う。独自の要素といっても、普通の abutton といった要素と同じ I/F なので属性で値を渡して、要素の中で発生したことはイベントを通して知ればよい。

次の様なクリックされたらカスタムイベント my-click を発火する WebComponent ( Custom Element ) を定義しておいて、

import { html, render } from '/node_modules/lit-html/lib/lit-extended.js';

const template = props => html`
  <style>
    :host {
      display: block;
    }
  </style>
  <div>
    <button on-click="${props.onClick}">${props.text}</button>
  </div>
`;

export default class MyButton extends HTMLElement {
  static get observedAttributes() {
    return ['text'];
  }
  constructor() {
    super();
    this._shadowRoot = this.attachShadow({mode: 'open'});
  }
  connectedCallback() {
    this.render();
  }
  attributeChangedCallback() {
    this.render();
  }
  render() {
    const text = this.getAttribute('text');
    render(template({
        text,
        onClick: this.onClick,
    }), this._shadowRoot);
  }
  onClick() {
    this.dispatchEvent(new CustomEvent("my-click", {bubbles: true, composed: true}));
  }
}

window.customElements.define('my-button', MyButton);

Vue のコンポーネントで以下のように使う。

import Vue from '/node_modules/vue/dist/vue.esm.browser.js';

Vue.component('home', {
    data() {
        return {
            value: 0,
        };
    },
    mounted() {
        setInterval(() => {
            this.value += 1;
        }, 1000);
    },
    methods: {
        onClick() {
            console.log('onClick', this.value);
        },
    },
    template: `
        <my-button v-bind:text="value" v-on:my-click="onClick"></my-button>
    `,
});

v-bind ディレクティブで、カウントしている値を text 属性の値としてバインディングして、v-on ディレクティブで my-button コンポーネントから発火される my-click イベントをハンドリングする。

Vue でのイベントハンドラの扱い

v-on ディレクティブは、カスタムイベントを含む DOM イベントをハンドリングすることができる( 細かいけど、Vue コンポーネントの場合は Vue の持っているイベント機構で発火されたイベントもハンドリングできる )。
このディレクティブが肝で、React と違って、イベントハンドラの関数をコンポーネントに渡す必要がない(渡すこともできるが、あえてそうする必要がない)。
なので、WebComponent ( Custom Element ) へ関数を渡すことを考えなくてもよい。

最初に書いたモチベーションの場合、WebComponent を書く人間と、それを使う人間が分かれることがほとんどになるので、
WebComponent は、自身を使おうとしている View フレームワークや、それが関数を渡そうとしていること、あるいは関数を渡すための仕掛けについて、関心を持つべきではないし、コンポーネント自体の再利用性も鑑みると関数を引き渡すことは諦めたほうがいいのではないかと思う。将来的に双方で関数を渡したい・受け取りたいニーズが高まれば別。

WebComponent でのイベントリスナーの扱い

DOM 操作したくないので button 要素のクリックのイベントハンドラの管理も含め lit-extended でだいぶ楽をしたが、extended ではない lit-html ( addEventListener )を使う場合はこんなかんじになる。

import { html, render } from '/node_modules/lit-html/lit-html.js';

const template = props => html`
  <style>
    :host {
      display: block;
    }
  </style>
  <div>
    <button>${props.text}</button>
  </div>
`;

export default class MyButton extends HTMLElement {
  static get observedAttributes() {
    return ['text'];
  }
  constructor() {
    super();
    this._shadowRoot = this.attachShadow({mode: 'open'});
    this._shadowRoot.addEventListener('click', (e) => {
        if (e.target.tagName === 'BUTTON') {
            this.onClick();
        }
    });
  }
  connectedCallback() {
    this.render();
  }
  attributeChangedCallback() {
    this.render();
  }
  render() {
    const text = this.getAttribute('text');
    render(template({
        text,
        onClick: this.onClick,
    }), this._shadowRoot);
  }
  onClick() {
    this.dispatchEvent(new CustomEvent("my-click", {bubbles: true, composed: true}));
  }
}

window.customElements.define('my-button', MyButton);

button 要素にイベントリスナーを登録すると lit-html が要素を差し替えることを考慮して(この例では考えなくていいかもだが)、適切なフックで都度 addEventListener, removeEventListener を呼ぶ必要がある。そこで、shadowRoot に対してイベントリスナーを登録し、イベントを発生された要素に応じて、カスタムイベントを発火させるようにする。
shadowRoot に登録するイベントリスナーが分岐だらけになりそうな気もするのだけど、コンポーネントの責務さえしっかり決まっていればさほど問題にならないような気がする。コンポーネントの状態管理が複雑になるのは、また別の問題。

正直、この例だったら lit-html を使わず DOM API でも実装できるが、実際にコンポーネントを作ろうとしたら、もう少し複雑なものになって DOM API ではつらくなり lit-html を使うことになると思うので試した。

色々書いたけれども、Vue では WebComponent が普通に使えると思うので、今のうちから各種 CSS フレームワーク、UI フレームワークの WebComponent( Custom Element )を定義したライブラリを作っておけば、後で重宝されるかもしれないですね。

マネー・ショート を観た

観た。

サブプライム住宅ローン危機の発生を予測し、事前に空売り(実際は空売りではないんだけど)することで巨額の利益をあげた男たちの物語。実際のモデルがいる。

邦題の「華麗なる大逆転」や黄色いパッケージから、アウトロー達がウォール街のエリートたちに一泡吹かせる痛快ストーリーかと思ったが、全くそんなことはない。 そこにあるのは、アウトローたちの心の葛藤である。

彼らの全てが喜々としてトレードしたわけではない。世界経済の崩壊が起こることを確信し、このような事態を招いた連中への怒り、絶望といった負の感情を噛み締めながらトレードするのである。

物語の終盤では、自分たちの成功が、多数の人々が職・資産を失い露頭に迷う先にあることを自覚し、良心の呵責に苛まれる。また、危機がはじまり、いざ売り抜こうとする際に「ここで売って巨額の利益を上げたら、自分たちが一番憎んでいた連中と同じになるのではないか」と苦悩する。

スティーヴ・カレルクリスチャン・ベールブラッド・ピットの徹底的な役作り、巧みな演技がこれらの心の葛藤を見事に描いている。特にスティーヴ・カレルの演技が表情・声のひとつひとつの変化のレベルで良かった。また機会があったら見たい。

デヴィッド・リンチ:アートライフ を観た

観た。

映画『デヴィッド・リンチ:アートライフ』公式サイト

不気味で、得体の知れないデヴィッド・リンチの発想はどこから生まれるのか。彼の生い立ちや絵の創作活動を通して探る作品。

彼が語る過去のエピソードに合わせて、彼の版画作品が映される。幼い頃の恐怖体験、住んでいた住居、フィラデルフィアの工業地帯、彼の創造力の源泉が過去にあることが分かる。ひとつひとつの作品に過去の体験に基づく物語があるのだ。

数日前に、ヒカリエでやっていたデヴィッド・リンチの版画展に行ってきたのだけど、正直、作品からそういった背景を掴み取ることがまったくできなかった。この映画を観た後に行けば、彼の過去の物語を思い浮かべながら作品を鑑賞できるかもしれない。

フィラデルフィアの風景の映像やそのときの暮らしぶりの話は、イレイザーヘッドを観たことがある人にとって、たまらないものに違いない。廃墟、差別主義、モノクロ、子供が生まれたばかりの夫婦の生活。あの不気味な映画は、その頃のリンチの心象を映像にしたものだ、ということがしっくりくる。

Vue.js で特定のプロパティを変更の追跡の対象外にする

きっかけ

とある案件で、とあるサードパーティSDK を利用していた。その SDK が提供するコンストラクタから生成したインスタンスを Vue.js のインスタンスのデータとして扱おうとしたら、Security Error のような例外が投げられて困った。 (回避するために、インスタンスのデータとして扱わないように試みたのだけど、致し方ない理由で諦めた)

原因

Vue.js では、データの変更を追跡するためにプロパティを getter/setter に上書きする。ココらへんの話は リアクティブの探求 — Vue.js が詳しい。この上書きの処理はプロパティがオブジェクトの場合は掘り下げて再帰的に行われる。おそらく問題の起きたインスタンスでは、セキュリティの観点からこういった処理を防ぐ機構が入っていたのだと推測。すごいね。

解決

これまた公式ドキュメントなのだけど、Object.freeze で追跡の対象外にできることを知ったので以下のようなコードを書いた( Vue インスタンス — Vue.js )。

const foo = new ThirdpartyFoo();

const container = {
  foo,
};

const vm = new Vue({
  data() {
    return {
      container: Object.freeze(contianer),
    },
  },
});

vm.container.foo;

はじめ foo 自体を Object.freeze したのだけど、foo のメソッド呼び出しに伴うプロパティの変更ができなくなってしまった。そこで、容れ物のオブジェクトを用意して、元のオブジェクトを包むことにした。こうすることで、foo のプロパティの getter/setter への上書きは防ぎつつ、これまで通り foo のメソッドを呼び出すことができる。

これまで特に意識せず、様々なオブジェクトを Vue のインスタンスのデータとして扱っていたのだけど、変更を追跡する必要がない、オブジェクトのプロパティの階層が深い( getter/setter への上書きのコストが高い )オブジェクトは Object.freeze で追跡の対象外にしてよいかもしれない。

個人サイトを nuxt で書き換え、netlify で公開するようにした

追記: 2018/03/28

唯一イケてなかったのは、netlify のビルドタスクを実行する環境の Node のバージョンが古いこと。async/await が使えず、プリレンダリングに失敗してしまった。これは、しょうがないので、dist もバージョン管理対象にした。

NODE_VERSION環境変数をセットすることで、async/await が使える Node.js でビルドできた。Continuous Deployment | Netlify


経歴や職歴が書かれた個人サイト https://www.kitak.info に久しぶりに手をいれた。

元々、サイトジェネレーターの hugo を使ってサイトを生成し、VPS で公開していたのだけど、nuxt で書き換え、netlify で公開するようにした。以下、それぞれに関する個人メモ。

nuxt

プリレンダリングの機能があることを知って、前々からサイトジェネレーターとして使ってみたい気持ちがあった。

記事を markdown で書いていたので、プリレンダリング時に markdown から HTML を生成した。既存の markdownレンダリングする Vue のライブラリは、slots や mounted hook を利用したクライアントサイドで実行する制約のあるものがほとんどだったので、実装は単純なのだけど、こんなかんじ( https://github.com/kitak/www.kitak.info-nuxt/blob/6af6c36755e75f98e641f614a18109f70f53a1d9/components/MdArticle.vue )の markdown-js をラップした Vue コンポーネントを用意した。別にクライアントサイドでレンダリングしてもよいのだけど、事前にレンダリングしておいたほうが表示が早いだろうという気持ちの問題。

/ にリクエストがきたときに /about と同じ内容を表示したかった(内部リダイレクトしたかった)。nuxt では pages ディレクトリの構造 = ルーティングの設定なので、リダイレクト先のコンポーネントをそのまま返すようなコンポーネントを用意すればよい( www.kitak.info-nuxt/index.vue at 6af6c36755e75f98e641f614a18109f70f53a1d9 · kitak/www.kitak.info-nuxt · GitHub )。

netlify

作成したサイトを配信するために netlify を利用することにした。静的ファイルの配信に特化したサービス。総じてよかった。今回、自分が利用した機能については無料プランの枠で収まっている。

  • 管理画面が使いやすい
  • CDN で配信してくれる
  • 独自ドメインSSL証明書を Let’s Encrypt で取得してくれる
  • パス毎にカスタムヘッダーの指定ができる
  • (使っていないけど)SPA の Prerendering をしてくれる
  • (使っていないけど)特定のパスだけ api に proxy できる。SPA の場合、ページと api の origin が同じになるので CORS でハマることがなくなる

唯一イケてなかったのは、netlify のビルドタスクを実行する環境の Node のバージョンが古いこと。async/await が使えず、プリレンダリングに失敗してしまった。これは、しょうがないので、dist もバージョン管理対象にした。

アレハンドロ・ホドロフスキー監督 エンドレス・ポエトリーを見た

見た。アレハンドロ・ホドロフスキー監督の自叙伝的小説「リアリティのダンス」の映画の続編。

www.youtube.com

臨死体験のような自叙伝

この映画を見て、ホドロフスキー監督が死ぬ前に臨死体験として見る映像はこのようなものなのではないか、という気がした。臨死体験の中には、これまでの人生が映画のように映され、自身が観客となって追体験するというものがある。この種の臨死体験とは、自分の自叙伝を死の直前に自分だけが読むようなものなのかもしれない。マジック・リアリズムの演出も、時折、老いた自分が現れて若き日の自分に語りかける様子も臨死体験と考えれば、なんとなくしっくりくるのである。

最後に両親と和解するシーンは、過去を自分の都合の良いように美化しているようにも見える。批判的な書き方をしたが、人間の脳とはそのようなものではないかと思う。つらい出来事をそのまま受け入れれば、心を病んでしまう。誰もが、どこかでそういった出来事を忘却したり、美化しているのではないか。ましてや、死の直前に自分の人生を受容するためにそれを行うのは、当たり前のことではないだろうか。

自分の人生を生きること

全体を通して、主人公は自分の人生を生きることを追求する。親の言いなりの日々を過ごし、親という他人の人生を生きていた主人公。詩と出会い、詩人になりたいと思った日から、自分の人生を歩みはじめる。サンティアゴの芸術家たちとの交流を通して、徐々に自分の人生を生きはじめるが、それでも、親の期待に応えなければいけないのではないか、という気持ちが心のどこかにひっかかる。物語の最後の最後まで引きずるその気持ちも、両親と別れる際に向き合い、両親が息子の課題を他人の課題として切り捨てた時点で消え去る。この親子の関係、家族が再構築されるクライマックスは、この物語の最大の見せ場としてふさわしく、心を揺さぶられる。

人生の意味と生の肯定

生きることの虚しさや意味に苦しむ若き日の自分の前に、老いた自分が現れる。そして、生きる意味を問われ、ただ「生きろ」とだけ繰り返し語り続ける。

宇宙の長い時間の流れの中で、人の生命は海の中で浮かび上がる一粒の泡のように、ほんの一瞬だけ存在するちっぽけなものかもしれない。それを虚しいと捉えることもできるが、何もないところから生まれてきたという事実に目を向け肯定的に捉えれば、虚無から何かを形作る力があると考えることもできる。一般的な人生の意味はなく、生きる過程で、その力を行使して生きる意味を作り上げ、自分自身にそれを与えていかなければならない。「生きろ」という言葉の繰り返しには、そのようなメッセージがあるのではないかと思う。