Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Java入門

 Java入門

2017年4~5月開催「ブートキャンプ特別講座」の資料になります。

Recruit Technologies

June 02, 2017
Tweet

More Decks by Recruit Technologies

Other Decks in Technology

Transcript

  1. 自己紹介 • 五味 和人 (ごみ かずひと) • 55期10月入社 (3社目) •

    〜57期:主に検索基盤の導入と検索品質改善を担当 • 58期 :APプロダクト開発グループのGM • S53年うまれ (53 → ごみ) • 山梨出身 • サッカーやってます • ポジション:GK (GOMI Kazuhito) ラッキーナンバー です 世間のひとは厳しい
  2. おしながき • Maven基礎 • GC基礎 • レイヤー?抽象化?実装の隠蔽? • バッドコードからプロダクトコードへ •

    オブジェクト指向とUMLモデリング ※Java文法、Java8らしい書き方はやりません
  3. GC基礎:Mark-Sweep GC • ふたつのフェーズでオブジェクトを破棄する • マークフェーズ • スイープフェーズ • 実装は単純でCopy

    GCとは違い2倍のメモリー量を必要と しないがフラグメンテーションが起きる ◎ ◎ ◎ Mark Sweep
  4. GC基礎:世代別GC • Xms == Xmxにするとメモリー拡張コストが抑えられる • NewRatio = Old /

    New(3を設定するとNewはHeapの1/4) • SurvivorRatio = Eden / {S0 | S1} (6を設定するとS0, S1はNewの1/8) ※ S0をS1は必ず同じサイズにな る JVM Total Memory New(Xmn, NewRatio) Old Metaspace (MaxMetaspaceSize) Eden Survivor (SurvivorRatio) S0 S1 Heap(Xmx, Xms) Non - Heap ※ 重要なポイントだけに絞っています。
  5. GC基礎:世代別GC • 青字:-XX:MaxTenuringThresholdで指定した値 • あくまで目標値であり必ずしも維持されるわけではない -XX:PrintTenuringDistributionを指定するとGCログが↑のようになり動きがイ メージしやすくなる。 2014-09-16T16:42:15.357+0200: 6.796: [GC

    6.796: [ParNew Desired survivor size 381681664 bytes, new threshold 7 (max 15) - age 1: 16125960 bytes, 16125960 total - age 2: 16259512 bytes, 32385472 total - age 3: 2435240 bytes, 34820712 total - age 4: 17179320 bytes, 52000032 total - age 5: 43986952 bytes, 95986984 total - age 6: 20858328 bytes, 116845312 total - age 7: 31571664 bytes, 148416976 total
  6. GC基礎:CMS • CMSInitiatingOccupancyFraction • CMSが発動するOld領域の使用量閾値 • デフォルト値はある計算式に基づいて決定されるが90%近く、アプリ特性に応じて60% 近くまで下げた方が良い JVM Total

    Memory New(Xmn, NewRatio) Old (CMSInitiatingOccupancyFraction) Metaspace (MaxMetaspaceSize) Eden Survivor (SurvivorRatio) S0 S1 Heap(Xmx, Xms) Non - Heap ※ 重要なポイントだけに絞っています。
  7. GC基礎:CMS New Old Eden Survivor S0 S1 Liveオブジェクト Deadオブジェクト ③この間にもSurvivorからLive

    オブジェクトがPromoteされる • CMSでSweepされる前にOld領域が不足するとPromoteに失敗したりマーク フェーズに失敗してFull GCが発動する
  8. GC基礎:CMS New Old Eden Survivor S0 S1 Liveオブジェクト Deadオブジェクト ③この間にもSurvivorからLive

    オブジェクトがPromoteされる • CMSでSweepされる前にOld領域が不足するとPromoteに失敗したりマーク フェーズに失敗してFull GCが発動する Stop The World
  9. • Presentation (Interface) • Application • Domain • Infrastructure (Data

    Source) Layered Architecture 大別すると3, 4種類しかない
  10. ~ from PofEAA ~ Provision of services, display of information

    (e.g., in Windows or HTML, handling of user request (mouse clicks, keyboard hits), HTTP requests, command-line invocatiions, batch API) ~ from ドメイン駆動設計 ~ ユーザーに情報を表示して、ユーザーのコマンド を解釈する責務を負う。外部アクターは人間の ユーザーではなく、別のコンピューターシステム のこともある。 Layered Architecture : Presentation
  11. • HTMLや画面などのビューに近いところに位置 • リクエストハンドラーやREST APIエントリーポイント • 外部世界とアプリケーションの世界を繋ぐグルーコードで あるべき(ビジネスロジックは書かない) • 技術革新の影響を受けやすい

    (BFF部分に該当する) • アーキテクチャーを決めれば実装は機械作業的になる • Java EE:JSP / Servlet • Struts :Action • Spring :Controller Layered Architecture : Presentation
  12. ~ from PofEAA ~ Logic that is the real point

    of the system ~ from ドメイン駆動設計 ~ ビジネスにとって意味があるものか、あるいは他 システムのアプリケーション層と相互作用するの に必要なものである。 このレイヤーは薄く保たれる。ビジネスルールや 知識を含まず、やるべき作業を調整するだけで、 実際の処理は、ドメインオブジェクトによって直 下のレイヤーで実行される共同作業に委譲する。 Layered Architecture : Application
  13. ~ from PofEAA ~ Logic that is the real point

    of the system ※ PofEAAではApplicationとDomainに明確な定義差はない ~ from ドメイン駆動設計 ~ ビジネスの概念と、ビジネスが置かれた状況に関 する情報、およびビジネスルールを表す責務を負 う。 この層がビジネス・ソフトウェアの核心である。 Layered Architecture : Domain
  14. ~ from PofEAA ~ Communication with databases, messaging sysetms, transaction

    managers, other packages ~ from ドメイン駆動設計 ~ 上位のレイヤーを支える一般的な技術的機能を提 供する。アプリケーションのためのメッセージ送 信、ドメインのための永続化などがある。 Layered Architecture : Infrastructure
  15. • Application, Domainレイヤーと永続化装置の間を繋ぎ、永続化装 置に依存しがちなロジックを全て隠蔽する • RDBMS? KVS? File System? Other

    System? • Oracle? MySQL? PostgreSQL? • 永続化装置は性能要件や外部連携などの都合で変更が余儀なくされ るケースが多々あるため、隠蔽して変更の影響範囲を局所化する Layered Architecture : Infrastructure
  16. 演習:インフラストラクチャー(5~10min) • java.sql.PreparedStatement#executeQueryを内部で利用して [select * from Employee as e where

    e.組織 = :所属組織コー ド] の結果を返却するメソッドのシグネチャーを考えてください。 • 条件 • :所属組織コードはString型引数でnullと空文字は指定されないものとしま す。 • Employeeテーブルは以下の3つの列で構成されているものとします。 • 社員番号 • 社員名 • 所属組織コード
  17. • HTMLや画面などのビューに近いところに位置 • リクエストハンドラーやREST APIエントリーポイント • 外部世界とアプリケーションの世界を繋ぐグルーコードで あるべき(ビジネスロジックは書かない) • 技術革新の影響を受けやすい

    (BFF部分に該当する) • アーキテクチャーを決めれば実装は機械作業的になる • Java EE:JSP / Servlet • Struts :Action • Spring :Controller Layered Architecture : Presentation 再掲
  18. • このコード、どこかおかしい? public void doSomething(Integer arg) { if (arg !=

    null) { if (arg < 0) { do1(); } else if (arg > 0) { do2(); } else { do3(); } } } バッドコードからプロダクトコードへ
  19. • このコード、どこかおかしい? public void doSomething(Integer arg) { if (arg ==

    null) { return; } if (arg < 0) { do1(); } else if (arg > 0) { do2(); } else { do3(); } } バッドコードからプロダクトコードへ
  20. • このコード、どこかおかしい? public List<String> findEmployee(String orgCode) { if (orgCode ==

    null) { throw new NullPointerException(); } if (orgCode.length() != 7) { return null; } String[] result = find...; return (result == null) ? null : Arrays.asList(result); } バッドコードからプロダクトコードへ
  21. • このコード、どこかおかしい? public List<String> findEmployee(String orgCode) { if (orgCode ==

    null) { throw new IllegalArgumentException("orgCode must be not null."); } if (orgCode.length() != 7) { throw new IllegalArgumentException("orgCode length must be 7."); } String[] result = find...; return (result == null) ? Collections.emptyList() : Arrays.asList(result); } バッドコードからプロダクトコードへ
  22. • このコード、どこかおかしい? (lambdaじゃないのは置いといて) public List<DTO> toList(Map<String, String> arg) { List<DTO>

    ret = new ArrayList<DTO>(); for (String key : arg.keySet()) { ret.add(new DTO(key, arg.get(key))); } return ret; } バッドコードからプロダクトコードへ
  23. • このコード、どこかおかしい? (lambdaじゃないのは置いといて) public List<DTO> toList(Map<String, String> arg) { List<DTO>

    ret = new ArrayList<DTO>(arg.size()); for (String key : arg.keySet()) { ret.add(new DTO(key, arg.get(key))); } return ret; } バッドコードからプロダクトコードへ
  24. • このコード、どこかおかしい? public void doSomething() { try { do... }

    catch(Exception e1) { try { rollback(); log(e1); throw new RuntimeException(e1); } catch(Exception e2) { log(e2); throw new RuntimeException(e2); } } } バッドコードからプロダクトコードへ
  25. • このコード、どこかおかしい? public void doSomething() { try { do... }

    catch(Exception e1) { log(e1); try { rollback(); } catch(Exception e2) { log(e2); } finally { throw new RuntimeException(e1); } } } バッドコードからプロダクトコードへ
  26. • このコード、どこかおかしい? public void doSomething() { try { do... }

    catch(Exception e) { } } バッドコードからプロダクトコードへ
  27. • このコード、どこかおかしい? public void doSomething() { try { do... }

    catch(Exception e) { // NOP } } バッドコードからプロダクトコードへ
  28. • このコード、どこかおかしい? public void doSomething() { Integer[] intArray = new

    Integer[10]; Arrays.sort(intArray, new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { do... } }); } バッドコードからプロダクトコードへ
  29. • このコード、どこかおかしい? private static final Comparator<Integer> SORTER = new Comparator<Integer>()

    { @Override public int compare(Integer o1, Integer o2) { do... } }; public void doSomething() { Arrays.sort(intArray, SORTER); } バッドコードからプロダクトコードへ
  30. • このコード、どこかおかしい? public String concat(String str, int num) { StringBuilder

    sb = new StringBuilder(); for (int i = 0; i < num; i++) { sb.append(str); } return sb.toString(); } バッドコードからプロダクトコードへ
  31. • このコード、どこかおかしい? public String concat(String str, int num) { StringBuilder

    sb = new StringBuilder(str * num); for (int i = 0; i < num; i++) { sb.append(str); } return sb.toString(); } バッドコードからプロダクトコードへ
  32. • このコード、どこかおかしい? private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd"); public

    static void doSomething(Date date) { .... String formatDate = sdf.format(date); .... } バッドコードからプロダクトコードへ
  33. • このコード、どこかおかしい? public static void doSomething(Date date) { SimpleDateFormat sdf

    = new SimpleDateFormat("yyyy/MM/dd"); .... String formatDate = sdf.format(date); .... } バッドコードからプロダクトコードへ
  34. • このコード、どこかおかしい? private static Pattern pattern = Pattern.compile("a.c"); public void

    isValidFormat(String str) { return pattern.matcher(str).matches() } バッドコードからプロダクトコードへ
  35. • このコード、どこかおかしい? public void doSomething() { try { do... }

    catch (Exception e) { throw new RuntimeException(); } } バッドコードからプロダクトコードへ
  36. • このコード、どこかおかしい? public void doSomething() { try { do... }

    catch (Exception e) { throw new RuntimeException(e); } } バッドコードからプロダクトコードへ
  37. • この設定、どこかおかしい? ※ https://logging.apache .org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html <appender name="stdout" class="org.apache.log4j.ConsoleAppender"> <param name="Target"

    value="System.out" /> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d{yyyy MM dd HH:mm:ss,SSS} %C %F %m%n" /> </layout> </appender> バッドコードからプロダクトコードへ
  38. • この設定、どこかおかしい? <appender name="stdout" class="org.apache.log4j.ConsoleAppender"> <param name="Target" value="System.out" /> <layout

    class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d %m%n" /> </layout> </appender> バッドコードからプロダクトコードへ
  39. オブジェクト指向:概念? public class UserCreateService { public boolean submit(String name, String

    password) { ... } } public class UserDeleteService { public boolean submit(String id) { ... } } public class UserService { public boolean create(String name, String password) {...} public boolean delete(String id) {...} }
  40. 演習:内部構造を説明しよう(10min) • Spring Framework@OSSの AnnotationConfigApplicationContextの継承関係や関連するクラ スをペアを組んで説明してみましょう。 ※ https://goo.gl/PlJKB1 • 条件

    • 手法は問いません。 • コードを使っても良いですし、口頭でも構いません。 • 5分経ったら説明係を交代してください。
  41. UML:Three Amigos Grady Booch Ivar Hjalmar Jacobson James Rumbaugh 経緯はどうあれ、みんなRational

    Softwareの中の人 (Rational Softwareは2003年にIBMに買収された)
  42. UML:Structure No Diagram Overview 1 クラス図 オブジェクトの構造やオブジェクト間の関係、役割 を表現 2 オブジェクト図

    特定条件下におけるオブジェクト同士(インスタン ス同士)の関係を表現 3 コンポジット構造図 ※ UML2.0で追加 クラスやコンポーネント等の内部構造と関係を表現 4 コンポーネント図 ソフトウェアコンポーネントの構成を表現 5 配置図 ハードウェア、ソフトウェア、ディレクトリなどを どう配置するかを表現 6 パッケージ図 パッケージ間の関係やオブジェクトがどのパッケー ジに属するかを表現
  43. UML:Behavior No Diagram Overview 1 シーケンス図 オブジェクト間(インスタンス間)のやりとりを時 間系列で表現 2 コミュニケーション図

    (コラボレーション図) 〃 ※ シーケンス図より表現力が乏しいので存在感薄い 3 タイミング図 ※ UML2.0で追加 リアルタイムのような短時間での状態遷移や時間制 約、メッセージ送受信などを表現 4 相互作用概要図 ※ UML2.0で追加 シーケンス図、アクティビティ図などを相互作用図 として概要化し全体を俯瞰して表現 5 ステートマシン図 状態を持つ概念にフォーカスして生成から破棄まで の状態遷移を表現 6 アクティビティ図 システムや業務の活動、データの流れ、条件分岐な どを表現 ※ フローチャートに近い 7 ユースケース図 対象機能と利用者や他システムなどの外部的な関係 を表現
  44. UML:今日やるダイアグラム No Diagram Overview 1 クラス図 オブジェクトの構造やオブジェクト間の関係、役割 を表現 2 オブジェクト図

    特定条件下におけるオブジェクト同士(インスタン ス同士)の関係を表現 3 シーケンス図 オブジェクト間(インスタンス間)のやりとりを時 間系列で表現
  45. 演習:UML:クラス図(20min) • タウンワークはひとつひとつが原稿という枠で扱われます • ユーザーにはカスタマーとクライアントがいます • 原稿には複数のカスタマーが応募でき、カスタマーは複数の原稿に応募で きます • 原稿を出稿するクライアントは応募先として管理されます

    • クライアント機能として「おうぼうけるくん(UK)」というものがあり、 応募先とUKアカウントはメールアドレスで関連付けられます。 • 応募先が異なっていてもメールアドレスが同じなら同じUKアカウント • UKアカウントにはアカウントごとに固有のUK設定がひとつあります • クライアントには管理者とメンバーがいて、管理者がUKアカウントにひ も付き、管理者アカウントが削除されるとメンバーもUKが使えなくなり ます • メンバーも削除されます • 応募するとチャットが開始され、カスタマーとUKアカウントがチャット ルームに関連付けられます
  46. 開放 / 閉鎖原則 (Open Closed Principle:OCP) Carrier carrier = mobile.getCarrier();

    switch (carrier) { case DOCOMO: form.KW = ResponseUtils.encodeURL(form.KW, "windows-31j"); break; case AU: form.KW = ResponseUtils.encodeURL(form.KW, "windows-31j"); break; case SOFTBANK: form.KW = ResponseUtils.encodeURL(form.KW, "windows-31j"); break; case SOFTBANK3G: form.KW = ResponseUtils.encodeURL(form.KW, "UTF-8"); break; case WILLCOM: // 新規キャリアが参画したら case ブロックを追加する必要があるかもしれない // case SPRINT: // case ATT: // case VERIZON: default: form.KW = ResponseUtils.encodeURL(form.KW, "windows-31j"); break; }
  47. 開放 / 閉鎖原則 (Open Closed Principle:OCP) Carrier carrier = mobile.getCarrier();

    CarrierStrategy carrierStrategy = CarrierStrategyFactory.buildStrategy(carrier); form.KW = carrierStrategy.encodeURL(); public class CarrierStrategyFactory { public static CarrierStrategy buildStrategy(Carrier carrier) { switch (carrier) { case DOCOMO: return new DoCoMoStrategy(); case AU: return new AuStrategy(); case SOFTBANK: return new SoftBankStrategy(); case SOFTBANK3G: return new SoftBank3GStrategy(); case WILLCOM: default: return new DefaultStrategy(); } } }
  48. 単一責任の原則 (Single Responsibility Principle:SRP) • 凝集度を考えるとき、SRP (Single Responsibility Principle:単 一責任の原則)

    が基本的な考え方になる。 • SRP は「1 つのクラスは 1 つの責務 (だけ) を持つ」を原則とし、 複数の責務を 1 つのクラスに持たせないことに意識を向けている。 • 責務が端的で分かりやすいものであればクラスの境界がはっきりし、 新たな機能を追加するときどこを修正すれば良いのか、何のクラス を追加すれば良いのかが明確になる。 • 「唯一の責務を全うするために属性や操作が集まっている」、これ が凝集しているということである。
  49. 継承と委譲 • 一般的に「継承」は差分プログラミング的なコードの再利用を例に 説明されることが多い。この効用は非常に直感的でわかりやすいた め、多くのプログラマーは「コードの再利用 == 継承」と捉えて 多用する傾向が強い。もちろん継承によるコードの再利用は正しい ことだが、誤用はクラスの凝集度を下げ、結合度を高めることにな りかねないので、用法用量を守って正しく使うことが大切となる。

    • 継承はクラスの関係を密にし、クラスが持つべき本来の責務範囲を 逸脱し肥大化する恐れがあり、「結局このクラスの責務は何?」状 態になる可能性が高い。 • それを回避しつつコードの再利用を実現する手段には何があるか。 「委譲」だ。具体例は後述するが、以下の観点に基づき継承でコー ドの再利用を実現するか、委譲で実現するかを決定すると良いコー ドになる。 • 「型」の再利用は継承 • 「機能」の再利用は委譲