nesheep5's blog

プログラミング・子育て・家づくり・音楽 etc...

Scala入門時に役立つ情報まとめ

はじめに

Scalaの勉強を始めた時にJavaRubyと比べると情報量が少なく苦戦したので、今まで調べたことや経験者から聞いた情報などをまとめてみようと思います。
私自身まだまだ初心者ですが、これからScalaやってみようかなと思っている人の参考になれば幸いです。

WEBサイトで勉強する

ScalaのインストールやHelloWorldなどは検索するとすぐ見つかるので割愛します。
Scala特有の記法や概念などを勉強するのに以下のサイトが参考になりました。

技術系

読み物系

勉強会・イベントに参加する

技術書選びやネットでの勉強が意外と苦戦したので、勉強会を探して経験者に直接聞く作戦に切り替えました。ただ勉強会も他の言語に比べると少ないです。
関東で唯一?定期開催している芸者東京エンターテインメント社の「Scala勉強会in東京」にお邪魔させていただきました。
結果として作戦は大成功で、有益な情報がたくさん聞けました。可能な限り通いたいと思います。
またScalaをテーマにした日本最大級のカンファレンス「ScalaMatsuri」が2016年1月30、31日に開催されるので参加してみようと思います。

書籍で勉強する

通称コップ本と呼ばれる「Scalaスケーラブルプログラミング第2版 (2016/09/20に第3版が出版されました!)」がいちばん有名です。ただし全35章、700ページ超えと、初心者が読み切るにはそれなりの覚悟が必要です。苦笑

業務でScala使っている方に伺ったところ、普段は「Scala逆引きレシピ」で調べて、深く知りたい箇所をコップ本で勉強するのが良いのでは。との回答でした。
個人的には「関数プログラミング実践入門」「Javaによる関数型プログラミング」を読んでいたおかげで比較的すんなり頭に入ってきた感があるので、関数型プログラミングを全く知らない方は合わせて読むと良いかも知れません。

※ 参考:Scalaを学ぶためのScala本の読み進め方 (10冊)

問題を解く

とにかくコード書くのが上達の近道とのことで、別言語技術書のサンプルソースScalaに書き直す、などやったりするそうです。
最近はオンラインでプログラミングの問題を解くことができるので、簡単なレベルのものからScalaで書いています。プロコン系は開催日が指定されていることが多いので、自分のペースで進められる「Paiza」「AOJ」あたりがオススメです。
また「AtCoder」は過去問について他ユーザの回答を閲覧できるので、自力で解いた後に他の回答を見て良いところを盗む、といった使い方ができます。

Scala界の著名エンジニアを追う

Scalaの最新情報をキャッチアップする方法について勉強会で相談したところ、口を揃えて「吉田さんをフォローしろ」と言われました。
てっきりどこかのサイトを教えてもらえるものだと思っていたので、エンジニアをフォローするというアプローチはかなり新鮮でした。
私が参考にさせてもらっているエンジニアの方たちを挙げさせてもらいます。(50音順)

瀬良 和弘さん

エムスリー社ソフトウェアエンジニア。 ScalikeJDBC、Skinny Framework など Scala OSS プロジェクトリード。 Scalatra、json4s、Scalate のメンテナ。

竹添 直樹さん

ビズリーチ社チーフアーキテクト。 Scala逆引きレシピ著者、GitBucketファウンダー。

中村 学さん(がくぞさん)

株式会社Tech to Value 代表取締役。 Japan Scala Association理事。

水島 宏太さん

ドワンゴプログラマ。 Japan Scala Association代表理事。

Kenji Yoshidaさん

scalazとsbtとargonautとscalikejdbcのコミッター。

フレームワーク関連

WEBアプリフレームワーク

Play Framework」がデファクトスタンダードと言ってよさそうです。執筆時点で安定版である2.4系の情報が意外と少ないので、古い記事は公式の移行ガイドなどを見ながら読み替えをする必要になるかも知れません。ビズリーチ社のハンズオンは2.3系、2.4系が用意されているのでとても参考になりました。
シンプルでSinatraライクなWebフレームワークとして「Scalatra」も人気があるようです。

DBアクセスライブラリ

SlickScalikeJDBCが二大勢力のようです。SlickはPlayFrameworkの標準ライブラリになりました。
ScalikeJDBCは前述のエンジニアの方たちが作っているので、本当に困ったら直接聞けるというメリットがあります。(と勉強会で教わりました。笑)
私個人はScalikeJDBCを勉強し始めた段階なので、それぞれの良さがわかった頃に改めてまとめたいと思います。

※ 参考:Slick vs ScalikeJDBC

その他

scalazを使うエンジニアを業界では「Z戦士」と呼ぶそうです。笑

開発環境関連

IntelliJ IDEA

PlayFrameworkの勉強時、始めはEclipseにScalaIDEというプラグインを入れて使っていたのですが、動作が不安定&重いのでIntelliJ IDEAに乗り換えてみました。まだ使い始めなので慣れないですが、サクサク動いておすすめです。

ATOM

最近注目のテキストエディタATOMを使って開発環境を整えることもできるそうです。IDEを使うには大げさすぎる時など状況によって使い分けるといいかもしれません。 * AtomでのScala開発環境 - たけぞう瀕死ブログ

小ネタ

REPLでシンタックスハイライト

  • Scala 2.11.4より、ターミナルで"scala -Dscala.color"と入力してREPLを起動するとちょっとだけ(REPL結果の変数と型だけ)カラー表示となる。

Java8 逆引き Stream API

はじめに

Java8の新機能、Stream APIを使い始めてコーディングが格段に楽になりました。 備忘録的にサンプルコードを書き出してみました。少しずつ追加していく予定です。 Javaは使ったことあるけどラムダ式やStream APIはよく知らないという方は、参考にしてみてください。 バリバリ使っている方は、こんな使い方もあるよ!と教えていただけると嬉しいです。

ちなみにオライリー社のJavaによる関数型プログラミング ―Java 8ラムダ式とStreamがとても参考になりました。

【前提条件】Stream APIの説明に使用するオブジェクト

public class Person {
  private String name;
  private int age;
  private List<Person> children;

  public Person(String name){/*...*/}
  public Person(String name, int age){/*...*/}
  public Person(String name, int age, Person... children){/*...*/}
  
  @Override
  public String toString() {/* name(age) [children...] */}
  
  // getter, setter...
}

コレクション、配列、MapをStreamクラスに変換(Arrays#stream,Stream#of)

  // コレクション
  List<String> list = new ArrayList<>();
  Stream<String> listStream = list.stream();

  // 配列
  String[] ary = new String[] {"AA","BB","CC"};
  Stream<String> aryStream1 = Arrays.stream(ary);
  Stream<String> aryStream2 = Stream.of(ary);

  // MAP
  Map<String,String> map = new HashMap<>();
  Stream<Entry<String, String>> mapStream = map.entrySet().stream();

メソッド参照・コンストラクタ参照(Class::method)

  String[] names = new String[] {"Tom","Bob","Alice"};

    Stream.of(names)
      // コンストラクタ参照
      .map(Person::new) // name -> new Person(name)
      // メソッド参照
      .forEach(System.out::println); // person -> System.out.println(person)
      // Tom(0)
      // Bob(0)
      // Alice(0)

Personリストからnameリスト作成(Stream#collect,Collectors#toList)

  List<Person> persons = new ArrayList<>();
  persons.add(new Person("Tom",  21));
  persons.add(new Person("Bob",  25));
  persons.add(new Person("Alice",19));

  List<String> nameList =
    persons.stream()
      .map(Person::getName)
      .collect(Collectors.toList());
 
  nameList.steram().forEach(System.out::println);  
    // "Tom"
    // "Bob"
    // "Alice"

PersonリストからnameのCSV作成(Stream#collect,Collectors#joining)

  List<Person> persons = new ArrayList<>();
  persons.add(new Person("Tom",  21));
  persons.add(new Person("Bob",  25));
  persons.add(new Person("Alice",19));

  String nameCSV =
    persons.stream()
      .map(p -> String.format("\"%s\"", p.getName()))
      .collect(Collectors.joining(","));

  System.out.println(nameCSV);
  // "Tom","Bob","Alice"

Personリストからageの重複なしリスト作成(Stream#distinct)

  List<Person> persons = new ArrayList<>();
  persons.add(new Person("Tom",  21));
  persons.add(new Person("Bob",  25));
  persons.add(new Person("Alice",19));
  persons.add(new Person("Mike", 19));

  List<Integer> ageDistinctList =
    persons.stream()
      .map(Person::getAge)
      .distinct()
      .collect(Collectors.toList());
    
  ageDistinctList.stream().forEach(System.out::println);
  // 21
  // 25
  // 19

Personリストをage順にソート(Stream#sorted,Comparator#comparingInt)

  List<Person> persons = new ArrayList<>();
  persons.add(new Person("Tom",  21));
  persons.add(new Person("Bob",  25));
  persons.add(new Person("Alice",19));

  persons.stream()
    .sorted(Comparator.comparingInt(Person::getAge))
    .forEach(System.out::println);
    // Alice(19)
    // Tom(21)
    // Bob(25)
    

Personリストをname頭文字でグループ化(Comparator#groupingBy)

  List<Person> persons = new ArrayList<>();
  persons.add(new Person("Tom",  21));
  persons.add(new Person("John", 18));
  persons.add(new Person("Jack", 19));

  Map<Object,List<Person>> nameIndex =
    persons.stream()
      .collect(Collectors.groupingBy(p -> p.getName().charAt(0)));

    System.out.println(nameIndex);
    // {J=[John(18), Jack(19)], T=[Tom(21)]}

Personリストからchildrenリスト作成(Stream#flatMap)

  List<Person> persons = new ArrayList<>();
  persons.add(new Person("Tom", 21,
                  new Person("Tomas", 1), 
                  new Person("Tommy", 0)));
  persons.add(new Person("Bob", 25,
                  new Person("Bobby", 2)));
  persons.add(new Person("Alice", 19));

  persons.stream()
    .flatMap(person -> person.getChildren().stream())
    .forEach(System.out::println);
    // Tomas(1)
    // Tommy(0)
    // Bobby(2)    

try-with-resourcesでリソース解放されないパターン

はじめに

Java7から"try-with-resources"構文が追加されました。 ファイルやDBアクセスしたあとのリソース解放を自動で行ってくれる大変便利な機能で、解放し忘れをなくし、コードをすっきりさせることができます。 ただし、書き方によってリソースが解放されないパターンがあったので紹介します。

具体的には以下のような場合です。 リソース解放の対象クラスをネストさせてインスタンス生成した場合、コンストラクタで例外が発生するとリソース解放されません。

File file = new File("out.txt");
// PrintWriterがインスタンス生成に失敗すると、BufferedWriter・FileWriterが解放されない
try(PrintWriter pw = 
        new PrintWriter(new BufferedWriter(new FileWriter(file)));) {
    // 処理
}
// ・・・

検証

各Writerクラスにログを仕込み、どのような動作をするか検証してみました。

public class Test {
    public static void main(String[] args) {

        File file = new File("out.txt");
        try (PrintWriter pw = 
                new PrintWriterWrapper(
                new BufferedWriterWrapper(
                new FileWriterWrapper(file)));) {
            System.out.println("func");
        } catch (Exception e) {
            System.out.println("catch:" + e);
        } finally {
            System.out.println("finally");
        }
    }

    // 以下、ログを追加したラッパークラス

    public static class PrintWriterWrapper extends PrintWriter {

        public PrintWriterWrapper(Writer out) {
            super(out);
            System.out.println("new PrintWriter");
        }

        @Override
        public void close() {
            System.out.println("close PrintWriter");
            super.close();
        }
    }

    public static class BufferedWriterWrapper extends BufferedWriter {

        public BufferedWriterWrapper(Writer out) {
            super(out);
            System.out.println("new BufferedWriter");
            throw new RuntimeException();
        }
        @Override
        public void close() throws IOException {
            System.out.println("close BufferedWriter");
            super.close();
        }
    }

    public static class FileWriterWrapper extends FileWriter {

        public FileWriterWrapper(File file) throws IOException {
            super(file);
            System.out.println("new FileWriter");
        }

        @Override
        public void close() throws IOException {
            System.out.println("close FileWriter");
            super.close();
        }
    }
}

処理が正常終了する場合、作成したインスタンスを逆順でリソース解放(closeメソッド実行)しています。

// ・・・
// ネストでインスタンス生成する
try (PrintWriter pw = 
        new PrintWriterWrapper(
        new BufferedWriterWrapper(
        new FileWriterWrapper(file)));) {
    System.out.println("func");
}
// ・・・

// 実行結果(close()が実行されている)
// new FileWriter
// new BufferedWriter
// new PrintWriter
// func
// close PrintWriter
// close BufferedWriter
// close FileWriter
// finally

ただしコンストラクタで例外が発生した場合、内包するインスタンスに対するリソース解放がされません。

// ・・・
// ネストでインスタンス生成する
try (PrintWriter pw = 
    new PrintWriterWrapper(
    new BufferedWriterWrapper(
    new FileWriterWrapper(file)));) {
  System.out.println("func");
}

// ・・・

// PrintWriterWrapperのコンストラクタで例外発生させる
public PrintWriterWrapper(Writer out) {
    super(out);
    System.out.println("ERROR!! new PrintWriter");
    thorow new RuntimeException();
} // ・・・

// 実行結果(close()が実行されない)
// new FileWriter
// new BufferedWriter
// ERROR!! new PrintWriter
// catch:java.lang.RuntimeException
// finally

ポイントは以下の2点です。

  • "try句で変数として宣言されたインスタンス"が自動リソース解放の対象となる
  • try句でインスタンス生成する際、コンストラクタで例外が発生した場合はcloseメソッドが実行されない

検証1では、変数pwのcloseメソッドが実行され、内包するBufferedWriter、FileWriterを連鎖的にcloseしています。 検証2では変数pwのcloseメソッドが実行されず、内包するインスタンスも自動リソース解放の対象となっていないためそのまま残ってしまいます。

解決法:ネストせず個別に変数定義する

結論として、コンストラクタで例外が発生しないことが明白である場合以外は個別に変数定義するのが良さそうです。 以下の例ではPrintWriterのインスタンス生成に失敗した場合もBufferedWriter、FileWriterのcloseメソッドが実行されています。 (FileWriterのcloseメソッドが2回実行されているのは、BufferedWriterのcloseメソッドから連鎖的に実行されたのと変数fwとして宣言したため自動リソース解放の対象となっているためです。)

// ・・・
// 個別にフィールドを宣言し、それぞれインスタンス生成する
try ( FileWriter fw = new FileWriterWrapper(file);
    BufferedWriter bw = new BufferedWriterWrapper(fw);
    PrintWriter pw = new PrintWriterWrapper(bw);) {
  System.out.println("func");
}

// ・・・

// PrintWriterWrapperのコンストラクタで例外発生させる
public PrintWriterWrapper(Writer out) {
    super(out);
    System.out.println("ERROR!! new PrintWriter");
    thorow new RuntimeException();
}
// ・・・

// 実行結果(close()が実行されている)
// new FileWriter
// new BufferedWriter
// ERROR!! new PrintWriter
// close BufferedWriter
// close FileWriter
// close FileWriter
// catch:java.lang.RuntimeException
// finally

エンジニアの情報収集法まとめ

はじめに

プログラミング系の時事ネタは能動的に情報収集しないと入ってこないのですが、若手だった頃はどうやって情報を仕入れればよいのかさっぱり分かりませんでした。 情報収集のコツを掴んでからパッと視界が開けた経験があるので、特に新米エンジニアの方は参考にしてみてください。

ニュースアプリ

GunosySmartNewsなど色々試しましたが「はてなブックマーク」がプログラミング系記事多めでした。
通勤時間などに流し読みして、気になるものは深く調べると良いです。

はてなブックマーク
はてなブックマーク - 人気エントリー - テクノロジーはてなブックマーク - 人気エントリー - テクノロジー 

ITニュース

Webサイト

TechCrunch Japan
TechCrunch Japan - 最新のテクノロジーとスタートアップ・Webに関するニュースを配信するブログメディアTechCrunch Japan - 最新のテクノロジーとスタートアップ・Webに関するニュースを配信するブログメディア
POSTD
POSTD | プログラミングの話題を翻訳して届けるエンジニアのためのニュースメディアPOSTD | プログラミングの話題を翻訳して届けるエンジニアのためのニュースメディア
CodeZine(コードジン)
CodeZine(コードジン)CodeZine(コードジン)
CodeIQ MAGAZINE
CodeIQ MAGAZINE|エンジニアのためのWebマガジンCodeIQ MAGAZINE|エンジニアのためのWebマガジン
SELECK [セレック]
SELECK [セレック]|企業の隠れた知が集まるビジネスライブラリSELECK [セレック]|企業の隠れた知が集まるビジネスライブラリ
UX MILK
UX MILK | クリエイターのためのUXメディアUX MILK | クリエイターのためのUXメディア
geechs magazine(ギークスマガジン)
フリーランスエンジニアの「イマ」を知る | geechs magazine(ギークスマガジン)フリーランスエンジニアの「イマ」を知る | geechs magazine(ギークスマガジン) 

メールマガジン

Frontend Weekly
Frontend WeeklyFrontend Weekly 

Web系企業・エンジニア技術ブログ

クックパッド開発者ブログ
クックパッド開発者ブログクックパッド開発者ブログ 
クラスメソッド株式会社ブログ | Developers.IO
AWS/iOS技術者の必読メディア:クラスメソッド株式会社ブログ | Developers.IOAWS/iOS技術者の必読メディア:クラスメソッド株式会社ブログ | Developers.IO 
Hatena Developer Blog
Hatena Developer BlogHatena Developer Blog 
サイボウズ
サイボウズ式 | 「新しい価値を生み出すチーム」のための、コラボレーションとITの情報サイトサイボウズ式 | 「新しい価値を生み出すチーム」のための、コラボレーションとITの情報サイト 
さくらのナレッジ
さくらのナレッジ | ITエンジニアに役立つ情報&おもしろネタを、 ホスティング・データセンター業界の最前線から 全力でシェア!さくらのナレッジ | ITエンジニアに役立つ情報&おもしろネタを、 ホスティング・データセンター業界の最前線から 全力でシェア! 
Social Change! ソニックガーデン SonicGarden 倉貫義人のブログ
Social Change! ソニックガーデン SonicGarden 倉貫義人のブログSocial Change! ソニックガーデン SonicGarden 倉貫義人のブログ 

技術情報共有サービス

Qiita
Qiita - プログラマの技術情報共有サービスQiita - プログラマの技術情報共有サービス 

学習系Webサイト

ドットインストール

動画でプログラミング学習できるサイト。様々なプログラミング言語の入門向け情報がまとめられています。新人の学習はもちろん、新しい言語に挑戦するときの最初の一歩にも最適。

ドットインストール - 3分動画でマスターする初心者向けプログラミング学習サイトドットインストール - 3分動画でマスターする初心者向けプログラミング学習サイト 
ひしだま’s 技術メモページ

個人運営のWebサイト。情報量が多く、特にJavaScalaの勉強でお世話になっています。

ひしだまのコンピューター関連技術メモ(Hishidama's Programming MemoPage)ひしだまのコンピューター関連技術メモ(Hishidama's Programming MemoPage) 

質問系Webサイト

エンジニア版Yahoo知恵袋のようなQ&Aサービス。開発中一番お世話になります。

StackOverFlow

おそらく世界で一番有名なQ&Aサイト。日本語版もできました。

Stack OverflowStack Overflow 
Teratail

最近話題の日本版StackOverFlow。レバレジーズ社のサービス。

teratail【テラテイル】|思考するエンジニアのためのQAプラットフォームteratail【テラテイル】|思考するエンジニアのためのQAプラットフォーム 

スライド共有サイト

プレゼン資料の共有サービス。登壇者が発表後アップしていることが多いので復習しましょう。

SlideShare
Share and Discover Knowledge on LinkedIn SlideShareShare and Discover Knowledge on LinkedIn SlideShare 
SpeakerDack
Speaker Deck - Share Presentations without the MessSpeaker Deck - Share Presentations without the Mess 

技術系イベント検索サイト

特にdots.がオススメ。エンジニア向けイベント検索に特化していて、気になる技術にチェックを入れておくと関連イベントをメール通知してくれます。

dots.
dots. [ドッツ] - IT勉強会・セミナーなどのイベント情報サイトdots. [ドッツ] - IT勉強会・セミナーなどのイベント情報サイト 
connpass
connpass - エンジニアをつなぐIT勉強会支援プラットフォームconnpass - エンジニアをつなぐIT勉強会支援プラットフォーム 
ATND
イベント開催支援ツール アテンド : ATNDイベント開催支援ツール アテンド : ATND 
Doorkeeper

セミナー・勉強会・イベント管理ツール | Doorkeeper
セミナー・勉強会・イベント管理ツール | Doorkeeper  

勉強会・イベントスペース

最近エンジニア向けのイベントスペースが増えてきました。渋谷に集中しているようです。都心勤務の方はぜひ。

ヒカ☆ラボ(渋谷ヒカリエ)

レバレジーズ社がエンジニア、クリエイターの方のために無料で開催する勉強会。

ヒカラボとは | ヒカラボヒカラボとは | ヒカラボ 
21Cafe<ニイイチカフェ>(渋谷区道玄坂)

geechs社が運営する、エンジニア&デザイナーのための無料イベントスペース。


    ABOUT|エンジニア&デザイナーのための無料イベントスペース 21cafe<ニイイチカフェ>    ABOUT|エンジニア&デザイナーのための無料イベントスペース 21cafe<ニイイチカフェ>  
dots. イベントスペース(渋谷区宇田川町)

イベント情報検索サービス「dots.」のイベントスペース。

dots. [ドッツ] - IT勉強会・セミナーなどのイベント情報サイトdots. [ドッツ] - IT勉強会・セミナーなどのイベント情報サイト 

コミュニティ

カンファレンス

技術系雑誌

そのまま業務で使えるような特集が多く組まれており、得た知識を実戦投入しやすいのが魅力です。 雑誌で幅広く情報をキャッチして、気になる技術は技術書などで深く勉強する、などすると良いと思います。

ポッドキャスト

  • Rebuild.fm :
    宮川達彦さんがMCを務める、おそらく日本で一番有名なテック系ポッドキャスト。毎回ゲストを迎え、ITニュース、技術、ガジェットなどの最新時事ネタからアニメまで幅広いテーマを扱います。伊藤直也さんゲスト回のエモい話は必聴。

  • mozaic.fm :
    Rebuild.fmと比べ、より技術に特化したド直球のポッドキャストJxckさんがMCを務めています。更新は少なめですが、何度もじっくり聞き直したくなる濃い内容です。

  • codelunch.fm :
    「エンジニアがランチの時に話すような技術ネタ」がコンセプトのポッドキャスト。なかでも和田卓人(@t_wada)さんがPaworAssertについて語った第16,17回は必聴です。

Slack公開グループ

著名エンジニア

技術書や技術系ブログの著者、技術系イベントの登壇者など、気になった人をフォローすると新鮮な情報が入ってきて勉強になります。

技術全般
Java
Ruby
Scala
テスト駆動開発
人工知能
セキュリティ

サックスレッスンメモ

基礎練習

前回の宿題を確認。sus4を12キー覚えているか、

  • 半音で上昇(C-C#...)
  • ランダム

でチェック。得意なキー、苦手なキーが如実に表れていたので、満遍なく練習すること。

そのあと新たに半音フレーズ を教えてもらいました。
上手そうに聴こえる基礎練シリーズです。笑

  • 半音上昇→全音下降(C#-D-C-C#...)
  • 半音下降→全音上昇(D-C#-D#-D...)

アドリブ中、コードでのアプローチに疲れた時に使ったりするそう。

色んなフレーズを

  • dimサークル
  • ホールトーンサークル
  • 4度サークル で練習すること。 楽器がないときにも出来るので、頭の体操としてやる。

曲練習

  • 速い曲の場合、2,4で乗ったりスイングしようとは思わない。1拍目を感じて、ゆったり大きく吹く。縦ノリ
  • フレーズが切れてしまうので、ずーっと音が続いているようなイメージを持つ
  • 裏拍(1裏)は、強めのタンギングで少し前めで吹く。そうすると後ろのフレーズが詰まらず、ゆったり吹ける。=余裕があるように聴こえる
  • アドリブの話し。コードに対して5thから始まるフレーズをよく使うとのこと。FM7に対してC始まり

前回のレッスン

  • jazzの場合、音程が高いと間違って聴こえる。低いのは許容範囲が広い。低いと暗く聴こえるので、わざと低めに取ることもある。「ピッチを気にしてフラフラ吹くより、多少低くても堂々と良い音で吹いたほうが合ってるように聴こえる」