自分のレスポンシブWEBデザインの何が盲点だったのか
いきなりマルチデバイス対応のWeb画面のサンプルを作ることになったのですが、とりあえず作ってみたらすごく疲れた。 (もっといいやり方あるだろコレ...)と思いながらやってた。いくらか原因がわかったので棚卸し。
問題
グリッドデザインのためのクラス(col-md-12, とかのことを言いたい)を宣言する時に、divタグがやたら多くて疲れた。 ヘッダーのロゴ画像とかタイトルとかがうまくヘッダーに収まってくれず、一部人力で高さや幅を指定してしまった。
仮説
ヘッダーは、専用のクラスがある気がする。 divタグ以外に要素を表すタグを使うべきだったんじゃないだろうか。
結論
グリッドデザインの組み方が悪い。PC用の表示をする時に、1行の中の箱要素の中身まで横に崩す必要はなさそうだ。 ヘッダーは、ナビゲーション関連のクラスを使うのが良さそうだった。
参考にしたサイト
bootstrapのチュートリアルをじっくりみた。 www.tutorialrepublic.com
気がついたこと
ヘッダーについて - 便利なクラスがたくさんある。 - ページのタイトルとかをトップに張り出す時には"navbar-header"。スマホ表示の時にヘッダーを右端に寄せてくれる -
divについて - rowの内側の要素それぞれの縦並びを横に崩そうとしない。 - PC用の画面をデザインしてからスマホ用に並べようとすると↑の失敗をしてしまう - 子要素の中でさらに柔軟な縦横のデザインをやりだすと、マージンがかさんで場所ごとに横の位置が揃わなくなる。
反映してみた。
Javaのimportについて自分なりに整理
そもそもはEclipseで外部ライブラリをimportするのってどうするんですか?という後輩さんの質問に答えられなかったのがきっかけ。 調べ物をしていくうちに、そもそもEclipseなしで外部ライブラリを使うのってスイスイできないなって気づいた。これはまずい。
先に結論を述べて、そのあと実験します。
結論
Javaでクラスファイルをimportするには、以下の2点を守る必要がある 1. コンパイル時のクラスパスに必要なクラスファイル(ないしはソースファイル)があること 2. 実行時のクラスパスに必要なクラスファイルがあること
実験
二つのソースファイルをもつ簡単なプログラムを作って、コンパイル時と実行時に条件を変えて試してみた。
ソースファイル
src/ ├ Hello.java └ spanish/ └ Hola.java
import spanish.Hola; public class Hello { public static void main(String[] args){ System.out.println("Hello, world."); Hola hola = new Hola(); hola.printHola(); } }
package spanish; public class Hola{ public void printHola(){ System.out.println("Hola!!"); } }
コンパイル
- 現在のクラスパス(src/)に、パッケージ名に沿ったディレクトリ構成で外部クラス(Hola.java)が配置されている場合 src/ ├ Hello.java └ spanish/ └ Hola.java
$ javac Hello.java (エラーなし)
$ javac Hello.java Hello.java:1: error: package spanish does not exist import spanish.Hola; ^ Hello.java:6: error: cannot access Hola Hola hola = new Hola(); ^ bad source file: ./Hola.java file does not contain class Hola Please remove or make sure it appears in the correct subdirectory of the sourcepath. 2 errors
実行時
- クラスパス(src/)上に外部クラス(Hola.class)がある場合 src/ ├ Hello.java ├ Hello.class └ spanish/ ├ Hola.java └ Hola.class
$ java Hello Hello, world. Hola!!
$ java Hello Hello, world. Exception in thread "main" java.lang.NoClassDefFoundError: spanish/Hola at Hello.main(Hello.java:6) Caused by: java.lang.ClassNotFoundException: spanish.Hola at java.net.URLClassLoader.findClass(URLClassLoader.java:381) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ... 1 more
ソースファイルがあってもダメ。
- 現在のディレクトリ(src/)にはパッケージはないが、別のディレクトリにパッケージがあり、クラスパスが通っている場合 java/ ├ src/ │ ├ Hello.java │ └ Hello.class ├ another/ └ spanish/ └ Hola.class
$ java -classpath .:../another Hello Hello, world. Hola!!
コンパイル時と実行時で、クラスファイルが置いてある場所が違っても構わない!知らなかった!
「Webを支える技術」を目次だけ読んで中身を想像した
実は冗談でやってるわけではない。 こないだ読んだ「本を読む本」という本に、目次を読んで中身を想像するのは大事だって書かれていたような気がするので実践してみてる。
第1部 Web概論
Webの歴史を論じている。コンピュータが軍や大学にしかなかった時代から、アプリがWeb上で動くようになった現代までの流れを追う。 「Web APIをめぐる議論」にSOAPとWS-とRESTのことが書いてある。WS-って何か分からないが、RESTと対比されているのでクライアント側のフォーマットが決まっているプロトコルなのではないか。 RESTについて1章割いている。RESTfulなAPIをどう設計するかについて論じていると予想。URIの体系とか、サーバーサイドの実装のコツ(キャッシュをリバースプロキシにもたせるとか?)が書かれているのではないか。
第2部 URI
URIの仕様と設計について。仕様の章は、URIを要素に分解して説明していると予想。プロトコル、ドメイン、etc… 改めて説明しようとするとできないな。 設計の章は、ドメインが変わったときやAPIを追加したいときなんかの変化に強いURI体系について論じているのではないか。サービス/領域/リソース名 みたいに分解すると予想。
第3部 HTTP
基本→メソッド→ステータスコード→ヘッダ。HTTPの中身を要素ごとに解説すると予想。 ぶっちゃけレスポンスそのものって私は見たことほぼなくて、アプリケーションでformに梱包されているのしか受け取った覚えがない。 メソッド(DELETEとかPUTとか)にもページを割いている。GETとPOST以外使ったことないけど、態度として正しいんだろうか。
第4部 ハイパーメディアフォーマット
HTMLとJSONはわかるんだけど、microformatsとAtomって何だろう。microformatsはRDFと対置されるものらしい。Web以前のドキュメントの装飾とかに使われた古いフォーマットだろうか。 AtomはRSSとかと一緒に見かけたことがある。ブログの更新とかに使われるんだろうか。これって現役の技術? JSONは知ってるけど、ハイパーメディアフォーマットって映像とか動画とか埋め込むフォーマットだと思ってた。誤解かもしれない。
第5部 Webサービスの設計
読み書きとリソースの設計。読みは置いといて、書き込みは排他制御とか。トランザクションリソースって聞き慣れない言葉だけど、DBだとトランザクションレベルって言葉があるから、そのWeb版かな? トランザクションレベルとは、逐次コミットとかまとめてコミットとかそういうやつだったと思う。 リソースの設計って何だ。と思ったが、DBではこんな形、Webサービスにしたらこんな形、の黄金パターンみたいなものかしら。
EclipseなしでStrutsを動かそうとして挫折中
jspファイルを読み込んでいる時に、ActionやActionFormと関係するところがうまく動かないらしい。。。
2017/09/26 追記: WEB-INF直下のclassesフォルダに/helloが位置するようにクラスファイルを配置したらうまくいきました。
Strutsとの戦いの難所を超えた。クラスファイルの配置場所を理解していなかった。インタプリタ原語ほんと楽だな…
— さわら (@hiroga_cc) 2017年9月25日
そもそもの背景
前にStrutsを使ってた時、そういえばEclipse任せ&プロジェクトの既存の設定任せで全然勉強してなかったことに気がついた。 なのでEclipseなしでStrutsのアプリを立てている。モダンなWAFとの比較もしたい。
やったこと
気がついたこと/ 困っていること
StrutsのWebアプリの作成
このチュートリアルに従ってやってるんだけど、このフォルダ構成は一般的なんだろうか。 前に使ってたところはどうだったっけ? www.atmarkit.co.jp
struts-config.xmlの設定が煩雑。railsがフォルダ構成を決めていることのメリットがちょっとわかった。 これが設定より規約か… ルーティングは、tornadoやflaskだとアプリ側で記載するから、
jspファイル、Actionファイル、ActionFormファイルの編集
jspがActionとかActoinFormを呼び出すときのエラーって、Pythonでjinja2とか使っても起きるんだろうか?
formはpythonだとdformってのがあるらしい。後で試したい。
Tomcatの導入
こちらを参考にさせていただいた。
まず、コマンドを自分で設定するっていうのが斬新だった! brew install hoge したら hoge が使えるようになるのに慣れてたせいで、
ln -s /usr/local/tomcat8.5.11/bin/startup.sh /usr/local/bin/tomcat-start
はほんと勉強になった。こうなってたのねえ。
Gradleでビルド
めっちゃ新鮮!もっと使いこなしたい。 こちらを参考にさせていただきました。 qiita.com
こんな感じになった。
apply plugin: 'java' sourceSets.main.java.srcDirs = ['WEB-INF/src'] repositories { mavenCentral() } dependencies { compile 'javax.servlet:servlet-api:2.5', 'org.apache.struts:struts-core:1.3.10' }
依存性の注入を今は手作業でやってる。なんとかしたい。 あと、結果のクラスファイルは手作業でソースファイルと同じところにコピーし直してる。(これ動かない原因かな…?) 紐ついてるライブラリも、importするクラスファイルから逆に調べられるようになりたいなー。 どうしたらいいのかしら。
localhostでwebアプリを動かした時にサーバーの設定をした覚えがない
現場ではlocalhostにデプロイする時にWAS(WebSphere Application Server)の設定とかするのに、 家でrailsとかtornadoとかデプロイする時にサーバーとアプリのつなぎ込み?した覚えがない!なんで!
仮説
調べてみたら、tornadoはwebサーバーとしての機能も持っていた。 railsもサーバーとしての機能を持っているのではないか。 ただし、サーバーを別途立てて運用することもできるのではないか(railsとunicornの単語をセットで見かけたことがあるから)
やってみた
railsアプリケーションを動かしてみるのが一番。 今回は他にもFlask(PythonのWAF)とPlay(Java/ScalaのWAF)も動かしてみた。
Rails
$ hello_app hiroaki$ rbenv exec rails s => Booting Puma => Rails 5.0.5 application starting in development on http://localhost:3000 => Run `rails server -h` for more startup options Puma starting in single mode... * Version 3.9.1 (ruby 2.3.4-p301), codename: Private Caller * Min threads: 5, max threads: 5 * Environment: development * Listening on tcp://0.0.0.0:3000 Use Ctrl-C to stop
調べたところ、デフォルトでPumaというwebサーバーが指定されているらしい。
Flask
$ python project.py * Running on http://0.0.0.0:5000/ * Restarting with reloader
シンプルだなあ… Flaskは開発用のWEBサーバーを内蔵している、という記述を見つけたから、 Flask内部のWerkzeug(ウェルクツォイク、WAFのためのユーティリティ)が、同梱されているwebサーバと通信しているというイメージであってるかな?
Play
$ sbt run [warn] Executing in batch mode. [warn] For better performance, hit [ENTER] to switch to interactive mode, or [warn] consider launching sbt without any commands, or explicitly passing 'shell' [info] Loading project definition from /Users/hiroaki/Dev/lrn/play/play-java-starter-example/project [info] Set current project to play-java-starter-example (in build file:/Users/***/play-java-starter-example/) --- (Running the application, auto-reloading is enabled) --- [info] p.c.s.AkkaHttpServer - Listening for HTTP on /0:0:0:0:0:0:0:0:9000 (Server started, use Enter to stop and go back to the console...)
Akka HTTPというプロジェクトで作られたWEBサーバーが動いているらしいということはわかった。
結論
有名なWAFには、開発用のサーバーが一緒に入ってる、と考えて良いのではなかろうか。 いざ運用、という段になったら、専用のサーバーを立ててアプリを叩くように設定するのだと思われる。
久しぶりにfacebook messengerのチャットボット作って忘れてたこと
CIの勉強と便利ツール作成を兼ねて、久しぶりにチャットボットを作ってる。 構成はtoanado(pythonのwebアプリ用フレームワーク)+heroku
とりあえずおうむ返しまでできた。多分次回も忘れてることを書いておく。
便利コマンド
シェル
vi ~/.bash_profile (fb-バックエンド間の通信で使うtokenを設定する) source ~/.bash_profile
heroku
heroku login –app APPNAME heroku log -t –app APPNAME heroku config:set TOKEN_NAME=“token-no-nakami”
忘れていたこと
環境変数の設定周りがあやふやだった。
.bash_profileという、bashが起動時に勝手に読み込んでくれる、ユーザー単位の設定(中身はexportコマンドなど)が書かれたファイルを使う。 起動時に読み込むようにここに書いておく。書き込んだ直後は、source ~/.bash_profileとかで反映する。 sourceコマンドはファイルの中身を忠実に実行するコマンド。
heroku周りもあやふやだった。
pythonを動かすには、Procfileはじめ色々と設定ファイルが必要だった。 前回作ったのがなければまずかった。
facebook-heroku間のつなぎ込みもあやふやだった。
手順はこんな感じ。 facebook->バックエンドの通信のtokenの正解をバックエンド側に設定する。 facebookの開発者向けダッシュボードからWebhooks >> 設定。
それが終わったら、今度はバックエンドからfacebookに返事。 facebookの開発者向けダッシュボードでページのサブスクリプション用トークンを取得し、 それをバックエンドに設定。それができたらメッセージを送信。 このフォーマットは面倒なので前に作ったやつを毎回パクってる。
CIについて
今やってるとこなんだけど…herokuとgitはすごく楽チンなんだけど、redmineのつなぎ込みがなんかうまくいかない。 難し〜。
継続的インテグレーション自前でやってみる計画
「チーム開発実践入門」を読んでみて、仕事以外でやってみたいなと思いつつある。 こういうのは妄想をたっぷり膨らませておくのがモチベに繋がる。なので計画立ててみた。
最終目標:
マスターブランチにマージしたら自動でテストしてデプロイしてくれること。チケットもいい感じに更新してくれること。
ステップ1
チケット駆動でやりたいので、まずはRedMineサーバーを立てる。 若干古い感じがするけど、SIerの現場でためらいなく使えること(要はOSSであること、実績があること)が今回は大事。 AWSでDockerで建てられるっぽい。
ステップ2
それが終わったら、バージョン管理ツール、CIツール、本番環境を用意する。 バージョン管理はGit、中央のリポジトリはGithubを使えばよし。実業務を念頭におくと、アプリ用とDB用でリポジトリを分けるべし。 (アプリとDBはN:1の関係になると思われるので)
CIはJenkinsを使ってみる。Githubとの連携を考えるとTravisCIがいいらしいんだけど、SIerの現場でも使えることを考えるとOSSが良い。 これもAWSでDocker使って立てる。
本番環境はHerokuにする。 多分Docker経由でAWSにあげるのが良いんだろうけど、それは後でいい。
ステップ2の鍵は、Github - Jenkins - Herokuのつなぎ込みだと思う。特にJenkins、触ったことないから画面が想像つかない!
ステップ3
アプリとDBを作ってローカル、ついでHerokuで動かす。 チケット管理をGithub, Jenkins, Herokuに連携させる。
ステップ4
UTを書いてJenkinsに登録する。 カバレッジを楽チンに見られるようにする。
読んでみて
大体はSIerの現場でも経験したことがある(たとえExcel管理であっても)んだけど、DBのスキーマをリポジトリで管理するのは気がつかなった。 あとはローカル環境にDBを構築することも。ローカルから開発環境のDBを参照するのって普通じゃなかったんだね!
読むだけじゃなくて実際に手を動かしながら参照する本なのかもしれない。