Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

1周遅れのScala入学 #nds41

1,139 views

Published on

Nds41

Published in: Engineering
  • Be the first to comment

1周遅れのScala入学 #nds41

  1. 1. 第41回長岡IT技術者勉強会 1週周遅れのScala入学 2015/4/11 @nemuzuka
  2. 2. 自己紹介 • 片桐 一宗(かたぎり かずむね) • id:nemuzuka • @nemuzuka • サーバサイドにJavaを使用したWebアプリケーションの 開発を主にしております • フリーランス(vss.jp.net)
  3. 3. Scala再入学のきっかけ
  4. 4. システムを新しく構築するチャンス • AWSのサービス使用 • S3 / CloudSearch / CloudFront… • 全ての操作で画面切り替えとかちょっと… • AjaxでDOM書き換え • HTML5 • IE?最新しかサポートしない! • スケジュールがタイト • 要望がコロコロ変わりそう…
  5. 5. そこで選んだのが • サーバサイドはJava • Tomcat • Seasar2 • SAStruts • S2Dao +今まで培ってきた  ・diconファイル  ・薄いラッパー
  6. 6. ちょっと 開発のパワーが足りないから 外部の人の協力を得よう
  7. 7. 『新規なのにJavaなんですか』 『新規なのにSeasar2 なんですか( ´_ゝ`)』 えもいわれぬ老害感
  8. 8. 結局Javaの構成で 無事カットオーバー できましたが... 何か新しいこと やらないといけないかな
  9. 9. 選択肢は2つ • 別のフレームワークを学ぶ • JavaEE • Spring • Play Framework • 新しい言語を学ぶ • 静的型付けが良い • IDEが使えた方が良い
  10. 10. あっ!
  11. 11. 入学してた。
  12. 12. 当時は「できない子」 • bot写経で躓き、「ガッ」できなかった • みんなの「XXXのコード見せてください」の画面切り 替えが早すぎて追いつけなかった • 単純に手が遅い
  13. 13. 再入学の後押し • Javaの資産が使える • Apache Commonsとか • AWSのSDKだって使える • 関数型プログラミングもオブジェクト指向プログラミングもサポート • とりあえず「使う」だけなら関数脳にならなくても良い • 型推論でスクリプト言語のようにも見える • でも、IDEで追いやすい
  14. 14. 「Javaやってます」 よりも 「Scalaやってます」 の方がなんとなく仕事が来そう
  15. 15. というわけで Scala再入学することに
  16. 16. どうやって再入学したか? • 今更、NullPoGaBot作ってもなー • どうせやるなら何か案件が始まった時に使えるものにし たい
  17. 17. S2でやってたことを Scalaでやるならどうするか に置き換えてみよう
  18. 18. フレームワークの置き換え 機能 JAVA SCALA WEBフレームワーク SAStruts Scalatra + scalata-forms テンプレートエンジン JSP Scalate (SSP) ORM S2Dao Slick
  19. 19. こんなときどうする(1) ∼トランザクション管理∼
  20. 20. トランザクション • DBの変更を • 適用する(commit) • 取り消す(rollback) • これをそれぞれのプログラムで行うと • DBに対する操作とビジネスロジックが混在する • ソースコードの見通しも良くない • コネクションの解放漏れ等にも繋がる
  21. 21. S2だと DI • S2の仕組みに乗れば自動的にトランザクションが効く • @Bindingを付与して実装クラスをInjection • 正常終了(何も例外が発生しない)時commit • 例外が発生すればrollback • DI使うのに外部XMLは不要 • コネクションプールもdiconに書くだけで使える
  22. 22. Scala(Scalatra)だと filter • Scalatraのinitでコネクションプール設定 • filterでトランザクション制御 • トランザクション開始 • 処理呼び出し • 正常終了(何も例外が発生しない)時commit • 例外が発生すればrollback
  23. 23. ソースはこんな感じ //Filter class class TransactionFilter(db: Database) extends Filter { def doFilter(req: ServletRequest, res: ServletResponse, chain: FilterChain): Unit = { db withDynTransaction { // 1. トランザクションを開始し、ThreadLocalにSessionを格納 chain.doFilter(req, res) // 2. Servletの処理を行う } // 3. 正常時commit、例外発生時rollback } } DB Database.dynamicSession をimport ThreadLocal 取得して処理を行うことが可能 class ScalatraBootstrap extends LifeCycle { val cpds = new ComboPooledDataSource() // 1.設定ファイルを元にコネクションプールを生成 override def init(context: ServletContext) { // 2.Scalatra起動時に一回だけ呼ばれるメソッド val db = Database.forDataSource(cpds) // 3. Slick用データソースの取得 context.addFilter("transactionFilter", new TransactionFilter(db)) // 4. TransactionFilterをfilterとして登録 context.getFilterRegistration(“transactionFilter").addMappingForUrlPatterns( util.EnumSet.allOf(classOf[DispatcherType]), true, “/*") // 5. Servletの定義が続く… } }
  24. 24. これでこんなLayer設計ができます ・Servlet ・Service  →DBアクセスしないので、Sessionをコード上で意識しない ・Dao  →ThreadLocalからSessionを取得してSQL発行
  25. 25. こんなときどうする(2) ∼認証・認可チェック∼
  26. 26. 認証・認可 • 認証 • リクエストを送ってきた人が正規のユーザであることを確認すること • ID / パスワードでログインしている • 本人しかしらない筈なので、正規のユーザとみなす • 認可 • その機能を利用する権限の有無を確認すること • 管理者権限を所有していないのに、管理者機能を使用できるのはNG • Webアプリの場合、URLを直接叩かれる可能性があるので、特に注意する必要あり
  27. 27. S2だと S2AOP • ログイン成功時、HttpSessionにログイン情報を設定 • 受けたリクエストが認証済みでなければならない場合 • Interceptorを使用して、Actionの呼び出し前にログイン情報がHttpSessionに存在するか チェック • 存在しなければログイン画面へリダイレクト • 存在するが、そのActionを使用する権限をユーザが持っていない場合、不正アクセスが 来たとみなし、しかるべき画面にリダイレクト • AOPの定義はdiconファイルに定義 • パッケージ、クラス名等の正規表現で定義できる
  28. 28. Scala(Scalatra)だと filter • ログイン成功時、HttpSessionにログイン情報を設定 • リクエストURIを元に受けたリクエストが認証済みで無ければならな い場合 • filterでログイン情報がHttpSessionに存在するかチェック • 存在しなければログイン画面へリダイレクト • 存在するが、そのServletを使用する権限をユーザが持っていな い場合、不正アクセスが来たとみなし、しかるべき画面にリダ イレクト(これは、Servlet側機能)
  29. 29. こんなときどうする(3) ∼コード自動生成∼
  30. 30. ER図を常に信じられる状態にしたい 3.ソースコード (絶対に手動で修正しない) 2.RDBMS 1.ER図
  31. 31. • S2Dao-CodeGen • Slick code generator S2だと Scala(Slick)だと
  32. 32. こんなときどうする(4) ∼動的SQL発行∼
  33. 33. 画面に入力された項目だけwhere句に追加 未入力の場合、その項目はwhere句に含めない
  34. 34. S2だと IFコメント • 条件に応じてSQLを変更することが可能 • /* IF 条件 */…/*END*/ • 条件がtrueの場合、/*IF*/と/*END*/に囲まれた部分が評価 される /*IF hoge != null*/hoge = /*hoge*/‘abc’/*END*/ 引数hogeがnullでない場合にのみ、 hoge = hogeの値 がSQL文に追加される
  35. 35. Scala(Slick)だと 生Preparedstatement • ゴニョゴニョ頑張れば他のやり方でできる気もするけど、こっちの方が確実だと思 う • where句のカラムが動的に変わらないのであれば、StaticQueryを使用した方が良い • 複雑なテーブル結合する場合はStaticQueryやPreparedstatement使ったほうが余計 なことにハマらなくて良いかも • S2Dao使ってる時でも生SQLを発行してた • ORMは楽になるところだけ使う def coffeeByName(name: String) = sql"select * from coffees where name = $name".as[Coffee] println("Coffee Colombian: " + coffeeByName("Colombian").firstOption)
  36. 36. まだいろいろあるけど、 ドキュメント読めば何とかなります
  37. 37. Java使いがScalaと戯れた感想
  38. 38. 型推論 • 変数名定義の時にクラス名の有無でこんなに違うかーっ てくらいスッキリします [Scala] val credentials = new BasicAWSCredentials(accessKey, secretKey) val s3client = new AmazonS3Client(credentials) val localFile = new File("ローカルファイルパス") val bucketName = "バケット名" val filePath = "S3のアップロード先のパス" val upReq = new PutObjectRequest(bucketName, filePath, localFile) s3client.putObject(upReq) [Java] AWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey); AmazonS3 s3client = new AmazonS3Client(credentials); File localFile = new File("ローカルファイルパス"); String bucketName = "バケット名"; String filePath = "S3のアップロード先のパス"; PutObjectRequest upReq = new PutObjectRequest(bucketName, filePath, localFile); s3client.putObject(upReq);
  39. 39. 名前付き引数 • 大好きです。Javaにもあれば良いのに • 使う側が意識して設定するようになるのがイイと思います • 引数の順番が変わった時にも追従してくれます • 特にSlickのデータモデル(case class)のインスタンスを生成するときは嬉しい • カラムの追加や順番を変更することが多いので [Scala] case class User(age:Int, name:String) ・ ・ ・ val hanako = User(7, “はなこ”) // ① val jiro = User(age = 38, name = “二郎”) // ② val taro = User(name = “太郎”, age = 17) // ③ →全てUserクラスのインスタンスが生成可能だが、 case class User(name:String, age:Int) と変更した場合、①はコンパイルエラーになる
  40. 40. index付きループ • Javaにもあれば良いのに • Javaだと拡張forを諦めてfor(int i = 0; i < list.size(); i++) [Scala] val list = List("A", "B", "C") for((e, index) <- list.zipWithIndex) { // eには該当要素、indexには該当indexが格納される ・ ・ ・ }
  41. 41. まだまだあるよ • if とか for は式なので値を返せる • 「このifで何をしたいんだっけ?」が見えるようになるのがイイ! • 複数の戻り値を返せる(タプル) • わざわざ戻り値用のclass作らなくてもいいんです • traitでmix-inがすごい • チェック例外がない • 個人的にはあってもいいと思うけど…(設計思想変える必要あり) • Either(さっきのヤツ!) • 比較は「==」でOK • equalsを使わなくて怒られる新人減ります • breakが変 • もなど / かりー → よくわかりません
  42. 42. 再入門に準備したもの
  43. 43. purchase from https://gist.github.com/Shinpeim/6740436
  44. 44. まとめ • 結構面白いです、Scala • 潤沢なメモリ+SSD必須 • 金食い虫なので仕事に使うなら上の理解が必要かも • 次はテスト周りをしっかりと

×