あいつの日誌β

働きながら旅しています。

Single Page Application を Serverless Framework と React で作って見ました。

とうわけで S3 に配備しました。API へのアクセスは API Gateway -> Lambda -> DynamoDB なのでそんなにお金かからないはず。しばらくは動かしたままにするのでよかったら下記URLへ訪問してみてください。

http://serverless-fav-articles.s3-website-ap-northeast-1.amazonaws.com/

この作業で覚えた事を備忘録として Qiita に記事を書いたのでそちらも合わせてご覧ください。

Single Page Application を Serverless Framework と React でやる Tutorial(1) https://qiita.com/okamuuu/items/57ef47ac43602fd9e5f9

Single Page Application を Serverless Framework と React でやる Tutorial(2) https://qiita.com/okamuuu/items/06b2c0de27bb267e792a

Single Page Application を Serverless Framework と React でやる Tutorial(3) https://qiita.com/okamuuu/items/4028c86f1ba72bbd12a2

Single Page Application を Serverless Framework と React でやる Tutorial(4) https://qiita.com/okamuuu/items/6e9c0b3e30a1881f5da5

Single Page Application を Serverless Framework と React でやる Tutorial(4) https://qiita.com/okamuuu/items/9082ef45928d98328a9d

こちらからは以上です。

マクロンを除去したい

マクロンとは

マクロン - Wikipedia

マクロンは、ダイアクリティカルマーク(発音区別符号)の一つで、長音記号ともいう。これに対する伝統的な短音記号はブレーヴェである。

どうして除去したいのか?

Google Map を使ったアプリを作ろうと思って reverseGeocoding したら何故かマクロンがついてきてしまい DB にそのまま突っ込むとマクロンあるのと無いので検索結果がずれるのがいやです。

結局こうした

もうちょっとエレガントな書き方できそうな気もしますが...

function deleteMacron(string) {
  return string
    .replace(`Ā`, `A`)
    .replace(`ā`, `a`)
    .replace(`Ī`, `I`)
    .replace(`ī`, `i`)
    .replace(`Ū`, `U`)
    .replace(`ū`, `u`)
    .replace(`Ē`, `E`)
    .replace(`ē`, `e`)
    .replace(`Ō`, `O`)
    .replace(`ō`, `o`)
}

console.log(deleteMacron('Hokkaidō')); // Hokkaido

とりあえずマクロンって言葉検索しづらいですね。

2018年春からフロントエンドを始める為の開発環境構築手順

あらすじ

春ですね。新人研修の準備をしましょう。

動作環境

babel-preset-env はこの記事を作成している時点では version 1 を使っています。しばらくすると version 2になるかもしれません。

% cat package.json                                                                     {
  "name": "practice-frontend",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "dependencies": {
    "babel-cli": "^6.26.0",
    "babel-preset-env": "^1.6.1",
    "http-server": "^0.11.1",
    "webpack": "^4.1.1",
    "webpack-cli": "^2.0.12"
  }
}

準備1: 静的サーバーを用意

mkdir practice-frontend && cd $_ 
mkdir dist
echo 'hello' > dist/index.html
yarn init -y  
yarn add http-server --save-dev 

localhost:8080 で静的サーバーを起動します。

yarn http-server dist

http://localhost:8080 にアクセスして hello が表示される事を確認します。

準備2: babel

mkdir src lib
touch .babelrc
yarn add babel-cli babel-preset-env --save-dev

.babelrc を作成します

{
  "presets": [
    ["env", {
      "targets": {
         "node": "v6.10",
         "ie": 11
      }
    }]
  ]
}

src/Dog.js を作成します。

export default class Dog {

  constructor(voice="bow wow") {
    this.voice = voice;
  }

  say() {
    return this.voice;
  }
}

トランスパイルします。

yarn babel -d lib/ src/

test.js を作成して node test.js を実行して動作を確認します。

var Dog = require('./lib/Dog').default;

var dog1 = new Dog();
var dog2 = new Dog('ruff ruff')

console.log(dog1.say())
console.log(dog2.say())

準備3: webpack 4

webpack は version 4から webpack と webpack-cli が別れたのでそれぞれを install します.

yarn add webpack webpack-cli --save-dev

webpack 4 からはある程度の規約がデフォルトで設定されるので webpack.config.js がなくても動作します。デフォルトではエントリーポイントが src/index.js となっています。先ほどの test.js と少し似ていますが src/index.js を用意します。

import Dog from './Dog';

var dog1 = new Dog();
var dog2 = new Dog('ruff ruff')

console.log(dog1.say())
console.log(dog2.say())

以下を実行すると dist/main.jsコンパイルされたファイルが出力されます。

yarn webpack --mode=development

以下のコマンドが動作することを確認します。

node dist/main.js

準備4: index.html を修正

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>test</title>
</head>
<body>
  hello world
<script type="text/javascript" src="main.js"></script>
</body>
</html>

この状態で yarn http-server dist を実行して http://localhost:8080 にアクセスしてデベロッパーコンソールなどで console.log が犬の鳴き声を出力している事を確認します。

http-server が cache を長くもっている(?)みたいなのでうまく表示されない場合は reload してみたりしてください。

まとめ

駆け足ですが最低限必要な開発環境を構築する手順を紹介しました。

webpack extensions の指定方法

hogehoge.jsrequire(‘hogehoge’) しているなら

resolve: {
  extensions: [".js"]
}

fugafuga.jsxrequire(‘fugafuga’) しているなら

resolve: {
  extensions: [".js", ".jsx"]
}

mogemoge.jsonrequire(‘mogemoge’)しているなら

resolve: {
  extensions: [".js", ".jsx", ".json"]
}

なんですが私は基本的には .js 以外は拡張子をつけて import したほうが良い気がします。つまり以下のようします。

require('hogehoge')
require('mogemoge.json');
require('mogemoge.scss');

webpack 2 以降は以下の記述でOK。

resolve: {
  extensions: [".js"]
}

ちなみに webpack 1 では拡張子無しで import する場合は以下のように空文字を記述していました。

resolve: {
  extensions: ["", ".js"]
}

おしまい

標準偏差の求め方

あらすじ

数学は思ったよりも人生に影響すると思ったので復習しようとおもいました。

標準偏差とは

下記URLをご覧ください。本記事はこちらを参考に Node.js を使って紹介しています。

https://atarimae.biz/archives/5379

標準偏差を求める

主に以下の手順で求めることができます。

  • 平均値を求める
  • 平均値から偏差を求める
  • 偏差から分散を求める

平均値を求める

以下のようなテスト情報があります。

const childMathTests = [
  {name: "A", value: 35},
  {name: "B", value: 55},
  {name: "C", value: 70},
  {name: "D", value: 80}
];

この生徒たちの平均値は以下の通り

(35 + 55 + 70 + 80) / 4 // 60

平均値から偏差を求める

各データの値から平均値を引いた値を求めます。これを偏差と呼びます。

35 - 60 === -25 // A
55 - 60 === -5  // B
70 - 60 === 10  // C
80 - 60 === 20  // D

求めた偏差を2乗します。

(35 - 60) ** 2 === 625
(55 - 60) ** 2 === 25
(70 - 60) ** 2 === 100
(80 - 60) ** 2 === 400

分散を求める

求めた偏差の2乗を合計して 4 で割ります。

(625 + 25 + 100 + 400) / 4 === 287.5

標準偏差を求める

分散の正の平方根を求めます。これがこの4人の数学の標準偏差です。

Math.sqrt((625 + 25 + 100 + 400) / 4) === 16.95582495781317

実装

Node.js では以下のように書けます

const childMathTests = [ 
  {name: "A", value: 35},
  {name: "B", value: 55},
  {name: "C", value: 70},
  {name: "D", value: 80} 
];

const values = childMathTests.map(x => x.value);

function sum(accumulator, currentValue) {
  return accumulator + currentValue;
}

function getStandardDeviation(values) {
  const average = values.reduce(sum) / values.length;
  const deviations = values.map(x => x - average);
  const dispersion = deviations.map(x => x ** 2).reduce(sum) / values.length;
  return Math.sqrt(dispersion);
}

console.log(getStandardDeviation(values));

実践

というわけでテスト結果からばらつきが多いテストかばらつきが少ないテストかを判断できるようになりました。

const childMathTestValues0316 = [0, 5, 10, 70, 80, 80, 82, 85, 93, 95];
const childMathTestValues0318 = [50, 52, 54, 60, 60, 60, 61, 61, 70, 72];

console.log(getStandardDeviation(childMathTestValues0316)); // 36.67151483099655
console.log(getStandardDeviation(childMathTestValues0318)); // 6.6783231428256

0316 はほとんどのが80点以上とっているもしくは一部の生徒が平均点を下げています。つまり平均点付近にあまりマッチする生徒がいない。 0318 はほとんどの人が平均点付近である点数にマッチしています。

両日のテストはどちらも平均点が60点です。どちらのテストも「平均点が60点のテストで70点もとった」という言い方ができます。

なんですがばらつきの多い 0316 ではほとんどの生徒が 80点を超えているので実はそんなにすごくないです。 0318 だと70点を超えている生徒が 2人しかいないのですごいと言えると思います。

まとめ

というわけで標準偏差は学校で習ったようですが(記憶にない)社会に出てから使う機会はないと思っていました。 なんですが使う機会がなかったわけではなく、応用が効く場面に遭遇してもそれを使えてなかった気がします。

そんなわけで久しぶりに数学を勉強してみました。こちらからは以上です。

補足: 平均偏差と標準偏差

偏差を2乗する理由は平均偏差ではばらつきを正しく把握できないケースがあるので、「離れれば離れるほど、ポイントを高くする」という手法が編み出されました。これが標準偏差。2乗して計算したものを平方根で元に戻しています。

MySQL が動かない The server quit without updating PID file

あらすじ

古い MacBook をテスト用のサーバーにしようと思い、OSを更新した後 MySQL を起動しようとしたら MySQL が立ち上がらなくなった。

.. ERROR! The server quit without updating PID file (/usr/local/var/mysql/okamura-MacBook-Pro.local.pid).

というわけで brew uninstall mysqlbrew install mysql を実行。なんだけどうまくいかない。

ログを見る

どうやら initialize のときにすでにファイルがあって処理が中断されたっぽい

/usr/local/Cellar/mysql/5.7.21/bin/mysqld
--initialize-insecure
--user=okamuuu
--basedir=/usr/local/Cellar/mysql/5.7.21
--datadir=/usr/local/var/mysql
--tmpdir=/tmp

2018-03-11T11:29:18.826836Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --exp
licit_defaults_for_timestamp server option (see documentation for more details).
2018-03-11T11:29:18.830393Z 0 [ERROR] --initialize specified but the data directory has files in it. Aborting
.
2018-03-11T11:29:18.830489Z 0 [ERROR] Aborting

たぶん data directory を削除しておけばよかったらしい。削除した後は以下のコマンドでリトライできるっぽい。

Warning: The post-install step did not complete successfully
You can try again using `brew postinstall mysql`

そんなわけで

無事動きました。おしまい。

% sudo rm -fr /usr/local/var/mysql
% brew postinstall mysql
% mysql.server start
Starting MySQL                                                                                               . SUCCESS! 

ES6 の module exports の機能に関するクイズ

突然ですがクイズです。ES6 の module exports の機能として正しいものを選びなさい

問題1

関数毎に export されている場合

export const One = () => (
  <div>one</div>
)

export const Two = () => (
  <div>two</div>
)

以下の記述で呼び出しができる。マルかバツか?

import { One, Two } from '../components/Export'

問題2

export default でオブジェクトに包んで返している

const Three = () => (
  <div>Three</div>
)

const Four = () => (
  <div>Four</div>
)

export default { Three, Four }

以下の記述で呼び出しができる。マルかバツか?

import Default from '../components/ExportDefault'

Default.Three
Default.Four

問題3

export default で関数を返している

const Five = () => (
  <div>Five</div>
)

export default Five

以下の記述で呼び出しができる。マルかバツか?

import Default2 from '../components/ExportDefault2'

Default.Five

答え

以下で調べてみてください

create-react-app practice-es2015-exports && cd $_
getstorybook
mkdir src/components

Export.js

cat << EOS > src/components/Export.js
import React from 'react'
export const One = () => (
  <div>one</div>
)

export const Two = () => (
  <div>two</div>
)
EOS

ExportDefault.js

cat << EOS > src/components/ExportDefault.js
import React from 'react'
const Three = () => (
  <div>Three</div>
)

const Four = () => (
  <div>Four</div>
)

export default { Three, Four }
EOS

ExportDefault2.js

cat << EOS > src/components/ExportDefault2.js
import React from 'react'
const Five = () => (
  <div>Five</div>
)

export default Five
EOS

stories

cat << EOS > src/stories/index.js
import React from 'react';
import { storiesOf, action, linkTo } from '@kadira/storybook';
import { One, Two } from '../components/Export'
import Default from '../components/ExportDefault'
import Default2 from '../components/ExportDefault2'

storiesOf('Answer', module)
  .add('=>', () => (
    <div>
      <One />
      <Two />
      <Default.Three />
      <Default.Four />
      <Default2 />
    </div>
  )); 
EOS

たぶん module exports の挙動で最初は混乱する人が多いと思うのでそんな場合はこれを試してもらうとよいのではないでしょうか。