ビューティフルWebコードスマートフォン用の表示で見るビューティフルWebコード美しいWebサイトのコーディングについて説明をしていきます。この広告は、90日以上更新していないブログに表示しています。MVCエラー処理はとても重要!でも大変なので、ルールを決めよう!エラー処理(例外処理)は非常に重要な処理です。真面目に処理しようとしたら、正常系のコードよりもエラー処理のコードの方が多くなっていくと思います。どのプログラム言語もtry-catchなどの例外処理が言語仕様として組み込まれていると思います。それぞれのエンジニアがそれぞれ思い思いにエラー処理を実装していたのでは、とてもいい品質のコードはできません。効率よく開発するためにエラー処理にもルールを設ける必要があります。エラーの種類を大別する!自分は、エラーの種類は以下の2種類があると考えています。自己復帰できないエラー(システムエラー)これらを以下のように定義します。自己復帰できるエラーとは障害ではない。ログレベルで言うならWARN。ユーザが自分の力で復帰できるのが望ましい。やり直しをさせることで、処理を完了することができる。URLのパラメータ改ざんによりDB検索をしたがデータが存在しなかった。Cookieが改ざんされた。自己復帰できないエラー(システムエラー)障害。ログレベルで言うならERROR、FATALインフラ障害(ネットワーク、DB)バグエラー処理の実装を開発者にどう伝えるか自分がリーダーだったら、こうします。エラー処理はするな!え?って思われるかもしれません。要件や、詳細設計としてフローチャート、シーケンス図レベルで記載されるロジックエラーについては、それぞれのエンジニアに任せましょう。それ以外のエラー処理に関しては一切エラー処理をするな!と言います。すべてのエラーを共通エラー処理に集めてしまい、そこでエラー処理を行います。なるかを考えていきましょう。いうURLについて考えてみます。以下の処理が行われるものとします。UsersControllerのIndexActionメソッドが呼び出される。DBからid=1234のユーザを検索する。検索結果をViewに渡して表示する。この中で、どういうエラーが発生するか、異常系を考えてみます。id=1234のユーザが存在しなかった。そもそもバグがあって、プロダクトコード内で実行中に例外が発生した。設定が間違って(DBの接続文字列が変わって)いてDBに接続できなかった。ネットワーク障害で、DBに接続できなかった。その他、現段階では想定していないのエラーが発生するかもしれない。a〜eのエラーについて、どういうエラー処理をさせたいでしょうか。要件がある場合は従う必要があります。要件が提示されなかったから何もしなくていいのかというとそうは行きません。少なくとも共通エラー画面を用意して、エラーを通知すべきです。考えられるエラー処理を次に記載します。id=1234のユーザが存在しなかったは、自己復帰できるエラーユーザが意図的にURLを改ざんし、存在しないidを入力してきた場合や、ユーザのURLをブックマークしていたけど、ユーザが退会してしまっていた、といったことも考えられます。以下のエラー処理が考えられます。(要件に従う必要があります。要件がなければ提案する事象です。)共通エラー画面に遷移させる。(例外をthrowして共通エラーハンドラに処理を任せる。NotFound扱いにする。(サイト内の404表示の手続きに従う。)該当するユーザは存在しないか、退会しています。いう独自画面を表示する。(Action内独自処理を入れる)共通エラー画面に遷移させるのは少し乱暴です。共通エラーは障害時しか表示してはいけないからです。共通エラーハンドラではエラーログを出力するため、ログ監視サービスが稼働してる場合、アラートが上がります。共通エラーハンドラに任せる場合、これは障害ではないよ!っていう独自の例外の型を準備して、それをthrowし、エラーログを出さないようにする必要があります。その他は自己復帰できないエラー(システムエラー)プログラムのバグ、ネットワーク障害、設定ミス(バグ)すべてユーザには関係のないサイト側の問題です。ユーザはどうすることもできません。これらは共通エラーページを表示するべきです。個々にエラー処理をしてはいけません。フレームワークのエラー処理の機能を理解しよう!どのフレームワークにも必ずエラー処理の機能が準備されています。IIS)などが500エラーを返します。エラー処理機能を細かく切り出すと以下のようになります。それぞれでハンドルされなかった場合、次の機能にエラー処理を任せます。理想論を言えば、そのエラーがURL固有(Action固有)であればAction内で処理すべきです。そのエラーがController固有であればControllerのエラーイベント処理で処理すべきです。そのエラーがサイト共通であれば、フレームワークの共通エラー処理に任せるべきです。Webサーバーの500処理は起きてはいけませんが、フレームワークが処理仕切れない例外が発生することもあるので、共通エラー画面に表示するhtmlをサーバーの500にも設定しておくべきです。404も同様にサーバーにも設定しておきましょう。これでも、結構複雑ですね(笑)。これをいろんなエンジニアの独断に任せたらまた大変なことになりそうですね。要件にあるURL固有のエラー処理以外は、エラー処理はするな!となるのです。共通エラー処理についてはリーダーや、メインプログラマ、1人に任せておきましょう(笑)共通エラー処理としてやっておくといいことエラー画面が表示されると、エンドユーザは不安になります。緊急であればサイト運営に問い合わせなどを行うことになるでしょう。保守運用を依頼されている場合、障害対応となります。障害対応はなるべく時間をかけずに簡潔に行えるようにしておくと、運用コストを削減できるでしょう。(保守費用が月額で決まっている場合、時間がかかればかかるほど、エンジニアのボランティア作業になってしまう)自分がよく実装するのは以下のような仕組みです。GUIDなどで一意のお問い合わせID(エラーID)を生成します。例外オブジェクトの内容、メッセージをお問い合わせIDと一緒にエラーログに出します。エラー画面を表示するのですが、ここでお問い合わせIDを一緒に出力します。メーラーを起動する仕組みであればお問い合わせIDをタイトルなどに含めてあげるといいでしょう。ここで注意なのですが、エラー処理では、エラーを起こす可能性のある仕組みを実装してはいけません。お問い合わせIDを生成した場合、その内容をDBに記録する!なんて実装をしてはいけません。DB障害でエラーハンドラーに飛んできた場合、エラーハンドラでDB書き込めないでしょ?また、ZABIXなどの監視ツールを使いエラーログを監視するといいですね!実際にエラーが起こったらどうするの?共通エラーハンドラで出力したエラーログを確認します。それが、コードのバグなのか、インフラエラーなのかを切り分けます。コードのバグであればバグ対応してください。今後そのエラーはなくなりサイトの品質が上がります。インフラのバグであれば、インフラ対応をしてください。冗長化構成をするなど、障害に強いインフラを目指してください。OK通常のView表示です。正常に処理が行われました。BadRequestURLのQueryStringが異常な場合などに利用したりします。Foundを使っても違和感がないと思うので、使うかどうかは検討してください。UnauthorizedBasic認証などが設定されている場合にWebサーバーが返します。Webサイトの実装として、認証ができなかった場合にこのステータスを返す設計をすることもあります。Forbiddenアクセス権限がない場合にWebサーバーが返します。サイト側の実装としては、ユーザのランクや権限に応じてアクセスできない場合、このステータスを返す設計をすることもあります。NotFoundよく知られたステータスコードです。静的なリソースファイルが存在しない場合、Webサーバーが返します。Controller、Actionへのルーティングができなかったときに、フレームワークが返します。パラメータをURLに含めるURL設計の場合、対象のパラメータのデータが存在しなかったときに、プログラムにて自前で返す場合もあります。AllowedGETしか受け付けないURLでPOSTでアクセスがあった、など、ルーティングできない場合に、フレームワークによっては、フレームワークが勝手に返します。BadRequestが利用されることもあります。InternalServerErrorプログラムで例外が発生し、フレームワークで処理されなかった場合、Webサーバーが返します。共通エラーハンドラーでプログラムで処理した場合でも、エラー画面を表示するときにはこのステータスで返します。ServiceUnavailableメンテナンスモードです。フレームワークで対応するのかWebサーバーで対応するのか、要検討してください。Foundとするのか、方針を統一しておくといいと思います。各ステータスコードのエラー画面を準備しよう!サイトとして考えられるHTTPステータスコードを検討しておくと、とても幸せになります。Webのプログラムの処理が入る前に、Gatewayや、Webサーバーがステータスコードを返す場合もあります。GatewayやWebサーバーがエラーを返す場合、各ステータスに応じた静的なHTMLを配置しておくと良いと思います。※Apacheが返すエラー画面が表示されてしまうと、サーバーにApacheを利用していることがばれてしまい、セキュリティ、ユーザビリティの観点であまりよろしくありません。Web仕様変更が悪いのではない。仕様変更に絶えられない実装が悪いのだ!プロジェクトは仕様変更との戦いです。仕様が変わったせいで、全てのコードを見直し、テストを全てやりなおすなんて日常茶飯事です。仕様が変わった事を恨んでも仕方がないので、仕様が変わってもすぐに対応できる準備をあらかじめしておく必要が有ります。Web開発でよくあるのが、HTMLやControllerのソースコードにURLが直接記述されているので、URL変更が思うようにできない、という悲鳴です。記述しなければいいじゃん!URLを管理するクラスを作りましょう!URLを管理するクラスを作って、URLの処理を閉じ込めます。公開すれば良いでしょう。パラメータ有りの場合は、メソッドにしてパラメータを引数で渡せるようにしましょう。パラメータが複雑であれば、パラメータのクラスを作ってそのクラスを引数で渡すようにしましょう。URLエンコーディングや、暗号化されたパラメータなど、パラメータ生成ロジックが発生するのであれば、ロジックもメソッドに閉じ込めましょう。//わざわざエラーコード一覧の資料を見なくても実装できるようにしてあげましょう。}}エラー画面URLであれば、エラーコードがenumになっており、enumにコメントをつけてあれば、どういうエラーなのかを資料を見なくても実装できます。ユーザ画面URLにいては、型がintのパラメータが必要ということがわかります。認証URLについては、複雑なロジックが内部に含まれていますが、ロジックが閉じ込められているため、利用者はロジックを意識することなく、呼び出すだけでURL生成ができます。tokenを生成してURLエンコードをしてセットしてください。"/auth?token={0}";}これはパラメータ付きURLのフォーマットを返しています。これではせっかくURL管理クラスを作る意味がほとんどありません。すべてのURLについて利用する側でFormat変換をしなくてはいけません。エラーコードを指定する場合、エラーコードの種類がわかりません。別の資料を見ながら手入力するのでしょうか。userIdに関しては、idはintなのか、stringなのかわかりません。tokenってどうやって生成するのかわからない場合、知ってる人に質問しないといけません。知ってる人が誰なのか?最悪たらい回しにされます。無駄な時間が過ぎます。プライドが高い人は、token生成アルゴリズムが記載された資料を見つけて、自前で実装してしまうかもしれません。URLエンコード忘れてしまった場合、テストで認証エラーが起きて原因調査に時間が取られます。すべてに言えますが、URL組み立てロジックがいたるところに分散してしまい、無駄なソースコードが増えます。stringのformatは便利ですが、パラメータ数が一致しないときには例外が発生するなど、色々面倒になります。ControllerやViewでformatを組み立てると、そのコードが実行されないと、バグがわかりません。正しいURL管理クラス設計を!たったひとつ、URLを管理するクラスを正しく設計し、共有するだけで、URLに関する無駄な結合テストが単体テストレベルで可能になります。URL組み立てロジックをそれぞれ実装しなくて済みます。複雑なURL組み立てをそれぞれの開発者が意識しなくてよくなります。URLを管理するクラスが肥大化してきたよ!よくあります。classを階層化するなり、Bridgeパターンを適用するなり、細分化してください。クラスのパスが変わってもビルドエラー箇所を直せば済みます。結合テストを書いてるのであれば、結合テストを実行してあげてください。まとめURL管理クラスを作り、パラメータなどのロジックはこのクラスに閉じ込める。stringフォーマットをpublicで公開しない。URL管理クラスの単体テストをすれば、URL生成ロジックのテストは完了する。肥大化してきたら、細分化して、メンテナンスしやすいようにする。画面遷移がたくさんあるサイトだったとします。/●●●/completedといったルールを決めておくとよいです。input、確認はconfirm、完了はcompleteといったルールが決まっているとすぐに該当のソースを確認できる。機能追加要件でのURL設計が楽。「ああ入力フォーム系か。Controller名さえ決めればいいなあ。Actionは決まってるからコピペ。実際に画面の種類を洗い出す!画面の要件定義から画面一覧をエクセルなどでまとめてみると、大抵、同じような画面が多い事に気づきます。ある種類の画面をピックアップしてみます。コンテンツ表示TOP画面系(いろいろ詰め込まれている、menu的な意味になったり、yahooのようなポータルになったり、facebookのような個人ページだったりします)一覧画面(記事やコンテンツの一覧を表示する画面です。)詳細画面(記事やコンテンツの1つを表示します。入力新規画面(質問や、日記などを投稿します。パスワード変更など設定系も含まれます。)確認画面(入力内容を確認する画面です。確認画面を挟まないこともあります。)完了画面(完了したことを表示する画面です。)※JavascriptのMVCを使ったシングルページ実装などもあるので、投稿機能自体がTOPや一覧に含まれることもあります。具体例たとえばスポーツニュースサイトの画面構成を考えてみましょう。)各スポーツ別TOP画面(プロ野球TOP、JリーグTOP、、、)各記事一覧(試合結果一覧、各ニュース記事一覧)詳細画面お問い合わせフォームといった具合ですね。各々適当な名前をつけてください。するとか、ポリシーに従ったルールを決めると良いと思います。URL一覧をexcelで管理し、controller名、actiom名を別セルで入力し、URLを自動生成させるようにしておくなどの工夫をすると、命名規則を管理しやすく、イレギュラー対応などが即時にできるようになります。S(主語)V(動詞)の関係になります。オブジェクト指向プログラミングでいうところのクラス名、メソッド名も主語、動詞の関係ですよね。実際に、MVCフレームワークではController名はクラス名、Action名はメソッド名になるので、やはり主語、動詞の関係であるべきです。Indexは動詞!?よく既定のAction名(省略可能なAction名)としてIndexが割り当てられているMVCフレームワークは多いと思います。Indexって動詞の意味もあるけど目次って意味だと名詞だよねぇ。例外なの?自分は例外だと思っています(笑)RestfulAPIのURL設計に毒されるな最近RestfulAPIの設計が市民権を得てきて、ナウでヤングな設計になってきています。SOAPや、XML-RPCのような古いAPIの形式の立場が無くなってきていてちょっと寂しい。MethodでURLはリソースを表す!を崇拝するあまり、画面のURLに動詞を使うことに抵抗を持つ若いエンジニアが結構います。今、話題にしているのは、画面のURL設計です。DELETE)を使いますが、ブラウザからのアクセスではPOSTとGETしか使えません。GETな動作ブックマーク検索エンジンからの遷移URLバーに直接URL入力!aタグによるリンクmetaタグによるリダイレクトjavascriptによるlocation.hrefによるリダイレクトformでmethod="GET"POSTな動作formからmethod="post"まあ、ほとんどGETなんですよね。HTTPメソッドを活用できない以上、URLで代用するしかないのですね。Action名に動詞を使いましょう。MVCMVCフレームワークを使ったURL設計についてです。S(主語)V(動詞)の関係になります。オブジェクト指向プログラミングでいうところのクラス名、メソッド名も主語、動詞の関係ですよね。実際に、MVCフレームワークではController名はクラス名、Action名はメソッド名になるので、やはり主語、動詞の関係であるべきです。Action名については別記事で考察します。Controller名は主語なんだから名詞!はい、名詞を使ってください。/beatiful(形容詞)/web/directly(副詞)/access/go(動詞)/homeおかしいですよね。Controller名は単数形なの?複数形なの?名詞の集合は単数形か複数形か、DB設計でも議論になります。同じように、URL設計でもよく議論になります。今の流行に乗るならば複数形がいいと思います。理由としては下の二つのURLを考えてみてください。(/users?id=1234)/usersの方はaction名ユーザ一覧を表すとします。/users/1234はユーザ一覧にて、ユーザIDが指定されたと考えることができます。DBのテーブルに置き換えてみてください。usersはテーブルです。