React.jsで子から親へ イベントを通知する
親コンポーネントのメソッドをコールバック実行するメソッドを
子コンポーネントのpropsに設定するればイベントの通知が可能。
まずイベントを発生させる子コンポーネントを定義する。
var CommentForm = React.createClass({ clickEvent(e){ var cast_value = "渡す値"; this.props.onEventCallBack({ message : cast_value }); return }, render : function(){ return ( <div> <button onClick={this.clickEvent}>click</button> </div> ) } });
次にイベントを検知する親コンポーネントを定義。
var CommentArea = React.createClass({ pushMessage : function(comment){ console.log(comment); }, render : function(){ return ( <div> <CommentForm onEventCallBack={this.pushMessage}/> </div> ) } });
これでCommentFormでクリックイベントが発生した際に
「渡す値」がconsole出力される。
Express4 & React.js 環境を構築
React.js開発環境でググるとBabelとかnpm-scriptsやら色々出てきて
軽くお試しで作るのには色々と面倒なので簡単な環境構築をする。
※ちなみにExpress4のテンプレートを利用します。
とりあえず前提条件で以下のものは導入済みのこと
・npm
・node.js
react-tools のインストール
$ npm install -g react-tools
各ディレクトリの準備
まずJSXファイルを保存するディレクトリを作成する。
今回は public/jsx を作成
続いてjsxのコンパイル先ディレクトリを作成。
これに関してはpublic/javascript/ で問題ない。
これで以下のコマンドを実行すれば自動的にjsxファイルが jsファイルに変換される。
$ jsx -x jsx ./public/react ./public/javascripts/
シェルスクリプトに纏める
このままいくとjsxを編集する度にコンパイルが必要なのでシェルを作成する。
ついでに起動用のコマンドを追記しておく。
start.sh
jsx -x jsx ./public/react ./public/javascripts/ node app.js↲ npm start
後は起動する際に以下のコマンドを実行する。
$ sh start.sh
これでReactの環境構築は完了。
本格的にやるならBabelとかnpm-scriptは必要。
Javascriptでコーディングする際のポイント
1. プリミティブ型は値渡し、オブジェクト型は参照渡し
var user = { "name" : "サンプルユーザー" }; var copy_user = user; copy_user.name = "更新ユーザー" //Object {name: "更新ユーザー"} user //Object {name: "更新ユーザー"}
このように参照元に変更が伝播する。
これが原因で意図しないバグが出るとかよく聞く話。
2. for in は使わない
Object.prototype.bag = "プロトタイプを汚染"; var user = {}; user.name = "SAMPLEユーザー"; for(var key in user){console.log(user(key))} //SAMPLEユーザー , プロトタイプを汚染
プロトタイプが汚染されているとプロトタイプチェーンぬよって こんなバグが発生する。
これのよくある回避方法は hasOwnProperty を使った以下の方法
for(var key in user){ if ( user.hasOwnProperty(key)) console.log(key) }//SAMPLEユーザー
ただ if文 が入るのでネストが深くなる。
ついでに ほぼ影響はないだろうけど全プロパティに評価が実行される問題もある。(速度にほとんど影響はでないだろうけど...)
なので こっちを使う。
Object.keys(user).forEach(function(key){console.log(key)})
こっちの方がスッキリしてるし何より Cool!!
え....for i ?
....知らない子ですね
3. Object型のディープコピー
Object型変数のディープコピーメソッドはネイティブには存在しない。
JSONを使って複製する方法はあることにはあるが、実は完全なディープコピーでは無かったりする。
var user = {}; user.call = function(){console.log("hogehoge")}; user.call() //hogehoge var copy_user = JSON.parse(JSON.stringify(user)); copy_user.call(); //copy_user.call is not a function(…)
このようにfunctionが破壊されてしまっている。
多分ネイティブのみでディープコピーをしようとすると自前でメソッドを実装するしかない。
残念ながら、そんな労力を払う気にはならないので、JQueryの$.extendを使って解決する。
var user = {}; user.call = function(){console.log("hogehoge")}; user.call(); //hogehoge var copy_user = $.extend(true,{},user); copy_user.call();//hogehoge
ちなみにコピーなので変更による伝播は無い。
copy_user.call = function(){console.log("メソッド書き換え")}; user.call(); //hogehoge copy_user.call(); //メソッド書き換え
3. == と ===
== の比較演算子は恐ろしい挙動をとる。
23 == "23" //true null == undefined //true 0 == ''" //true false == '0' //true false == 0 //true
...なんでだよと突っ込みたくなる。
一方 === では
23 == "23" //false null == undefined //false 0 == '' //false false == '0' //false false == 0 //false
どちらが安全なコーディングかは一目瞭然。
とりあえず == を使っているようなら === に書き換えることを お勧めする。
4. グローバル変数の削減
グローバル変数の宣言はアプリケーションで一つのみに制限することが最も良い。
var Main = {}; Main.UserModel = {......} Main.UserController = {.....}
このようにグローバル変数を一つに限定し、
以降 実装に必要な変数は全てグローバル変数のプロパティとして宣言すればいい。
そうすることでグローバル変数の問題から開放されストレスの無いコーディングが可能になる。
注意点としてはグローバル変数から全プロパティにアクセス可能なため
外部からアクセスされたくないメソッド、変数がある場合はクロージャ等で外部からアクセスできないようにする必要がある。
業務系プログラマを目指すということ
自分が業務系プログラマになって約半年が経過した。
結論から言うと自分が業務系プログラマになったのは失敗だったと断言できる。
もし業務系プログラマをこれから目指そうと思う人がいるなら、
この記事の内容を一つの参考にしてほしい。
まず、自分が考えてる業務系プログラマの適正項目は
- プログラムが苦手で可能ならコーディングしたくない
- 単純作業が好き
- 新しい技術に興味が無い
- スーツを着ることに抵抗がない
最後のは怪しいけど、まず上の3項目に関しては然程外れてはいないと思う。
その根拠となるのが業務系システム業界の体質になる。
業務系システム開発で頻繁に登場する言語は
- JAVA
- VB
- C#
- JavaScript(WEBシステムなら要求される)
この辺りが鉄板になってくる。
これ以外の言語はまったく使われず、むしろ却下される事が多い。
詰まるところこの3つさえ使えれば大体の案件には就くことができてしまうので
勉強をする必要がなくなってしまう。
更にある程度経験を積んで30代を迎えると肩書はシステムエンジニア(SE)になり、
設計や顧客との打ち合わせに業務がシフトするのでコーディングは不要になっていく。
業務系プログラマにとってプログラムとは
SEになるための手段となってしまっているわけだ。
なので、少なくともプログラムが好きですという人は絶対に目指してはいけない。
もう一つ、顧客側にも問題がある。
それは納品物に対する品質の保証を開発側に要求してくることだ。
勿論品質の保証を求めることは顧客側にとっては当然のことだし
それを否定するつもりは毛頭ない。
ただ、「品質の保証」の仕方に問題があるのは間違いない。
品質の保証には俗にいうエビデンスが用いられる。
エビデンスが何かを説明すると...
作成したシステムが正常に動いているかどうかを確認するために
テストを行い、その結果を画面をキャプションしてExcelに貼り付けていく作業のことだ。(会社やプロジェクトによって方法は違うけど、大体こんな感じ)
開発規模にもよるけど大体1機能30枚ぐらいのキャプションが貼り付けられる。
機能数が50なら1500枚。
それも顧客に納品するものなので綺麗に取って綺麗に貼り付ける必要がある。
....聞いただけでも効率が悪くて生産性が無いことがわかる。
この辺に文句をつけ始めるとキリがないので割愛するけど、
とりあえず物凄い規模の単純作業だということは理解できると思う。
(勿論テストが不要な訳ではないのでテスト自体は必要)
なら別の形の「品質の保証」をすればいいんじゃないか?
とも思うけど、残念なことに顧客がExcelのエビデンスを求めている以上、
それは諦めるしか無い。
いくら効率的な方法を見つけても、顧客側に受け入れられなければ意味は無い。
だから永遠とExcelエビデンスは量産され続ける。
業務システム開発に携わる限りこのExcelエビデンスという地獄から逃れる術はない。
ここからは主観も混じるけど、
業務系プログラマ及びSEはサラリーマンと大差がないといっても過言じゃない。
ちょっとプログラムが出来るサラリーマンで、エンジニアではない。
勿論、それが駄目だと言うつもりはない。
実際、SEになれば収入もある程度安定していているし、
会社によっては休みもしっかりと確保されている。
普通に生きていくには悪く無い選択肢だと思う。
ただ、技術者として生きていくというのなら話は別で、
そういう人が業務系プログラマになると悲惨な思いをすることになる。
セッションとクッキーの違い
WEBシステムを組むうえで何となく使っているsessionとcookieについて
自分でも違いについて理解できていないと思ったので調べてみました。
HTTPを意識する
セッション、プロトコルの違いを確認する前に、HTTPプロトコルについて確認が必要になると思う。
まず、HTTPプロトコルは状態を持たないということを最初に認識しておく。
HTTPプロトコルではリクエストを送りレスポンスを受け取った時点で、その通信は終了してしまう。
Google先生に 「セッション クッキー 違い」と検索したとする。
その後、もう一度「セッション クッキー 違い」と検索する。
動きとしては…
ユーザー側からGoogle先生に向けて「セッション クッキー 違い」をリクエストし、
Google先生は 「セッション クッキー 違い」に該当するレスポンスを返してくれる。
前者と後者でリクエストとレスポンスの動きに何ら違いはないけど
この同じ動作でも前者と後者は別の通信だと認識されることになる。
HTTPの問題点
さっきの様にリクエストごとに別の通信と認識されるというのは凄く困る。
どんな困ることがあるかというと
簡単な例を挙げると、ログイン画面でログインした後に、そのログイン情報を次の画面に引き継げないといった問題が出てくる。
この場合システム側で何らかの処理をとる必要が出てくる….面倒くさい。
session&cookieはそんな問題を解決してくれる。
本題 sessionとcookieとは?
とりあえず概念は大事。
まずはcookieの概念を確認する。
Cookieとは、Webサイトの提供者が、Webブラウザを通じて訪問者のコンピュータに一時的にデータを書き込んで保存させる仕組み。
CookieにはWebサイト(Webサーバ)側が指定したデータを保存しておくことができ、利用者の識別や属性に関する情報や、最後にサイトを訪れた日時などを記録しておくことが多い。ネットサービスなどのサイトで利用者のIDなどが保存されると、次にアクセスしたときに自動的に利用者の識別が行われ、前回の続きのようにサービスを受けることができる。 -IT用語辞典抜粋
…簡潔に纏めるとこんな感じ
- HTTPヘッダーに格納できるテキストデータ。
- このデータはクライアントのブラウザに保存される。
このcookieを利用すればブラウザに値が格納されているからHTTPプロトコルの値を保持できない問題は解決できる。
でもログイン情報をcookieに格納すれば….という訳にはいかない。
cookieは ”クライアント側に値を保存する” ←これ
クライアント側にあるということはクライアント側で変更が可能な訳で….少し知識のある人なら簡単に改竄出来てしまう。
この問題を解決するのがsessionになる。
セッションとは、活動期間、学期、会期、開催期間、集会などの意味を持つ英単語。コンピュータシステムやネットワーク通信において、接続/ログインしてから、切断/ログオフするまでの、一連の操作や通信のこと
-IT用語辞典抜粋
ちょっと不足気味なので追加
- クライアントとサーバーの通信状態をsessionと呼ぶよ
- sessionにはIDを割り振って管理するね
- 保持されたsessionが欲しいときはIDを指定して取り出してね
といった感じ。
sessionを使えば値はサーバー側に保存されてるためクライアント側からでは操作できない。
これで安心。
ただ、sessionのIDをどうやってサーバーに送信するか という問題がある。
この問題の解決に先ほどのcookieにsessionのIDを持たせてしまう訳です。
cookieにsessionのIDを格納すれば…
サーバー側にsessionのIDを送信することが出来る
クライアント側はsessionのIDは改竄できても関連している中身はサーバーにあるからデータの改ざんは出来ない。
これで安全な通信が可能になる訳です。
まとめ
- クライアント側に値を保存
- データ改竄の可能性あり
session
- サーバー側に保存
- データ改竄の可能性は低い
- 取り出すにはsessionID をサーバーに送信する必要あり
とりあえず機密情報はsessionに格納しておけば安全。
ただ、sessionも万能じゃないから、session使えば絶対に漏洩、改竄されないなんてことはない。
余談
一応sessionIDはcookie以外にもURLやフォームで飛ばしたりすることができる。
色々と問題があるのであるので採用されることはまず無いけど。
多重継承の問題点
オブジェクト指向言語を幾つか触ってからJavaを触っているとinterfaceの存在が気になり始めた。
要は多重継承を回避するためにinterfaceを採用したという話は知ってるけど
そもそも多重継承のデメリットを理解していないから調べてみた。
名前衝突の問題
public class FAX{ public void print(){ //FAXを印刷する実装 } } public class Printer{ public void print() { //用紙を印刷する実装 } }
実装は面倒なのでしませんが、コメントの機能を実装したものと仮定しておく
早速FAXとPrinterを実装したNewPrinterクラスを実装する
FAXも印刷できるPrinterを実装するイメージ
ところが…
両方ともメソッド名が print のため、NewPrintクラス側ではどちらのメソッドを継承するのかが判断できない問題が発生してしまう
これが名前衝突の問題。
ダイアモンド継承の問題
- Baseクラスに「Aと出力するメソッド」print()メソッドを定義する。
- Baseクラス をchild_Aクラスとchild_Bクラスが継承する
- child_Bでprint()メソッドを「Bと出力するメソッド」にオーバーライドする
- child_Aとchild_Bを継承するchild_Cを定義する
こんな実装をしたとして....
このChild_Cでprint()メソッドを使用すると何が出力されるのか…というのがダイアモンド継承問題。
一応答えとしては
- Child_Aに問い合わせる
- Child_Aはprintメソッドを定義していないのでBaseクラスに問い合わせる
- Aが返ってくる
という結果になる。
なぜChild_Bが呼ばれないのか?
それには深さ優先度 という規約が関わっているらしい
深さ優先度とは先に継承したクラスを優先するという規約で、
今回の場合クラス優先度は Child_A > Child_Bになるため
結果としてChild_Bは呼び出されなかった...ということらしい
このダイアモンド継承の問題は片方が呼び出だされないところにあって、
本来実装したい機能を多重継承で実装する際に
「常にどちらが優先されるクラスなのか」を意識しながらコーディングしていくことになり
バグの度に無理矢理実装を追加し続けてクラスの関連性が把握できなくなり
最終的にはクラスがゲシュタルト崩壊してサヨウナラする原因になるとか...恐ろしい
このように多重継承は問題を抱えていますが、その考え方自体はシンプルでいいと思う
ただ、多重継承に限った事ではなく、継承にも言える事で、
継承という方法は既存コードを使いまわせるため便利だけど、
過剰な継承は誰も配線を把握できない爆弾を製造することになるので
過剰継承は控えた方がいいという認識で間違いはない
ちなみに多重継承を採用しているのはC++。
JAVAは冒頭で言ったように禁止(interfaceで多重継承的な実装を実現している)
RubyはMix-inで一応多重継承を採用しているみたい