See the Elephant

渋谷でWebプログラマをやっている25歳が書く日常ブログ

なぜヘッドホンのサイトを作りたいのかリストアップしてみる

  • 自宅にいながら自分にあったヘッドホンを見つけることができるサイト
  • 良いヘッドホンとの出会い
  • 偶然の出会いを大切にしたい. 思ってもみなかった良いものに出会いたい
    • 扱う在庫数の多さ, マイナーからメジャーまで
    • まずは, 自分が持っているもの, ajitoにあるヘッドホンから撮っていこう
    • 人が持っているものは借りてもいいかもしれない
    • あとは, ビックカメラとかe-イヤホンで視聴
      • 多分この作業がコンテンツ作りのコアになる
  • 頭が痺れるような, 心を揺さぶるようなヘッドホンに出会いたい

    • 音質にこだわった録音
      • 録音環境は使用機材にこだわる
        • マイク: Roland CS-10EM
        • レコーダ: Zoom H5
      • 編集ソフトは録音が済んでから考えよう
    • ユーザ層を考えた再生環境を用意
      • 視聴環境は, 庶民的な環境とハイレゾ環境を用意する
        • まずは, iPhone6だけで良い. 庶民的で直刺し用途に.
          • 再生機にお金をかけない人は大多数. 最初はそれで良い
          • 俺もお金ないし, 十分需要はありそう
        • ハイレゾプレイヤーが必要になったら(むしろ自分が欲しくなったら)買う
        • ポタアンとかね. 正直最近はいらないし, And端末の方が良い
    • 対象とする商品
      • ヘッドホン
        • 有線ヘッドホン
        • Bluetoothヘッドホン
        • 録音機材的にヘッドホンが妥当.
      • イヤホン
        • 耳型がないと取れないので一考.
  • 届けたい人

  • 使えるお金は限られているけど, 自分に合うヘッドホンを見つけたい人
  • 地方に住んでいてなかなか視聴の機会を持つことができない人
  • 良いヘッドホンを買ってみたいけど違いがいまいちわからない人

  • 届けたい思い

    • 偶然の出会いを大切にしたい. 思ってもみなかった良いものに出会ってほしい
    • 頭が痺れるような, 心を揺さぶるようなヘッドホンに出会ってほしい
    • 日常の1部分が非日常になるような体験を支えたい

eイヤホンいった感じだと若い層が多い?感じなのかな? きっとお金がないけど良い音で音楽を聞きたい人がいるんだと思う. 自分もその1人だったのでそれを支えられる, 助けられるサイトにしたいな

symfony4 + Reactで自分のサイトを作って見たい2

ヘッドホンに関するwebサイト作りについて案が浮かんだのでメモ

  • ヘッドホンを視聴できるページを作る
  • e-iyahon, amazonへのリンクをはる
    • 決済, 認証システムは持たない
    • アカウントは必要になったら作れるようにする
  • 非常にシンプルな作りにする
    • ajitofmのように超シンプルな作りで良いと思う

ajito.fm

  • 自分が楽しむことを一番にする

symfony4でちょろっと作ってみようかな

Reactの勉強会に行った

Reactとは

勉強会の講師

twitter.com

React とは

  • Componentを作るだけ
  • データの流れは単方向
  • 仮想DOMを扱う

Component

再利用可能なパーツ Componentを作って組み合わせる JSXを使って行く

JSX JSの構文中にXMLをかける

propsとstate

props Component生成時に親から渡されるオブジェクト イミュータブル 外部とのインタフェース

state 動的に値を変化させられる Component内で管理

Componentのライフサイクル

https://qiita.com/kawachi/items/092bfc281f88e3a6e456

Redux

ReduxをつかうことでReactのComponentでは Stateを管理せずにpropsだけを使うようにできる

yarn

パッケージ管理ツール package.jsonで管理する

bable

ecmascriptのトランスコンパイラ ReactはES6で書く ES6はブラウザでそのまま動かない

webpack

アセットを生成するビルドツール 複数のソースを1つにまとめられる

flow

javascriptは動的かたつけ 静的型チェックできる

css modules

cssをComponentごとに持たせられるツール

create-react-appみてみる すぐにreact appのbootupできる

勉強法

公式チュートリアル 自分でちょっとアレンジ Reduxのチュートリアルやる

入門Reactを使用して輪読会 1人React.js Advent Calender 基本的なところが簡潔にまとまっている ライフサイクルの部分は常に見えるところに置いておくとよい

オープンソースにコミット 未マージだけど, 機能追加のコミットを試みた

オープンソースを読む Material-UI

実務での開発 / 実践が一番 手を動かすことが大事 他の人のコードも見れるので良い 教えてもらう

フロントは進化のスピードが早い はてぶ, qiita, SNSを毎日チェック

ランサーズの開発メンバーが書いたブログ公開中

気づき

ポエムを書く.

このブログは技術ブログにしようと思っていたけど,
力が入りすぎて肩が凝るのと,
気が重くなって書く気になれないので考えてること書くためにも使おう.

120%の力を出す

人のツイートを見てふと気づいたことを書く.

よく120%の力を出すっていうけども, これってどういう意味なんだろう, と考える.

120%と聞くと 体壊すくらい頑張って他のこと捨てて必死こいてやる みたいなイメージを受ける.
ちょっとブラックな思想.

実は そんなにハードルが高い, 高尚なことじゃなくて 今できないことをちょっと頑張ってやる というシンプルな意味なのかなと思った.

わからないことが目の前にあった時に, 自分が今できることを元にちょっと強くなるのが120%の力を出すことになるんじゃないのかな, と.

無理すること = 120%じゃないのかもしれない

無理して傷ついてちょっと強くなるのが人間だと僕は思う.
でも, 誰しもむやみやたらに傷つきたいわけではないと思う. そんな無理しなくていいじゃん, 楽しみながらやろうよと思ったりもする.

"本気で考えてもできないこと"ができるるようになった瞬間 = 120%の力が出た瞬間 なんだろうな.

その瞬間の120%がこれからの自分の100%になる.
無理せず楽しみながらわからないことを理解して行くほうが良いなと思えた.

コメントと名前付けの難しさ それに対して僕らができる防衛術

TL;DR

  • 命名はプログラミングの中で重要かつ難しいタスクである
  • コメントが出てきた時点で一考しよう. リファクタリングのチャンス
  • 抽象化は慎重に
  • 仕事を小さくすることで命名は比較的簡単にできる
  • コードに残らない事情はコメントで表明する

あるslackの雑談から始まった

僕が属しているコミュニティであった雑談から.

ういろう [11:26 AM]
結構、コメント書くって難しいよね・・・
コメントと変数名は、プログラム書くより難しいんじゃないかって思ってる。

抽象メソッドにどんなコメントを書くかーみたいなことも今考え中。

okashoi [11:41 AM]
抽象メソッドなら入出力だけわかればいいんじゃないのかな

> コメントと変数名は、プログラム書くより難しいんじゃないかって思ってる。

わかる。プログラミングするときに最も脳のリソースを消費するのは命名かなっておもってる(やや大げさ)

ういろう [11:59 AM]
> プログラミングするときに最も脳のリソースを消費するのは命名かなっておもってる(やや大げさ)
わかる・・・ある程度テンプレートがあるとはいえ、
正解がコード書くより不明瞭で・・・

リーダブルコード読んでも、までこう書くといい!みたいなのがないから難しい (edited)

そう!
プログラミングにおいて 命名はかなり重要 & 難しいタスク だと思う!

今回は, 名前付けやコメントを書くときに自分がどのようにやっているか,

どのようにして名前付けをしやすいコードの書き方をしているか書いていこうと思う.

そもそも一般的に名前付けは難しいのか

ここは, プリンシプル オブ プログラミング から引用する

2.7 名前重要

コードで命名は最重要課題プログラミングにおいて、「命名」を最重要課題として認識し、慎重に取り組むようにしましょう。
「名前を付ける行為」、そして、それを経て生まれた「名前そのもの」、両方に重要な価値があります。

・名前を付ける行為
  適切な名前を付けられたということは、その要素が正しく理解されて、正しく設計されているということです。
  逆に、ふさわしい名前が付けられないということは、その要素が果たすべき役割について、プログラマ自身が十分理解できていないということです。
  適切な名前を付けることができたら、その設計の大部分が完成したと言っても過言ではありません。
  
  
・名前そのもの
  名前は、コードを通じて、プログラマ同士がコミュニケーションするための最大の場となります。
  コードを書いた人と読む人が同時にその場にいて、「リアルタイムの会話」ができることは稀です。
  たいていは「コードを通じての会話」となるので、名前が適切でないと、コード上の会話は成り立ちません。
  このリアルタイムでないコミュニケーションを円滑にするため、名前には最大限の配慮がなされるべきです。

特に大事な部分をpick upする.

コードで命名は最重要課題プログラミングにおいて、「命名」を最重要課題として認識し、慎重に取り組むようにしましょう。

つまり, プログラミングでもっとも頭を使うのは「命名」と考えていいだろう.
上記に記したようにやはり命名は難しいのだ.

ではなぜ命名が難しいのか

ではなぜ命名が難しいのだろうか.
ここに関しては色々意見はあるのだろうが, 僕自身が考える一番の理由は

命名は設計の出来にかなり影響されるから

だと思っている.

...何が言いたいかというと...

名前付けが難しい = 設計がよくない

つまり, プログラマ名前をつけるのが難しい!!!と感じた瞬間に, 設計を見直すべきだよー というサインをコードが教えてくれているのだ.

適切な名前を付けられたということは、その要素が正しく理解されて、正しく設計されているということです。 逆に、ふさわしい名前が付けられないということは、その要素が果たすべき役割について、プログラマ自身が十分理解できていないということです。 適切な名前を付けることができたら、その設計の大部分が完成したと言っても過言ではありません。

例を見て考えてみる

命名(コメントも同様に)が難しいことはわかってきた.
じゃ, その難しさに僕たちはどのように立ち向かっていくべきか考えて行こう.

ということで雑談の続きを例に進めていく. ちなみに, webアプリケーションの話をしていることに留意して欲しい.
コードはphpで書いていく.

ういろう [11:53 AM]
ふむふむ。
ただ、変数名が意味を持ってしまうから、難しいところ。
最低限のコメントあったほうが良いのかなとか。
下のコードのようにやるとやり過ぎなのかなとか。
/*
 * htmlを表示させる
 */
abstract class exClass 
{
  abstract public function show();
}

/*
* データベースからデータを取得して、htmlを表示させる
*/
abstract class exClass 
{
  abstract public function show();
}
ういろう [11:58 AM]
> プログラミングするときに最も脳のリソースを消費するのは命名かなっておもってる(やや大げさ)

わかる・・・ある程度テンプレートがあるとはいえ、 正解がコード書くより不明瞭で・・・
リーダブルコード 読んでも、こう書くといい!みたいなのがないから難しい 

ここまで読んでみるとなんとなく Controllerっぽい挙動を意図したmethodについて話していることがわかる. 読み解ける情報を列挙して行こう.

  1. showというメソッドでhtmlを表示したい
  2. showメソッドに対してhtmlを表示するという役割をコメントで表現しようとしてる
  3. 抽象クラスとして宣言することでいろんなところで使いたい

1つずつ見て行こう.

1. showというメソッドでhtmlを表示したい

まずは, メソッドの役割を明確にしたい.
名前付けにおいてメソッドや変数の役割を日本語で明確に定義する工程は有効である.
なぜならば, 名前付けをする際には名前をつける対象をよく知る必要があるからだ.

日本人が生まれたての女の子に太郎 と名付けないように, 名付けられる対象が持つ特徴や置かれたプロダクトの文化, コードの文脈を理解して初めて名前をつけることができる.

先ほどのコメント htmlを表示するという表現は不明瞭さを含んでいる表現である.

viewとしてhtmlそのものを表示する役割を担っているのか,
controller内の1つのActionとしてhtml形式でresponseを返すのか,
CLIにhtmlを表示するdumpメソッドなのか(多分こんなことはしないけど),

メソッドが担う役割を明確に示す必要がある.

ここでは, controller内の1つのActionとしてhtml形式でresponseを返すという文脈で話を進めていこう.

一般的にはController内のエンドポイントをActionと表現するため, showActionという名前付けが妥当に思える. (もちろん, プロダクトの文化や一貫性にもよるのでshowという名前もなくはないし, Controllerの中で宣言されていればそれはきっとActionだろう)

showAction() のように明確にhttp responseを返しそうな名前付けをすると役割が明確になる.

明確に役割を定義することは名前付けを手助けするのである.

2. showメソッドに対して"htmlを表示する"という役割をコメントで表現しようとしてる

showActionのような名前付けを行なった結果, http responseが返ってきそうなメソッドとして扱えるようになる.
では, もう一度コメントを見てみよう.

  • htmlを表示させる
  • データベースからデータを取得して、htmlを表示させる

どちらもhtmlを表示させることを意識したコメントである.

showActionという名前からhtmlをresponseとして返してくることは容易に想像できると思う. 名前が自分の役割をはっきりと表明していれば, メソッドに対してコメントを書く必要はないのである.

業務委託でいらっしゃっている@t_wadaさんが
コメントが出てきた時点でリファクタリングチャンスとおっしゃっていた.
コメントを書いた時点で一度立ち止まり設計や命名を考え直すべきだろう.

下にサンプルコードを書いてみるが, おそらく読みやすさはそれほど変わらないと思う.

abstract public function showAction();


/*
 * htmlを表示させる
 */
abstract public function showAction();

実装に語らせる

あとは, 実装に語らせるという方法も取れる.
これは変数の命名で役割を明確にする方法である.

例えば, showActionが返しうる値がhtml, json, arrayの3種類だったとしよう.
この場合, 以下のように実装すればコメントは不要となる.

// jsonを返すパターン
public function showAction()
{
  $json = createJsonResponse;
  return $json;
}

// htmlそのものを返すパターン
// 多分あんまりない
public function showAction()
{
  $html = createHtmlResponse;
  return $html;
}

// テンプレートにレンダリングするパラメタを返すパターン
public function showAction()
{
  $response = [];
  $response = createResponseParams();
  return $response;
}

リーダブルコードにもあるが, 変数名は短いコメントと考えておくことが大切である.
メソッドと変数に対して正確に役割を示す端的な名前をつけておくことで, 名前に役割を説明させることができるのである.

これによって必然的にコメントは減っていく. コメントを減らすことでメンテナンスコストが下がるのも嬉しい部分である.

3. 抽象クラスとして宣言することでいろんなところで使いたい

抽象化(abstract), 実はこれも難しい.

これは命名とは別の話であるが,
実際早すぎる抽象化は命名を難しくすることもあるので触れておこう.

DRY (Don't Repeat Yourself), 同じものを繰り返すなという有名な言葉がある.
これに素直に従うと抽象化を急いでしまう.

実はこれも慎重に行うべきで, 早すぎる抽象化は負債化することがある.

YAGNI You ain't gonna need it: 実際に必要となるまでは追加しないとも呼ばれるが, 同じようなパターンが出現していない時点で想像で抽象化を行うと使われず, いじりにくいコードとなり負債化する.
同じような実装が3回,4回登場した時点で抽象化を始めても遅くはないのだ.

例えば, 2. showメソッドに対して"htmlを表示する"という役割をコメントで表現しようとしてるで示した例のように同じような役割で少しだけ実装が違うようなものが3回, 4出現した時に初めて抽象化を考えればいい.

@t_wadaさんとペアプロした時におっしゃっていた言葉を引用しよう.

通化は2out, 3outしてから考えていい. 1回目で共通化しようとしても将来生まれる需要と食い違って使われないことが多い. 2,3回, いや, 3,4回くらい同じコードを見てから共通化しても遅くない.

設計として正しくない場所に抽象化した概念を置いてしまった場合,
無理に抽象概念を使いまわそうとすると設計に歪みが生まれる.
これによって, 役割が複雑になってしまい命名が難しくなる.

このような副作用もあるため抽象化は慎重になるべきである.

命名の難しさへの防衛術

つらつらと述べてきたように, 変数やメソッドの名前がうまく決まらない(コメントが必要な程度に複雑さを持っている)場合は変数, メソッドの場所がおかしい/役割が多いことを示している. なのでコメント書いた時点で一旦考えてよいとおもう.

では, どのようにしてその複雑さや難しさを回避していくか.

3つの手順を踏むことでその難しさを軽減することができる. ここからは, コードで示しながら進めていく.

これは大きなメソッド(多分こういったメソッドにコメントが生えがち)をリファクタリングするときに使える手法である.

1: まずはやりたいメソッドをべたっと1つのメソッドに書く(もしくは最初からある)

class exController
{
  // requestを受けて新規データを作成する
  public function createAction($request)
  {
    process1
    process2
    process3
    process4
    process5
    process6
    process7
    process8
    return process9
  }
}

2: メソッドの処理を役割ごとにブロック化してそれぞれにコメントをつけていく

class exController
{
  // requestを受けて新規データを作成する
  public function createAction($request)
  {
    // request parse する
    process1
    
    // requestのvalidation
    process2
    process3
    process4
    
    // requestからentity作る
    process5
    process6
    
    // ORMにentity登録してdbにinsert
    process7
    process8
    
    // response返す
    return process9
  }
}

3: コメントごとにmethodに切り出す

class exController
{
  public function createAction($request)
  {
    $req = parseRequest($request)
    validateRequest($req)
    $entity = createEntityByRequest($req)
    insertEntity($entity)
    
    return process9
  }
}

public function parseRequest($request)
{
  return process1
}

public function validateRequest($request)
{
    process2
    process3
    return process4
}

public function createEntityByRequest($request)
{
    process5
    return process6
}

public function insertEntity($entity)
{
    process7
    return process8
}

実コードでこのやり方を実践すると, きっと初期状態よりもずっと追いやすく読みやすいコードになるだろう(この例だと初期状態が複雑に見えないためメリットを感じづらいが, やってみると効果が実感できると思う)

上記のようなフローでコード書くと, 以下のような良さがある

  1. まずべたっと1枚岩でコードを書くことで処理の流れをそのまま表現でき書きやすい
  2. 分割した後はメソッドの役割がシンプルになり命名しやすい
    • メソッドや変数の仕事が少なくなるため役割がシンプルになる
    • その結果, 副次的に命名がしやすくなる
  3. 各メソッド, 変数の役割や仕事が小さくなるため状態管理が楽, かつ, 汎用的になる
    • メソッドの使い回しが効くようになる
  4. 変数のスコープが小さく, 状態管理が楽なのでテストしやすい
    • 参照透過性も守りやすい

コメントを書かなければならない場合もある

コメントを書かなければいけない場合もある.
これはコードでは表現できない事情や背景がある場合である.
これらはコメントで残さなければ後に残っていかないため, コメントに残すべきである.

パフォーマンス上の制約でしぶしぶ選んだ選択や事業的な理由など, コードそのものでは示せないものはコメントに残すべきである.

裏返せば, コードを読めばわかることはコメントに書くべきではない ということを示している.

コメントを書いた時点で立ち止まる癖は付けても良いだろう

まとめ

  • 命名はプログラミングの中で重要かつ難しいタスクである
  • コメントが出てきた時点で一考しよう. リファクタリングのチャンス
  • 抽象化は慎重に
  • 仕事を小さくすることで命名は比較的簡単にできる
  • コードに残らない事情はコメントで表明する

Fluxとは何か MVC, MVVMとの違いも含めて

動機

仕事で, React + Redux + TypeScirpt + WebPackを使うことになりそうなので学んでいく.
そもそもjsに疎いので探り探りやっていく.
間違えもあるかもしれないが, 徐々にやっていこう.

TL;DR

  • Fluxとは, アプリケーションのデータフロー管理のためのアーキテクチャパターン
  • イベント駆動であり, 一方向のデータフロー制御を行う
  • Fluxの特徴は, Viewで独立したデータを持つ, データ状態を一方向のフローで制御, Event駆動である.
  • FluxはAction, Dispatcher, Store, Viewの4要素で構成される.

Reduxとは

Reduxとは, Facebookが提唱, 開発しているJsApp.
jsにおいて, データの状態(データの流れ)を管理するためのツールである.
ReduxはFluxの実装と聞いたことがあるので, Reduxの前にFluxについて学んでいこう.
FluxもFacebookが提唱しているアーキテクチャである.

Fluxとは

qiita.com github.com

FB公式から抜粋

Flux is a pattern for managing data flow in your application.
The most important concept is that data flows in one direction.
Fluxとは, アプリケーションのデータフロー管理のためのアーキテクチャパターンである.   
もっとも重要なコンセプトは`データフローが一方向にしか流れないこと`である.  

JavaScriptでWebページのデータを制御する際に, データの状態制御が複雑になりやすい.

Fluxはデータの流れを一方向に限定することで状態遷移を単純にし, データ状態の複雑さを軽減させようとする考え方である.

あくまでも考え方なので, 実装は伴わない.
RESTの実装がHTTPのように, Fluxの実装がReduxという関係性なのかなと想像している.
Reduxの源流なので, Fluxから追っていこうと思う.

Fluxのアーキテクチャ

https://github.com/facebook/flux/raw/master/examples/flux-concepts/flux-simple-f8-diagram-with-client-action-1300w.png

図をみると, 4つのパーツから構成されていることがわかる.

  • Dispatcher
  • Store
  • Action
  • View

データは必ず以下の動作で変更されていく.

  1. 何らかのActionがあり(Apiからのレスポンス, ViewEvent), Dispatcher がその全てを受ける.
  2. DispatcherStoreActionを伝搬.
  3. Storeは, Dispatcherから受けたAction によってデータの状態を変更. change eventを発火する.
  4. Storeのデータ状態が Viewに渡される. change eventでトリガーされる.
  5. ViewStore から受けたデータを表示.
  6. Viewで何らかの Actionが発生. 1に戻る.

storeは必ずしも1つではなく複数個持てる.
todoアプリであれば, 未消化タスク, 消化済みタスクstoreを分けることが可能である.

https://camo.qiitausercontent.com/0c5e672d5d5c6a46a84a54d407fd8d5c3ca3a280/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3133343239342f34363066366666332d666434382d393839612d336633302d6135326330623863646339392e706e67

Fluxとはなんなのか より引用

Fluxのなにがいいのか

Fluxとはなんなのかより引用するが,
Fluxを導入すると以下のメリットがあると言える

  • ViewにEvent(Action)の発行元だけ持たせ, App全体をEventDrivenにした
  • Storeに状態や副作用を集約したことで, そこ以外では参照等価になった.
    • これにより, App全体の見通しがよくなった

個人的にまだよくわかっていないこと

MVC, MVVCとの違い

正直, MVC(Model/View/Controller)との違いがそれほど大きくわかってない. MVVC(Model/View/ViewModel/Contoller)もそうだが, Viewの中の話でほぼ終始しているような気がする.

一回整理してみよう

MVC

MVCについて振り返る. at-grandpa.hatenablog.jp より図を引用.

https://cdn-ak.f.st-hatena.com/images/fotolife/a/at_grandpa/20131101/20131101070231.png

ViewModelの状態を参照しているだけ.
ViewはあくまでもModelの状態を表示しているだけで, ユーザの入力はControllerを伝ってModelで処理されデータの状態が変化する. サーバサイドレンダリングで作ったページを思い浮かべると良さそう.
Viewの中でデータの状態そのものは気にせず, ユーザの明示的な操作(formのPOSTなど)としてフォームの値が渡ってくるイメージ.
(Viewの中でformデータなどの状態はあるがDOMで閉じる)

MVVM

qiita.com より図を引用.

https://camo.qiitausercontent.com/d92ae1332c66d98e07f9b0c830bb28f49a4b2804/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f31353930322f62336361613534312d313535662d346162642d373436632d3966303335323137646634382e6a706567

MVC の場合は, ViewModelを直接参照していた.
MVVM では, ViewModelの間にViewModelという中間層を置く.

  • ViewViewModelの状態を参照し, ViewModelは常にViewの入力を監視する.
  • Viewに対する入力(Event)があれば, 即座に検知してViewModelの状態が変わる.
  • 逆にViewModelの状態が変わればViewの表示が変更される.

これを, Two-way data Bindingと呼ぶ.

Modelの状態変更は, ユーザの明示的な操作(formのPOSTなど)によって行われる. このとき, ViewModelの状態がModelに反映される.

この図には, Controller が存在しないが ModelViewModelの間にControllerがある.
言い換えれば, MVVMCとなる.

Flux

f:id:namu_r21:20180321205524j:plain

Fluxの場合は, 上のような図になる. MVCと比較するためあえてMCを書いている.
Fluxは Fluxのアーキテクチャ で述べた通り, データフローが一方向に制御されるコンセプトを持っている.

こうやって見てみると, MCVで明確な境界線がある.
View側で独立のデータを持ち, データ状態の制御だけに関心をあてているのがFluxである.
Viewで独立のデータ構造をもつアプリケーション, と考えてしまえばMVVMとそう変わらない

MVVMと比較すると, ViewModelStoreとなり, データの方向制御のためにDispatcherが登場したという形になる. Fluxでは, EventActionと呼ぶためここは同義として見て良いだろう.

MVC, MVVM, Fluxの違い まとめ

こうやってMVC, MVVM, Fluxを同じ構成で見てみると,
実はどれもMVCの延長線上にあることがわかる. というか, そもそもVIewのデータフローアーキテクチャなのでMCとは関係ないものである. そもそも関心ごとが違うので比較するまでもなかった.

MVCMVVM, Fluxで大きく異なるのは, View側にサーバ(Model, Controller)とは独立したアプリケーションがあり, Viewで独立したデータ状態を持つ/制御することであろう.
ここさえ理解すれば, MVVM, Fluxはあくまでもデータフローが双方向か一方向かの違いしかないことに気づける.

まとめ

  • Fluxの特徴は, Viewで独立したデータを持つ, データ状態を一方向で制御, Event駆動である.
  • Actionを起因としたイベント駆動であり, 一方向のデータフロー制御を行うアーキテクチャ
  • FluxはAction, Dispatcher, Store, Viewの4要素で構成される.
  • MVVM, FluxはMVCの延長線上にある概念
  • MVCとの大きな違いは, Viewで独立したデータを持つことである.
  • MVVMとの大きな違いは, Viewのデータフローの方向性が一方向であることである.

symfony4 + Reactで自分のサイトを作って見たい

自分のサイトを作ってみたい

Symfony4 + Reactでゆるふわにアプリを作ってみたい. ヘッドホンが好きなのでヘッドホンをレコメンドするWebアプリを作ってみよう. 仕事でコードを書く時間とは別に自分のためにコードを書いてみたい

どうせならということで新しい環境で作って見たい. PHP 7.2, Symfony4.1 + React(むずかったらVue2系)で作ろう.

導入

まずはphpを入れよう. phpbrewを入れる.

$ brew install phpbrew
$ phpbrew install 7.2.2 +openssl=$(brew --prefix openssl)
===> phpbrew will now build 7.2.2
===> Loading and resolving variants...
Checking distribution checksum...
Checksum matched:
===> Distribution file was successfully extracted, skipping...
===> Checking patches...
Checking patch for replace apache php module name with custom version name
Found existing build.log, renaming it to /Users/shuzon/.phpbrew/build/php-7.2.2/build.log.1519736915
===> Configuring 7.2.2...


Use tail command to see what's going on:
   $ tail -F /Users/shuzon/.phpbrew/build/php-7.2.2/build.log


===> Checking patches...
Checking patch for php5.3.29 multi-sapi patch.
Checking patch for php5.3.x on 64bit machine when intl is enabled.
Checking patch for openssl dso linking patch
3 changes patched.
===> Building...
Build finished: 4.5 minutes.
Installing...
---> Creating php-fpm.conf
---> Creating php.ini
---> Copying /Users/shuzon/.phpbrew/build/php-7.2.2/php.ini-development
---> Found date.timezone is not set, patching...
---> Found date.timezone, patching config timezone with Asia/Tokyo
Congratulations! Now you have PHP with 7.2.2 as php-7.2.2

* To configure your installed PHP further, you can edit the config file at
    /Users/shuzon/.phpbrew/php/php-7.2.2/etc/php.ini

* WARNING:
  You haven't setup your .bashrc file to load phpbrew shell script yet!
  Please run 'phpbrew init' to see the steps!

To use the newly built PHP, try the line(s) below:

    $ phpbrew use php-7.2.2

Or you can use switch command to switch your default php to php-7.2.2:

    $ phpbrew switch php-7.2.2

Enjoy!

$ phpbrew init
Using root: /Users/shuzon/.phpbrew
Initialization successfully finished!
<=====================================================>
Phpbrew environment is initialized, required directories are created under

    /Users/shuzon/.phpbrew

Paste the following line(s) to the end of your ~/.bashrc and start a
new shell, phpbrew should be up and fully functional from there:

    source /Users/shuzon/.phpbrew/bashrc

To enable PHP version info in your shell prompt, please set PHPBREW_SET_PROMPT=1
in your `~/.bashrc` before you source `~/.phpbrew/bashrc`

    export PHPBREW_SET_PROMPT=1

To enable .phpbrewrc file searching, please export the following variable:

    export PHPBREW_RC_ENABLE=1


For further instructions, simply run `phpbrew` to see the help message.

Enjoy phpbrew at $HOME!!

$ phpbrew switch php-7.2.2

php 7.2.2が入った

symfony4を入れる

http://symfony.com/doc/master/setup.html めっちゃこけた

$ composer create-project symfony/website-skeleton headphone-recommend
PHP Fatal error:  Uncaught Error: Call to undefined function Composer\Json\json_decode() in phar:///usr/local/Cellar/composer/1.6.3/libexec/composer.phar/src/Composer/Json/JsonFile.php:153
Stack trace:
#0 phar:///usr/local/Cellar/composer/1.6.3/libexec/composer.phar/src/Composer/Factory.php(290): Composer\Json\JsonFile->validateSchema(1)
#1 phar:///usr/local/Cellar/composer/1.6.3/libexec/composer.phar/src/Composer/Factory.php(576): Composer\Factory->createComposer(Object(Composer\IO\ConsoleIO), './composer.json', false)
#2 phar:///usr/local/Cellar/composer/1.6.3/libexec/composer.phar/src/Composer/Console/Application.php(338): Composer\Factory::create(Object(Composer\IO\ConsoleIO), NULL, false)
#3 phar:///usr/local/Cellar/composer/1.6.3/libexec/composer.phar/src/Composer/Console/Application.php(451): Composer\Console\Application->getComposer(false, false)
#4 phar:///usr/local/Cellar/composer/1.6.3/libexec/composer.phar/src/Composer/Console/Application.php(149): Composer\Console\Application->getPluginCommands()
#5 phar:///usr/lo in phar:///usr/local/Cellar/composer/1.6.3/libexec/composer.phar/src/Composer/Json/JsonFile.php on line 153

Fatal error: Uncaught Error: Call to undefined function Composer\Json\json_decode() in phar:///usr/local/Cellar/composer/1.6.3/libexec/composer.phar/src/Composer/Json/JsonFile.php:153
Stack trace:
#0 phar:///usr/local/Cellar/composer/1.6.3/libexec/composer.phar/src/Composer/Factory.php(290): Composer\Json\JsonFile->validateSchema(1)
#1 phar:///usr/local/Cellar/composer/1.6.3/libexec/composer.phar/src/Composer/Factory.php(576): Composer\Factory->createComposer(Object(Composer\IO\ConsoleIO), './composer.json', false)
#2 phar:///usr/local/Cellar/composer/1.6.3/libexec/composer.phar/src/Composer/Console/Application.php(338): Composer\Factory::create(Object(Composer\IO\ConsoleIO), NULL, false)
#3 phar:///usr/local/Cellar/composer/1.6.3/libexec/composer.phar/src/Composer/Console/Application.php(451): Composer\Console\Application->getComposer(false, false)
#4 phar:///usr/local/Cellar/composer/1.6.3/libexec/composer.phar/src/Composer/Console/Application.php(149): Composer\Console\Application->getPluginCommands()
#5 phar:///usr/lo in phar:///usr/local/Cellar/composer/1.6.3/libexec/composer.phar/src/Composer/Json/JsonFile.php on line 153

requirement

http://symfony.com/doc/master/reference/requirements.html

うまく動かない

phpbrew install 7.1.3 +openssl=$(brew --prefix openssl)

うーむ, だめだ

phpbrewではうまく動かない

$ brew install homebrew/php/php72
$ echo 'export PATH="$(brew --prefix homebrew/php/php72)/bin:$PATH"' > ~/.zshrc
$ php -v
PHP 7.2.2 (cli) (built: Feb  1 2018 11:50:40) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies

これで動いた.

$ composer create-project symfony/website-skeleton headphone-recommend
Installing symfony/website-skeleton (v4.0.3)
  - Installing symfony/website-skeleton (v4.0.3): Downloading (100%)
Created project in headphone-recommend
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 88 installs, 0 updates, 0 removals
  - Installing ocramius/package-versions (1.3.0): Downloading (100%)
  - Installing symfony/flex (v1.0.70): Downloading (100%)

Prefetching 86 packages 🎵
  - Downloading (100%)

  - Installing doctrine/lexer (v1.0.1): Loading from cache
  - Installing doctrine/inflector (v1.3.0): Loading from cache
  - Installing doctrine/collections (v1.5.0): Loading from cache
  - Installing doctrine/cache (v1.7.1): Loading from cache
  - Installing doctrine/annotations (v1.6.0): Loading from cache
  - Installing doctrine/common (v2.8.1): Loading from cache
  - Installing symfony/polyfill-mbstring (v1.7.0): Loading from cache
  - Installing symfony/http-foundation (v4.0.4): Loading from cache
  - Installing symfony/yaml (v4.0.4): Loading from cache
  - Installing symfony/webpack-encore-pack (v1.0.2): Loading from cache
  - Installing psr/link (1.0.0): Loading from cache
  - Installing fig/link-util (1.0.0): Loading from cache
  - Installing symfony/web-link (v4.0.4): Loading from cache
  - Installing symfony/filesystem (v4.0.4): Loading from cache
  - Installing symfony/config (v4.0.4): Loading from cache
  - Installing symfony/http-kernel (v4.0.4): Loading from cache
  - Installing symfony/event-dispatcher (v4.0.4): Loading from cache
  - Installing psr/log (1.0.2): Loading from cache
  - Installing symfony/debug (v4.0.4): Loading from cache
  - Installing psr/container (1.0.0): Loading from cache
  - Installing symfony/dependency-injection (v4.0.4): Loading from cache
  - Installing egulias/email-validator (2.1.3): Loading from cache
  - Installing swiftmailer/swiftmailer (v6.0.2): Loading from cache
  - Installing symfony/swiftmailer-bundle (v3.2.0): Loading from cache
  - Installing symfony/translation (v4.0.4): Loading from cache
  - Installing symfony/validator (v4.0.4): Loading from cache
  - Installing symfony/serializer (v4.0.4): Loading from cache
  - Installing symfony/inflector (v4.0.4): Loading from cache
  - Installing symfony/property-info (v4.0.4): Loading from cache
  - Installing symfony/property-access (v4.0.4): Loading from cache
  - Installing psr/simple-cache (1.0.0): Loading from cache
  - Installing psr/cache (1.0.1): Loading from cache
  - Installing symfony/cache (v4.0.4): Loading from cache
  - Installing webmozart/assert (1.3.0): Loading from cache
  - Installing phpdocumentor/reflection-common (1.0.1): Loading from cache
  - Installing phpdocumentor/type-resolver (0.4.0): Loading from cache
  - Installing phpdocumentor/reflection-docblock (4.3.0): Loading from cache
  - Installing symfony/serializer-pack (v1.0.1): Loading from cache
  - Installing symfony/security (v4.0.4): Loading from cache
  - Installing symfony/security-bundle (v4.0.4): Loading from cache
  - Installing symfony/process (v4.0.4): Loading from cache
  - Installing monolog/monolog (1.23.0): Loading from cache
  - Installing symfony/monolog-bridge (v4.0.4): Loading from cache
  - Installing symfony/monolog-bundle (v3.1.2): Loading from cache
  - Installing symfony/routing (v4.0.4): Loading from cache
  - Installing symfony/finder (v4.0.4): Loading from cache
  - Installing symfony/framework-bundle (v4.0.4): Loading from cache
  - Installing symfony/console (v4.0.4): Loading from cache
  - Installing zendframework/zend-eventmanager (3.2.0): Loading from cache
  - Installing zendframework/zend-code (3.3.0): Loading from cache
  - Installing ocramius/proxy-manager (2.2.0): Loading from cache
  - Installing doctrine/dbal (v2.6.3): Loading from cache
  - Installing doctrine/migrations (v1.6.2): Loading from cache
  - Installing symfony/doctrine-bridge (v4.0.4): Loading from cache
  - Installing doctrine/doctrine-cache-bundle (1.3.2): Loading from cache
  - Installing jdorn/sql-formatter (v1.2.17): Loading from cache
  - Installing doctrine/doctrine-bundle (1.8.1): Loading from cache
  - Installing doctrine/doctrine-migrations-bundle (v1.3.1): Loading from cache
  - Installing doctrine/instantiator (1.1.0): Loading from cache
  - Installing doctrine/orm (v2.6.0): Loading from cache
  - Installing symfony/orm-pack (v1.0.5): Loading from cache
  - Installing symfony/options-resolver (v4.0.4): Loading from cache
  - Installing symfony/intl (v4.0.4): Loading from cache
  - Installing symfony/polyfill-intl-icu (v1.7.0): Loading from cache
  - Installing symfony/form (v4.0.4): Loading from cache
  - Installing symfony/expression-language (v4.0.4): Loading from cache
  - Installing symfony/polyfill-php72 (v1.7.0): Loading from cache
  - Installing symfony/var-dumper (v4.0.4): Loading from cache
  - Installing symfony/phpunit-bridge (v4.0.4): Loading from cache
  - Installing twig/twig (v2.4.4): Loading from cache
  - Installing symfony/twig-bridge (v4.0.4): Loading from cache
  - Installing symfony/web-profiler-bundle (v4.0.4): Loading from cache
  - Installing symfony/twig-bundle (v4.0.4): Loading from cache
  - Installing symfony/stopwatch (v4.0.4): Loading from cache
  - Installing symfony/profiler-pack (v1.0.3): Loading from cache
  - Installing easycorp/easy-log-handler (v1.0.4): Loading from cache
  - Installing symfony/debug-bundle (v4.0.4): Loading from cache
  - Installing symfony/debug-pack (v1.0.4): Loading from cache
  - Installing symfony/asset (v4.0.4): Loading from cache
  - Installing sensio/framework-extra-bundle (v5.1.6): Loading from cache
  - Installing symfony/dom-crawler (v4.0.4): Loading from cache
  - Installing symfony/browser-kit (v4.0.4): Loading from cache
  - Installing symfony/css-selector (v4.0.4): Loading from cache
  - Installing symfony/dotenv (v4.0.4): Loading from cache
  - Installing symfony/maker-bundle (v1.1.1): Loading from cache
Writing lock file
Generating autoload files
ocramius/package-versions:  Generating version class...
ocramius/package-versions: ...done generating version class
Symfony operations: 20 recipes (3447d53bbbd23ec42f0eca52a31cb31b)
  - Configuring symfony/flex (>=1.0): From github.com/symfony/recipes:master
  - Configuring symfony/framework-bundle (>=3.3): From github.com/symfony/recipes:master
  - Configuring doctrine/annotations (>=1.0): From github.com/symfony/recipes:master
  - Configuring symfony/webpack-encore-pack (>=1.0): From github.com/symfony/recipes:master
  - Configuring symfony/swiftmailer-bundle (>=2.5): From github.com/symfony/recipes:master
  - Configuring symfony/translation (>=3.3): From github.com/symfony/recipes:master
  - Configuring symfony/security-bundle (>=3.3): From github.com/symfony/recipes:master
  - Configuring symfony/monolog-bundle (>=3.1): From github.com/symfony/recipes:master
  - Configuring symfony/routing (>=4.0): From github.com/symfony/recipes:master
  - Configuring symfony/console (>=3.3): From github.com/symfony/recipes:master
  - Configuring doctrine/doctrine-cache-bundle (>=1.3.2): From auto-generated recipe
  - Configuring doctrine/doctrine-bundle (>=1.6): From github.com/symfony/recipes:master
  - Configuring doctrine/doctrine-migrations-bundle (>=1.2): From github.com/symfony/recipes:master
  - Configuring symfony/phpunit-bridge (>=3.3): From github.com/symfony/recipes:master
  - Configuring symfony/web-profiler-bundle (>=3.3): From github.com/symfony/recipes:master
  - Configuring symfony/twig-bundle (>=3.3): From github.com/symfony/recipes:master
  - Configuring easycorp/easy-log-handler (>=1.0): From github.com/symfony/recipes:master
  - Configuring symfony/debug-bundle (>=3.3): From github.com/symfony/recipes:master
  - Configuring sensio/framework-extra-bundle (>=4.0): From github.com/symfony/recipes:master
  - Configuring symfony/maker-bundle (>=1.0): From github.com/symfony/recipes:master
Executing script cache:clear [OK]
Executing script assets:install --symlink --relative public [OK]

Some files may have been created or updated to configure your new packages.
Please review, edit and commit them: these files are yours.


 What's next?


  * Run your application:
    1. Change to the project directory
    2. Execute the php -S 127.0.0.1:8000 -t public command;
    3. Browse to the http://localhost:8000/ URL.

       Quit the server with CTRL-C.
       Run composer require server --dev for a better web server.

  * Read the documentation at https://symfony.com/doc


 Database Configuration


  * Modify your DATABASE_URL config in .env

  * Configure the driver (mysql) and
    server_version (5.7) in config/packages/doctrine.yaml


 How to test?


  * Write test cases in the tests/ folder
  * Run php bin/phpunit

かなり長くなったので今回はここまで