The future starts today

Webとか英語とか育児とかに関する雑記

英語苦手マンがこの3年間やってきたことと、その進捗

何度か英語のエントリーは書いていますが、最近書いていなかったのでちょっとまとめでも。

自分の元々のスペックとしては以下のような感じでした。

  • TOEICは500点くらい(学生時代それなりに勉強したにもかかわらず…)
  • 文法はひと通り理解している
  • リスニングが苦手
  • スピーキング×
  • 英語なしで生きていこうマン

その後社会人になって英語の必要性に気付き、色々とやってきて、意味があったこと、なかったことがそれぞれあったのでそのご紹介です。

やって良かったこと

シャドーイング

間違いなくこれは意味があったと言えるものがシャドーイングです。

シャドーイングとは、英語音声を流して、その音声を聞きながら同じ言葉を追っかけて喋るというものです。

テキストとしてはこの本を使いました。

決定版 英語シャドーイング

決定版 英語シャドーイング

  1. テキストを見ながら音声を聞き、追っかけて発音する
  2. 自然と英文を覚える(1, 2ページなので)
  3. テキストを見ずに音声を聞き、追っかけて発音する

基本的には上記の3つの手順をひたすら繰り返しました。

これによって伸びたと思う能力は、発音リスニングリーディング速度です。

音声を真似して喋るので、当然発音は良くなります。
できる限り音声に似せて発音できるようにします。

人間は、自分で発音できない音は聞き取ることが出来ないとどこかの本で読んだことがあります。
面白いもので、何度も発音することで本当にフレーズが聞き取れるようになりました。

最初はテキストを見ながら発音するのですが、意外とそれだけでも難しいものです。
今まで声を出してリーディングする練習をほとんどやってこなかったというのもあると思いますが、なぜか途中で音声に追いつけなくなります。
その原因を探っていた結果、改行部分で追いつけなくなるということに気づきました。
改行時、つまりページの右端に来たら目線を左端に持ってくる必要がありますが、音声が右端にたどり着いた時点で目線を移動しても間に合いません。
うまく途切れずに発音するためには、少しだけ文章を先読みする必要があります。
具体的には、右端の単語を発音している間に目線は次の行に移っているイメージです。
僕の経験上では、この訓練によってリーディングの速度が上がったと思います。

また、シャドーイングはやっていて結構楽しいです。
単語を覚えたり、長文を読んだりするのはツラくてなかなか続きませんが、英語を発音するというのは実はかなり楽しいです。(英語を発音している自分に酔っている的な感じかもしれませんw)
楽しみながら勉強できるのはとても重要です。

瞬間英作文

こちらもオススメです。 自分の場合、TOEICの点数を上げたいというのもありましたが、海外出張に行きたいという野心もあったので、スピーキングの練習もしなくてはならないと思っていました。

会社のとあるプロジェクトで、いざ英語を話さなくてはならない状況に置かれた際、最初は全然喋れませんでした。

喋ろうとしても語順が日本語と違うため、肯定文以外を話すのが難しいのです。

日本語の場合、例えば否定文を話したかったら最後に「〜ない」と付ければ良いですが、英語の場合は3単語目あたりで「not」を言わなくてはなりません。

疑問文はさらに難しくて、日本語であれば語尾で適当に「〜ですか?」などと聞いておけば良いですが、英語の場合、1単語目で「Do you ~」「Can I ~」などと言わなくてはなりません。

これが最初の壁だなと思いました。

疑問文を話したくても、つい肯定文で始めてしまい、気付いた時にはすでに手遅れということが多々ありました。(まぁ語尾を上げれば伝わりはしますがw)

どの本を見てもこんなこと書いてありません。
英語ができるようになってしまった人はきっとそんな苦労を覚えていないのでしょう。(それか元々話せるかどっちか)

この壁を乗り越えることができるのが瞬間英作文です。

スラスラ話すための瞬間英作文シャッフルトレーニング

スラスラ話すための瞬間英作文シャッフルトレーニング

青と緑と赤がありますが、僕のオススメは緑です。(青は単元ごと、緑は内容シャッフル、赤はパターンプラクティス)
青を持っている人が多いですが、単元ごとだとその文に使う表現が予想できてしまうため、シャッフルの方が瞬発力が鍛えられます。

日本語 英語
彼は彼女に会うために公園に行った。 He went to the park to see her.
君はまだ宿題をやってないの? Haven’t you done your homework yet?
彼はどれくらいあの車を運転しているの? How long has he been driving that car?
その男性は、彼女に挨拶しないで、歩き続けた。 The man kept walking without greeting her.

具体的には上記のような日本語をひたすら英語に直していく練習です。
これは一人でも出来ますし、二人以上で問題を出し合ってみるのも効果的です。(自分は朝練的な感じで結構二人でやっていました)

1秒以内に回答し始めるルールとか設けると面白いし、実践的です。

オンライン英会話

瞬間英作文である程度自信がついてきたらこれです。
やはり、実際に外国人と話すのが一番の訓練になります。

自分はDMM英会話をやっていました。

こちらのエントリーも参照。

shibe97.hatenablog.com

shibe97.hatenablog.com

最初は相当緊張しましたが、意外と25分間なんとかなってホッとした記憶があります。
瞬間英作文で鍛えた効果によって、英語を文章で話すことができました。

オンライン英会話で何の教材をやるのかにも寄りますが、オンライン英会話で身につく一番の効果は、外国人と話す恐怖心がなくなることかなと思います。
「え、それだけ?」と思うかもしれませんが、これ結構重要です。

「英語やだなぁ」
「外国人怖い」

みたいな思いがなくなって、

「ちょっと英語で話してみたい」
「海外行ってみたい」

となります。

英語に関するものに能動的に取り組めるようになります。

もちろん会話で使える便利フレーズだったり、海外の文化だったり、語彙力だったり、他にも得られるものはたくさんあります。

海外ドラマ

DMM英会話は結局1年3ヶ月で辞めてしまいました。

というのも、1年経ったあたりから自分の中であまり上達を感じなくなって来たからです。 この時点での自分の中での課題はリスニングでした。

DMM英会話の先生とは普通に会話が出来ても、会社の同僚の海外メンツは話すスピードが速すぎてなかなか聞き取れません。

そこで噂に名高い海外ドラマに手を出してみることにしました。

もちろん英語音声英語字幕で見ます。

色々と調べてみたところ、どのサイトでも「フレンズがオススメ!」と書いてあったので観てみることにしました。

f:id:shibe97:20170523001213j:plain

結論から言うと、僕にはフレンズは合いませんでしたw

話すスピード速いし、ギャラリーがなんで笑っているのかよく分からないし、ストーリーが浅いので「次の回を早く観たい」という気が起きませんでした。

なんで皆そんなにフレンズを推しているんだろうか・・・と思いながらも、なんとか1シーズンは観終えました。

もっとストーリー性があってスリルがありそうな物が観たいなぁと思い、プリズンブレイクを観ることにしました。

f:id:shibe97:20170523001836j:plain

予想通り、スリル満点で見事にハマりました。

英語自体はまぁ速いですが、字幕追いながらでなんとかなりました。
おそらくストーリーの流れ的になんとなく内容を把握できるというのもあるかと思います。

まだ全て観終わってはいませんが、自分の中では確実にフレンズよりは格上でした。

ちなみに、動画視聴サービスとしてはNetflixを使っています。 単純に海外ドラマが多そうだったという理由です。 今のところ特に不満はありません。

進捗どうですか?

はい、ここまでで大体3年間です。

進捗としては、TOEICは735点です。(全く威張れる点数ではない)
それも実は1年半前くらいに取った点数です。

と言うより735点は、ほぼシャドーイングだけで取った点な気がします。(言うてもシャドーイングは半年もやってない)
残りのやってきたことは、全て実践向きで、TOEICの点には結びつきませんでした。主に海外の人と話すのに役立ったかと思います。

もはやTOEICの点数を上げようという意欲があまりないのですが、一応指標として定期的に受けようとは思っています。

やってもあんまり意味なかったこと

逆にやっても全然身にならなかったなぁと思うことも挙げてみます。
※あくまで一個人としての意見です。

単語帳での勉強

やはり英語の勉強として誰もが避けて通れないものとして英単語の勉強があります。
さすがに全然単語を知らないと文章も読めないし、英語を聞き取ることもできないと思うので、最低限は知っている必要があると思います。

いわゆる英単語帳での勉強は、自分の場合は一時記憶で終わってしまい長期記憶になりません。 きっと何度も何度も復習すれば可能だと思いますが、面白くないので全然続きませんでした。

単語帳のアプリも色々と試してみましたが、どれも1ヶ月も続かないうちに脱落しました。

結果的に、単語は、必要に迫られて覚えるのが一番だと気づきました。

例えば海外ドラマを観ていて、この単語の意味が分からないと文脈つかめないという場面がちょいちょいあります。
そういう時は一時停止をし、ササっと単語を検索して理解します。 おそらくですが、人って結構使う単語が偏っていると思います。

この人はよくこのフレーズ使うな〜とか、よくこの単語使うな〜というのがあり、意外とドラマ内で何度も同じフレーズが出て来たりします。 ドラマを観つつ、調べた単語の復習をしつつ、という感じで楽しく覚えることができます。

最近出て来た熟語は「pull over」です。「ちょっと車を路肩に止めて」っていう意味だと思うのですが、なんとなく、車をpullして車線からoverさせる感じかぁとか考えたりするのも結構楽しいです。

英語の小説

もともと小説は結構好きなので、英語で読めたら良いんじゃねということで英語の分厚い小説を読んでみた時期がありました。
電車の中で「俺、英語の小説読んでるんだぜ」的なドヤりは出来るのですが、やはり文章だけだとなかなか読むのがしんどくて途中で断念してしまいました。

読み切れたらきっと読解力だったり読むスピードが上がったりするんでしょうね。
ただ自分は無理でした。
たぶんですが、長すぎるからダメだったのかなぁと思います。 技術的な内容の英語記事などの方が程よい長さで読めるので、僕はそちらの方が向いていると感じます。

まとめ

長くなってしまいましたが、自分的なオススメは以下のものです。

特に効果的なのは上の2つですかね。

結構短期間でも効果があったので是非試してみてください〜。

【Rust】メモリ管理(スタックとヒープ)

Memory

ずっとJavaScriptを書いてきた身からすると、メモリ管理という単語はあまり触れたくない単語。
ブラウザのガベージコレクターが良い感じにやってくれるというくらいの認識しかなかった。

そこでRustに入門して、メモリ管理の第一歩を踏み出してみる。

Rustにはスタックとヒープという2種類のメモリ管理方法がある。

スタックとは

下から順に上に重ねていく方式。(last in, first out)
スコープが外れたタイミングで解放されていく。

fn next() {
    let y = 20;
    let z = 30;
}

fn main() {
    let x = 10;

    next();
}

上記の例では、main関数でxのメモリが確保され、foo関数でy, zのメモリが確保される。
foo関数から抜けたタイミングでy, zはスコープ外となり、メモリが解放される。
そして、main関数が終わると全ての値が解放される。

スタックは単純な仕組みな故、高速である。

ヒープとは

順序関係なしにメモリ確保、解除ができる。
Box<T>型を用いた場合はヒープ領域にメモリが確保されるようになっている。

スタックの時とは異なり、メモリ確保は一番後ろの番地から行われる。

ところで<T>って何?

Rustのexampleを見ていると至る所に<T>が出てくる。
これはジェネリック型というやつで、簡単に言えばどんな型でも柔軟に対応しますよという型。(間違ってたらすまん)

通常、TypeのTを取って<T>と表記される場合がほとんどだが、別に何のアルファベットでも良いらしい。

話を戻しまして、

fn main() {
    let x = Box::new(5);
    let y = 10;
}

上記の例の場合、Box::new(5)によって生成された値はヒープ領域に保存され、xはその番地へのポインタをスタック上で保持する。
main関数が終わり、xがスタック上から解放されるタイミングでヒープ領域の値も解放される。

ヒープは自由度が高い故にコストが高く、スタックに比べると速度が遅い。

まとめ

基本的にはスタック形式でメモリ管理が行われるので、関数スコープを抜けたタイミングでメモリは解放されていく。
スコープを出てもメモリを保持したい場合にヒープを使うのだろうか。
まだ分からないことがたくさんあるので勉強せな。

顔と名前を覚えるのが得意すぎてツラい

f:id:shibe97:20170417223901j:plain

先日こんなツイートをしたところ、思ったより反響があったのでこれについて書いてみる。

自分は、1回でも面と向かって話したことがある人であれば、顔と名前はだいたい覚えている。

少なくとも顔はほぼ100%覚えている。

1度しか話したことがない場合、久々に会うと相手には覚えられていないことの方が多いのだが、たまに覚えてくれている人もいる。

俺調べでは、ビジネス寄り(営業とか企画)の方が多い。

逆にエンジニア、デザイナーは高確率で覚えられていない。笑

「覚えられないくらい印象が薄いのでは?」と言われたらそれまでだが、それにしてもだいぶ偏りがあると思う。

一度会社内でこの話をしたときに同調してくれた方々は皆、所謂「コミュ力が高い」部類の方々だった。

ちなみに皆、既婚。 周りをよく見ていて、ささいなことに気を遣えるような方々だった。

先日の飲み会の話

社内の若手デザイナーを集めて飲もうという会があった。

自分は5年目で、例年新卒研修で教える立場だったため、全員に対して面識があるつもりだった。

その場にいたとある後輩に

「久しぶりだね〇〇さん、最近は何やってるの〜?」

とさらっと聞いてみたところ、「え?」と驚きの表情と共に相手に焦りが見えた。

「誰だっけ・・・」と必死に頭のデータベース内を探っていた。

「あ、覚えてないか〜」とすかさずフォローを入れたが、なんとも言い難い悲しい気持ちになった。

先日の廊下での出来事

自分はデザイナーだが、とある案件で営業の方々(全員初見)+自分で飲みに行ったことがあった。

その中にデザイナーの業務に興味を持ってくれた先輩がいた。

ばっちりスーツを着こなしていて、「この人はモテそうだ。」という印象だった。

それ以来、3ヶ月に1度くらい社内でばったり会うが、その度に向こうから会釈してくれる。

先日は会社の廊下で20 ~ 30メートル先から会釈してくれて驚いた。

自分より相手の方が先に気づくということが自分にとっては結構珍しく、素直に「この人はすごい」と思った。 信頼できる人だと思った。

顔と名前を覚えることのメリット

自分の場合、1度しか話したことがない相手が自分のことを覚えていてくれた場合、「この人はできる!」とかなり好感度が上がる。 特に相手が目上の方だったらなおさらだ。

偉い人ほど顔と名前を覚えるべきだと思っている。

一般的に、偉くなればなるほど名前が知れ渡って、一方的に知られる可能性が高い。 そんな時こそチャンスだ。

「え、こんな人が自分のことを知ってくれているの?」となると、途端にその人に対する好感度は上がるものだ。

自分とは遠い世界の人だと認識されると好感度は下がっていく。

まとめ

顔と名前を覚えるだけで、人生がちょっと良い方向に変わるかもしれない。

一方的に覚えているとツラいことも多いけれど、それも上手く利用できるとコミュニケーションを円滑に進めることができる。

【Three.js】perlin-noiseを用いてなだらかな地形を生成する

最近スマホ版のマインクラフトにどハマりしていて、ある時「これthree.jsで作れるのでは?」と思い立ち、作り始めた。

three.jsの記事を色々と探していると、だいたいHTMLにscriptタグでthree.jsを読み込んで、立方体や球を表示させて、回転させてみて、終わり〜という記事ばかりであまり参考にならなかった。

とりあえずNode環境で実装したかったので、npmパッケージを探すところからスタート。

three.jsを扱えるnpmパッケージを使う

www.npmjs.com

以下のような形で使うことができる。

import THREE from 'three.js';
import keyEvents from './keyEvents';
import { createMap } from './map';

const main = function() {
  const scene  = new THREE.Scene(),
    width = window.innerWidth,
    height = window.innerHeight,
    fov = 60,
    aspect = width / height,
    near = 1,
    far = 1000,
    camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
  camera.position.set(0, 20, 0);

  const renderer = new THREE.WebGLRenderer();
  renderer.setSize(width, height);
  document.body.appendChild(renderer.domElement);

  const directionalLight = new THREE.DirectionalLight(0xffffff);
  directionalLight.position.set(0, 0.7, 0.7);
  scene.add(directionalLight);

  // set map
  createMap(scene);

  renderer.render(scene, camera);

  // set key events
  document.addEventListener('keydown', (e) => keyEvents(e, renderer, scene, camera));
}

window.addEventListener('DOMContentLoaded', main, false);

なだらかな地形を生成する

最初は立方体をひたすら敷き詰めて平面を作った。
しかし、実際マインクラフトはいい感じに地形が形成されている。
それっぽくなだらかな凹凸を出すためにはどうすれば良いのか悩んだ結果、perlin-noiseというパッケージを見つけた。

www.npmjs.com

中身を見るととても短い実装だが、とりあえず今は動けば良い。

perlin-noiseの使い方

generatePerlinNoise(width, height)を実行するとwidth * height分のlengthを持った配列が返ってくる。 各要素には0~1の値が格納されており、縦横にループで回すと良い感じのy座標が得られるという仕組みだ。

以下のように実装できる。

import THREE from 'three.js';
import perlin from 'perlin-noise';
import config from './config/blocks';

const X_LENGTH = 100;
const Y_LENGTH = 100;

class Block {
  constructor(x, y, z) {
    this.x = x;
    this.y = y;
    this.z = z;
  }
  setMesh() {
    const material = new THREE.MeshPhongMaterial({ color: config.color, side: THREE.DoubleSide });
    this.mesh = new THREE.Mesh(geometry, material);
    this.mesh.position.set(this.x, this.y, this.z);
  }
  getMesh() {
    return this.mesh;
  }
}

export const createMap = (scene) => {
  const yArray = perlin.generatePerlinNoise(X_LENGTH, Y_LENGTH);
  for (let i = 0; i < X_LENGTH; i++) {
    for (let j = 0; j < Y_LENGTH; j++) {
        const y = Math.round(yArray[i * Y_LENGTH + j] * 3) * 10 - 25;
        const block = new Block(-X_LENGTH*10/2 + i * 10, y, -Y_LENGTH*10/2 + j * 10);
        block.setMesh();
        scene.add(block.getMesh());
    }
  }
};

すると、こんな感じの地形が作れる。

f:id:shibe97:20170328231322p:plain

まとめ

スター数を見た感じ、もっとメジャーなライブラリがありそう。
一旦やりたいことは実現できたので良しとする。

Jestのスナップショット機能を使ってみた

f:id:shibe97:20170320232906j:plain

Jestとは

facebook.github.io

  • Facebook製のテストフレームワーク
  • Reactアプリケーションのテストに向いてる
  • スナップショットテストがある

スナップショットテストとは

  • スナップショット != スクリーンショット
  • 画像の差分を取るのではない
  • 出力されるHTMLの構造を比較する

Worcに導入してみた

shibe97.hatenablog.com

(別件ですが、先日Windowsにも対応しました!)

Worcはかなり細かくコンポーネントを分けているので、試しやすかった。
完全に自分にとっての実験環境になりつつある・・・

対象のコンポーネント

とりあえず今回は、ツイート部分のテキストエリアコンポーネントを対象としてテストを行なった。
以下のようなコンポーネント

  1 import React from 'react';
  2 import styles from './textarea.css';
  3
  4 export default ({ value = '', inputUpdate }) => (
  5   <textarea
  6     className={styles.textarea}
  7     placeholder="What's happening?"
  8     value={value}
  9     onChange={e => inputUpdate(e.target.value)}
10   />
11 );

スナップショット機能の使い方

スナップショット機能を使うにはreact-test-rendererというパッケージが必要。

$ npm i -D jest react-test-renderer

今回は対象のコンポーネントと同階層にテストファイルも置いた。
テストファイルの中身は以下のような感じ。

  1 import React from 'react';
  2 import renderer from 'react-test-renderer';
  3
  4 import Textarea from './Textarea';
  5
  6 describe('components/atoms/textarea', () => {
  7   it('renders correctly', () => {
  8     const tree = renderer.create(
  9       <Textarea value="test" inputUpdate={() => {}} />
10     ).toJSON();
11     expect(tree).toMatchSnapshot();
12   });
13 });

スナップショットが生成される場所

テストを実行すると、テストファイルが置いてある階層に__snapshots__ディレクトリが生成される。
このディレクトリ内にスナップショットファイルが入る。

.
├── Textarea.js
├── Textarea.test.js
├── __snapshots__
│   └── Textarea.test.js.snap
└── textarea.css

生成されたスナップショット

次のようなスナップショットファイルが生成される。

exports[`components/atoms/textarea renders correctly 1`] = `
<textarea
  className="textarea"
  onChange={[Function]}
  placeholder="What\'s happening?"
  value="test" />
`;

テスト時にこのファイルと常に比較され、差分があるとこける。

そのままでは修正するたびにこけてしまうし、意図的な変更をする場合でもテストがこけてしまう。

そこでスナップショットを更新するオプションが用意されている。

$ npm test -- -u

ちなみに--はエスケープの役割だそう。 npm testjestが呼ばれるようにpackage.jsonscriptsに設定してある。

試しに少し変更を入れてテストを走らせてみる

valueの部分にtestという文字列を付け加える。

  1 import React from 'react';
  2 import styles from './textarea.css';
  3
  4 export default ({ value = '', inputUpdate }) => (
  5   <textarea
  6     className={styles.textarea}
  7     placeholder="What's happening?"
  8     value={`${value}test`}
  9     onChange={e => inputUpdate(e.target.value)}
10   />
11 );

この状態でテストを走らせると次のようになる。

f:id:shibe97:20170321215237p:plain

差分がとても分かりやすく表示されている。
オプションを付けてスナップショットを更新するとエラーはなくなる。

Worcでの運用方法

とりあえず以下のようにしてみた。けどもっと良い運用方法あるはず。
皆どうしているんだろうか。

  • 元々push時にCIでnpm testを回していた
  • しかし、CI上でnpm test -- -uしてしまうとスナップショットテスト全て通過してしまうので意味がなくなってしまう
  • そこで、push直前にnpm testして、うまくいった場合にCI上でnpm test -- -uを行う
  • push直前の処理はGit hooksを利用

Git hooksとは

Gitコマンドにフックして何らかの処理を行わせる仕組み。

.git/hooks以下のシェルファイルをいじると動く。

  • pre-commit
  • post-commit
  • pre-push
  • post-push
  • pre-receive
  • post-receive
  • etc…

今回自分はpre-pushを利用。

.git以下はGitHubで共有できないので、postinstall時などに書き換えるようなスクリプトを用意する必要がある

まとめ

スナップショットという単語に興味は持っていたけどずっと触れていなくて、ついに試すことができて良かった。 非常に簡単にテスト実行まで試すことができたので、誰でもさくっと導入できると思う。。

難しいと思うのは運用面で、複数個所がエラーで落ちた際に、本当は正解なのに前回のスナップショットを正としているためエラーとなってしまっているパターンが混ざっていると、その切り分けをしなくてはならないのが大変だと思った。

このあたりはよく考えれば良い解決方法がありそうなので、色々と試していきたい。

関数の魅力を引き出すmap, filter, reduce

f:id:shibe97:20170302175949j:plain

JavaScriptの関数は第一級オブジェクトである。

変数に関数を代入できるし、関数の引数に関数を与えられるし、関数の返り値として関数を返せる。

ES2015で追加されたmap, filter, reduceを使うと今まで何だか綺麗に書けなかったものがスッキリいい感じに書けるようになる。

よくあるJSON配列をごにょごにょと変換する例を挙げていこう。

対象のJSON配列:

const list = [
    {
        id : "1",
        name : "hoge",
        status : "active",
        num : 13,
        children : ["a", "c", "e"]
    },
    {
        id : "2",
        name : "fuga",
        status : "stop",
        num : 22,
        children : ["a", "g"]
    },
    {
        id : "3",
        name : "piyo",
        status : "active",
        num : 57,
        children : ["e", "h"]
    }
];

map

mapを使うと、ある配列を新しい配列に変換できる。 要素数を変えずに他の配列書き換えたい場合に便利。

idだけを抜き出した配列を作りたい

従来の書き方

var ids = [];
for (var i = 0; i < list.length; i++) {
    ids.push(list[i].id);
}

console.log(ids);   // [ '1', '2', '3' ]

mapを使った書き方

const ids = list.map((item) => item.id);

console.log(ids);   // [ '1', '2', '3' ]

idとnameだけを抜き出した配列を作りたい

従来の書き方

var ids = [];
for (var i = 0; i < list.length; i++) {
    ids.push({
        id : list[i].id,
        name : list[i].name
    });
}

console.log(ids);
// [ { id: '1', name: 'hoge' },
//  { id: '2', name: 'fuga' },
//  { id: '3', name: 'piyo' } ]

mapを使った書き方

const ids = list.map(({id, name}) => ({id, name}));

console.log(ids);
// [ { id: '1', name: 'hoge' },
//  { id: '2', name: 'fuga' },
//  { id: '3', name: 'piyo' } ]

filter

filterを使うと、ある配列から必要なものだけを選んだ新しい配列を作ることができる。

statusがactiveのものに絞り込んでidを取得したい

従来の書き方

var activeList = [];
for (var i = 0; i < list.length; i++) {
    if (list[i].status === 'active') {
        activeList.push(list[i].id);
    }
}

console.log(activeList);   // [ '1', '3' ]

filterを使った書き方(mapも用いる)

const activeList = list.filter((item) => item.status === 'active')
                       .map((item) => item.id);

console.log(activeList);   // [ '1', '3' ]

statusがactiveのものがあるかどうかをBool値で取得したい

従来の書き方

var flag = false;
for (var i = 0; i < list.length; i++) {
    if (list[i].status === 'active') {
        flag = true;
    }
}

console.log(flag);   // true

filterを使った書き方(mapも用いる)

const flag = 
    list.filter((item) => item.status === 'active')
    .length > 0;

console.log(flag);   // true

reduce

reduceは配列内の全要素を用いて値やオブジェクトを生成する。 使い方が難しいが、使いこなせると強い。

各要素が保持しているnumの合計値を取得したい

従来の書き方

var sum = 0;
for (var i = 0; i < list.length; i++) {
    sum += list[i].num;
}

console.log(sum);   // 92

reduceを使った書き方(mapも用いる)

const sum = list.map((item) => item.num)
                     .reduce((x, y) => x + y);

console.log(sum);   // 92

各要素が保持しているchildren配列を連結したい

従来の書き方

var children = [];
for (var i = 0; i < list.length; i++) {
    children = children.concat(list[i].children);
}

console.log(children);
// [ 'a', 'c', 'e', 'a', 'g', 'e', 'h' ]

reduceを使った書き方(mapも用いる)

const children = list.map((item) => item.children)
                     .reduce((x, y) => [...x, ...y]);

console.log(children);
// [ 'a', 'c', 'e', 'a', 'g', 'e', 'h' ]

まとめ

for文やforEach文はループ処理であり、returnが存在しないため、ループ処理後は一度式を途切らせなくてはならない。
しかし、mapfilterreduceを用いると次の処理にそのままつなげることができる。
関数型の入り口として知っておいて損はない。

また、ほとんどの処理を1行で書くことができるため、コードが簡潔で済む。
慣れていないと解読する側は大変だが、mapfilterreduceさえ抑えておけば、後々活きてくるだろう。

electron-builderを使ってdmgファイルを生成する

f:id:shibe97:20170216225044p:plain

shibe97.github.io

このサイト上からdmgファイルをダウンロードし、ユーザーの端末上でインストールできるようにした。

Electronアプリからdmgファイルを生成する方法

electron-builderを用いる。

github.com

electron-builderを使うための設定

まず、package.json内に以下のプロパティを設定している必要がある。

  • name
  • description
  • version
  • author

また、electron-builder自身の設定もpackage.json内に記述する。
dependenciesscriptsと並列にbuildというプロパティを設定する。

"build": {
    "appId": "com.electron.worc",
    "mac": {
        "target": "dmg"
    },
    "directories": {
        "output": "docs"
    }
}

appId

アプリの識別子。
MacではCFBundleIdentifier、WindowsではApplication User Model IDとして用いられる。
デフォルトはcom.electron.${name}という形式。

Apple Developer Programに登録していないと警告が出るが、そのままパッケージングは進められる。
Code Signingに関してはこのあたり参照。

github.com

mac

Macにおける設定。
パッケージングファイル形式をdmgにしたい場合はtargetプロパティにそう指定する。

directories

パス関連の設定。
dmgファイルのアウトプット先はoutputプロパティに指定する。
今回はGitHub Pagesにホスティングさせるためにdocsディレクトリを指定した。

その他の設定

github.com

electron-builderを起動する

package.jsonに以下のようにscriptsを登録した。

"scripts": {
    "pack:osx": "build --mac --x64"
},

また、次の作業も必要。

  • electronをdevDependenciesに置く必要がある
  • package.jsonmainプロパティに指定しているファイルをもとにパッケージング処理が走る
  • アプリのアイコンをbuildディレクトリ配下に用意する(ファイル名はicon.icns)

Worcのディレクトリ構成は以下のような感じ(一階層のみ表示)

.
├── README.md
├── app
├── assets
├── build   <= アプリのアイコンを置く
├── dist
├── docs
├── node_modules
├── package.json
└── webpack.config.js

全てが設定済みの状態で先ほどpackage.jsonscriptsに登録したコマンドを叩けば起動する。

$ npm run pack:osx

dmgファイルをGitHub Pagesにホストする

Worcでは、GitHub Pagesを利用してランディングページをホストしている。 ここにdmgファイルも一緒において、ダウンロードしてもらおうと考えた。

しかし、dmgファイルをGitHubにpushしようとすると100MBを超えていて、pushできない現象が陥った。 そこで、Git Large File Storage(LFS)を利用した。

LFSの使い方

下記の手順で行う。(hoge.dmgは適宜、正しいパスに置き換えてください)

$ git lfs install
$ git lfs track hoge.dmg
$ git add .gitattributes
$ git add hoge.dmg
$ git commit -m "add dmg file"
$ git push origin master

git lfs trackを行うと、.gitattributesが生成され、そこに対象のファイルが記述される仕組みとなっている。

これらの作業により、100MB以上のファイルもpushできる。(ただし月に1GBまで、それ以降は有料)
たぶん1ヶ月にそんなに多くリリースしないと思うので、無料でいけるはず・・・。

まとめ

今までelectron-packagerを用いてパッケージングを行なった後、zip形式にし、GitHubのreleaseページにデプロイしていた。

なぜかzipにした後に解凍してみるとアプリケーションが動かなかったり、よくわからない現象が起こって困っていた。
また、GitHubのreleaseページからのダウンロードはあまり良いユースケースとは思えなかったため、ランディングページから直接ダウンロードできるようになって良かった。