エンターテイメント!!

遊戯王好きのJavaエンジニアのブログ。バーニングソウルを会得する特訓中。

SpringBootCLI + Groovy で "Hello Saga!"

きっかけ

安かったので買ってみたSpringBootの本に、Groovyで動かしている内容を見て、興味が湧いたので真似てみた。

実験

環境

OS

$sw_vers
ProductName:    Mac OS X
ProductVersion: 10.14.2
BuildVersion:   18C54

Spring Boot CLI

$spring --version
Spring CLI v2.1.2.RELEASE

homebrewで入れようとしたんだが、xcodeのバージョンが古いからダメですと言われて、かなり萎えた。。。
xcodeって、サイズが大きいから、アップデートするのシンドいんだよね。。。

ちなみに、homebrewでの入れ方は、下記。

$ brew tap pivotal/tap
$ brew install springboot

Groovy

Groovy Version: 2.5.5 JVM: 11.0.1 Vendor: Oracle Corporation OS: Mac OS X

実装

作るのは1クラスだけ。

@RestController
class App {
  @RequestMapping("/")
  def saga() {
    "Hello Saga!"
  }
}

Groovyだと、直後にメソッドから抜けることが確定してる式は、returnを省略できるので、"Hello Saga!"だけでいい。

実行は、spring run app.groovyでOK
しばらくすると、お馴染みのSpringBoot起動のコンソールが流れるはず。

俺の環境では、実行までにかなり時間がかかった。
こんなに遅かったか?と思って、Javaで書いたのを実行したら、ものすごい速かった。
groovyファイルをコンパイルするにしては長かった。
メッセージの内容をみていると、依存関係の解決が長かったので、groovyのコンパイルにひきづられて、何かの依存関係の解決もやり直しになってるんだろうなって推測。
詳しく調べるとハゲそうなので、とりあえず保留。

実行して、ブラウザでアクセスすると、Hello Saga!って出るはず。

ちなみにJavaで書いた時の記述

App.java 
@RestController
class App {
  @RequestMapping("/")
  public String saga() {
    return "Hello Saga!"
  }
}

groovyは、java特有の宣言記述が省略されてるのがよくわかる。

参考サイト

Spring Boot CLI と Groovy 7行で Hello, world! してみる - Qiita

【書評】最新JavaScript開発〜ES2017対応モダンプログラミング

まとメモ

JavaScript解説

ECMAScript

JavaScriptから言語仕様を抽出した規格。
ブラウザ操作のAPIであるDOM等を除いたものが定義されている。

Node.js

Node.jsの登場でJavaScriptCLIとして動くようになった。

JavaScriptの使われ方とその問題

複雑化に対応するために高速に進化した反面、クロスドメインで使われることが多くなった。
他言語エンジニアが片手間で書いたコードは、メンテが難しく進化に対応できていないことが多い。

APIサーバーとJSの分離による解決

APIサーバーとウェブクライアントが分離されることで、言語が入り混じることが少なくなった。
しかし、まだドメイン知識が重複してしまっているところがある。

今は、Node.jsの登場で、APIサーバーも構築できるようになっている。

JavaScriptの始め方

Node.jsのインストール

windows:Nodist
mac:anyenv+ndenv

トランスパイラ

コンパイラのようなもの。
JavaScriptを吐き出すのが仕事。

  • babel
  • webpack loader

バンドラ

複数ファイルを1ファイルにする。
モジュール開発しつつ、Webブラウザ上でうごくものを開発できる。

  • browserify
  • webpack
  • rollup

クセがどれも強い。

型の恩恵を受ける

Flow

静的な型チェックを行う。
プロジェクトの一部分に導入できることもできる。

型の概念は、TypeScriptに似ている。
mixed・合成型って型があるのが特徴的。

ユニットテストをしよう

  • AVA
    • テストの並列実行可能
    • 並列で処理するため高速

TDD

  • チケット駆動開発
  • 設計・開発のための技法
  • 雑な作りから、より洗練されたコードを作って行くのに向いている。

黄金サイクル

Red→Green→RefactorのサイクルがTDDの基本。

Red:テストだけ書く Green:テストを通る最小限のコードを書く Refactor:リファクタリングしてコードを洗練させる。

最初は、コンパイルエラーが出ず、テストに失敗する状態を作る。
テストも偶然通るような実装にはしないほうがいい。正しい実装に変化したことがわかりづらくなるため。
テストが通るようになったら、リファクタリングを行う。
この際に、挙動を変えないように注意する。
挙動が変わったかどうかは、テストの実行で確認する。

十分に仕様を設計・実装できていると確信できるものに対しては、サイクルを回す意味は薄い。

ウェブブラウザ向けの開発におけるテスト

E2Eテストは、書かなくて済むのなら、書かないほうがいい。
やる場合、テスト実行時間が長いこと、非効率であることに留意する必要がある。

E2Eテストの選択肢

  • Selenium WebDriver
  • Pantom.js
  • SlimerJS
  • Nightmare

Appendix JavaScriptの歩き方

できる限り公式ドキュメントを読む

日本語の情報は、古くなってる可能性が高い。
JavaScriptは開発が活発であるため、翻訳が追いつかないことが多い。

英語が苦手な人は、Google翻訳でOK

公式以外

  • stack overflow
  • Qiita
  • jser.info

技術選定には注意する

JavaScriptは、新陳代謝が早い。
今主流でも、2・3年後には、非主流になっていることもある。
スタープログラマでも、技術選定でミスをする。
JavaScriptでうまくやっていくには、技術に対するアンテナ感度を上げておくことが必要。
基礎*1をしっかり作ることが大切。
マルチパラダイム言語であるため、他言語の知見を知っておくことは、技術選定ミスを犯しにくくさせる。

  • Google検索する場合は、1年以内のデータに絞る。
  • Githubのスター数

エンジニアが身につけるべき基礎力

名前をつける力

  • 名前を正しくつけることは、責務の抽象化能力
  • 名前から責務の範囲を考える
  • 名前にお約束を設ける

ウェブ

  • HTML5.1の仕様
  • CSSの仕様
  • React + Redux
    • シンプル
    • パワフル
    • 学習コストが高くない

感想

読んでて、俺は基礎ができているのか?って不安になる。
不安になるってことはできてないんだろうな。

HTML5/CSSの仕様は、読んだことがない。
利用するときに探すだけってことが多い。
一回くらいは、目を通したほうがいいかも知れない。

*1:個別の細かいやり方ではなく、汎用的な手法や本質的な知識

2019/01/07週 気づきと振り返り

業務こなしての問題

Androidのprogaurd

年を跨いで対応していたが、いろいろひどい目にあった。

いじっていたが、何がダメなのか、袋小路に入って、ひたすら悩んでいた。
progaurdが無効のまま、progaurd.proに修正入れても反映されないでいろいろ悩んでいたりした。

もう、今となっては些細な問題だと思う。
仕組みをなんとなく覚えられたので、もう同じ轍を踏むことはないと信じたい。

package.jsonのdependenciyの削除

uninstallで消しましょう。
記述を削除すると、インストール済みのものが残ったままになり、間違って使ってしまって、他人がビルドしたとき、もしくは、CIかかったときに慌てるハメになる。

前にも書いた気がするな。。。

Androidのログ

タグは、パッケージ名を参考にしたほうがいいのではないかと思いました。
なぜなら、フィルタリングが楽になると思うから。

現場のタグ名が、クラス名になっているのだが、実装したクラスのログすべてをフィルタリングしたいってときに、どうすればいいのかかなり迷った。
結局、いい方法が思いつかなかったので、全出力で皿目で見るという作業になってしまった。

マジでタグ名をどうするかは、真剣に考えたほうがいい。

getter/setterの価値

俺は必要ないと思う派。

それなら、ただのpublicフィールドでいいじゃんって感じる。

カプセル化って言う人をたまに見るが、「ロジックが必要ない箇所に適用して、何か意味があるの?」って思う。
ロジックがないなら、普通にそのフィールドにアクセスしているのとなんら変わらないじゃんって思うんですよ。

JavaだとLombokが一時期話題になっていたが、そもそも単純getter/setterは必要ないと思っていたので、熱は早めに冷めた。

無力感

1ヶ月くらい、成果物を作ってない気がするのだが。。。
調査した結果、対応を見送る、難易度高すぎて諦めたタスクがいっぱいある。。。

存在意義とか、自分の能力を疑いたくなっちゃうよね。。。
他の人はタスクこなしているのに、俺だけ取れ高ゼロだもんな。。。

個人的に思いついた名言

  • 俺は組織の爆弾になる。潤滑油になどなるものか!
  • やればできる子なんだ。今はやらないだけなんだ。

【書評】読んだら忘れない読書術

読んだら忘れない読書術

読んだら忘れない読書術

まとメモ

基本原則

  • 記憶に残す
  • スキマ時間の利用
  • 速読より深読

読書術

ホームラン読書術

たくさん読むのではなく、読みたい本を選んで、自己成長に繋がるものを選ぶ。

守破離読書術

本を読む時、どのステージにいるのかを意識する。

守:基礎を学ぶ基本
破:他人の方法を学べる応用
離:自分のスタイルを学ぶブレイクスルー

自分のレベルにあってないものを読むのは、理解を困難にする。
自己満足を得るだけで、成長は得られない。

入門読書術

入門書で基礎知識と全体像を把握する。
深い学びを得るには必要なこと。

お勧め読書術

推薦されている本は、比較的ハズレを引きにくい。
誰が勧めているのかが重要。

自分軸読書術

売れているかどうかにかかわらず、自分が読みたい本か見極める。

専門書読書術

専門書は、大型書店で。

ネット書店読書術

  • 他者評価を知ることができる。
  • 他者評価は鵜呑みにしてはいけない。
  • レコメンドを使って本を紹介してもらう。

セレンディピティ読書術

自分の興味・関心を理解し、情報フィルターを準備しておく。
必要な本を発見できる確率を上げられる。

直感読書術

本を読むことで、本を見分けるデータが貯まる。
その結果、選球眼が養われる。

数珠つなぎ読書術

参考文献から次に読む本を選定する。
固め読みしたほうが、記憶に残りやすい

失敗しない基準

  • バランス良く読む
  • 長所を伸ばし、短所を克服させる
  • 情報と知識の偏りをなくす
  • ポートフォリオを作る

感想

ちょっと独善的すぎかなって気もする。

2018/12/17週24週 気づきと振り返り

業務こなしての問題

Oauth認証のImplictフロー

認証周りをImplictフロー利用してやるような実装に変えるタスクにチャレンジ中。
おそらく、refreshトークン使って再認証する処理を入れ込むと、ロジックが複雑になって、難読化するからだと思われる。

実装しているのだが、iframeを利用するのがうまくできない。。。
裏でアクセスさせるのが、途中でコケてしまうのよね。
年末で解決できなかったけど、たぶん、年始の俺が頑張って解決してくれるはず。

submoduleの移動

git mvで移動できる。
設定ファイルをイジって、git submodule sync したりするよりも、手間が少なく安全にできる。
設定ファイルをいじってやる場合、1日無駄に過ごす覚悟が必要。

gerritでhook忘れ

毎回忘れるのだが、新しくリポジトリをクローンしてきた際に、hookの設定をし忘れて、コミット&プッシュした時に、changeidが付与されず、あとあとコミットメッセージを入れ込む作業をしてしまう。
gerritのクローンコマンドに何か入れられないものなのだろうか?
クローンしてきたら、hookの設定を勝手にしてくれるのが一番嬉しいのだが。。。

logcatの切替

Androidで、logcatを環境ごとに出力するレベルを切り替えたいのだが、どうすればいいか?
build.gradleだったかをイジったが、その設定はダメっていうビルドエラーが出てきて萎えた。

個人的に思いついた名言

  • 明日の俺が頑張ってくれるはず。

intellij idea で micronaut + spring jdbc + sqliteのサンプル

きっかけ

年始が暇だから、何か作ろうと思い立った。
springbootでちゃっちゃと作ろうと思ったが、micronautで挫折したことを思い出し、再度チャレンジ。
とりあえず、動いたので、まとめる。

挫折したらそのままってのが、いつものパターンだったが、ゾンビランドサガを全話通して見て、再度チャレンジしたくなった。

まとめ

環境

OS

$sw_vers
ProductName:    Mac OS X
ProductVersion: 10.14.2
BuildVersion:   18C54

Java

$java -version
openjdk version "11.0.1" 2018-10-16
OpenJDK Runtime Environment 18.9 (build 11.0.1+13)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.1+13, mixed mode)

Intellij IDEA

Intellij IDEA 2018.2.6 Community Edition

お金ないっす。。。
金がなくても、開発はできる。ちょっと手間が増えるだけ。

micronaut

$mn -V
| Micronaut Version: 1.0.2
| JVM Version: 11.0.1

インストールは、sdkmanを利用。
sdkmanは、Java関連の開発環境を用意するためのツール。
macのhomebrewみたいなもの。
前に調べたもののリンクを貼っておく。

suzaku-tec.hatenadiary.jp

インストールは、sdk install micronaut

sqlite

$sqlite3 -version
3.24.0 2018-06-04 14:10:15 95fbac39baaab1c3a84fdfc82ccb7f42398b2e92f18a2a57bce1d4a713cbaapl

sqlite関連

SqliteManager Version 4.8.1

まとめ

流れ

  1. micronaut初期化
  2. intellij にインポート
  3. とりあえずgoodmorning Saga!
  4. Sqliteにアクセスしてみる
    1. テストデータ用意
    2. spring jdbc + sqliteを追加
    3. ファクトリクラスの実装
    4. データアクセスサービスの実装
    5. コントローラクラスからDBアクセス
    6. 起動

micronaut初期化

まずは、micronautのプロジェクト作成から。

コマンドは、下記の通り

mn create-app {プロジェクト名}

このコマンドを打つと、カレントディレクトリにプロジェクト名のディレクトリが掘られて、gradle関連のソースが格納される。

今回は、mn create-app murakumoで作成

叢雲を選んだのは、個人のセンスです。

intellij にインポート

intellij を起動して、初期画面から import Project を選択してインポート。
インポートする際は、gradleのプロジェクトとしてインポートさせる。

じゃないと、いろいろエラーが出て挫折する。
たぶん、前回は、next連打してたから、気づかなかったのかも。。。
もしかしたら、import じゃなくて、openを選んで開いていたのかもしれない。

とりあえずgoodmorning Saga!

まずは、作ったら、goodmorning Saga!でしょ。
Hello Worldは、古い。

実装

package murakumo.controller;

import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;

@Controller("/hello")
public class HelloController {

    @Get("/")
    public String index() {
        return "Goodmorning Saga!!";
    }
}

動作確認

下記コマンドで動かす。

$ ./gradlew run

そうすると、なんかビルドして動き出すはず。
自分の環境では、進捗が75%で止まるのだが、75%で localhost:8080/hello でアクセスすると、Goodmorning Saga!!が表示されるはず。
たぶんだが、75%のやつは、描画が更新されてないだけで、100%なんじゃなかろうか?

Sqliteにアクセスしてみる

今回は、いろいろORマッパーを探したけど、良さげなのがなかったので、Spring jdbcを使う。
本当は、脱springでやりたかったのだが、しょうがない。

テストデータ用意

まずは、DBの用意。
Sqliteは、DB作ると同時にtableも作らないとダメなので、ちょっとやっかい。

sqlite3 murakumo.db

カレントディレクトリは、murakumo直下

打つと、sqliteCLIに入るので、テーブルを作成する。 適当に、下create table sample(id, name)で、sampleテーブルを作る。
きちんとできているか確認するため、.tableを打つ。
そうすると、sampleって表示されるはず。

そしたら、一旦、sqliteCLIを抜けるため、.exitを打つ。
テーブルへのテストデータ投入は、sqlitemangerからやる。
sql文を打つのが早い人は、そっちでもいい。

spring jdbc + sqliteを追加

テストデータは用意できたので、今度はsqliteを利用するためのライブラリを追加する。

build.gradleのdependenciesに下記を追加。

    compile "io.micronaut.configuration:micronaut-jdbc-tomcat"
    compile 'org.springframework:org.springframework.jdbc:3.2.2.RELEASE'
    compile "io.micronaut:micronaut-spring"
    compile group: 'org.xerial', name: 'sqlite-jdbc', version: '3.25.2'

保存したら、勝手にライブラリのダウンロードが走るはず。

そしたら、今度は、jdbc接続用の設定を、application.ymlに追加する。
datasourcesが、今回追加した箇所。

micronaut:
    application:
        name: murakumo

datasources:
    default:
        url: jdbc:sqlite:murakumo.db
        driverClassName: org.sqlite.JDBC

ファクトリクラスの実装

今度は、jdbcアクセスようのDatasourceを生成するクラスを書く。
俺はよく知らないが、spring-jdbcは、こうやるものらしい。

package murakumo.factory;

import io.micronaut.context.annotation.Factory;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.inject.Inject;
import javax.inject.Singleton;
import javax.sql.DataSource;

@Factory
public class JdbcTemplateFactory {

    @Inject
    DataSource dataSource;

    @Bean
    @Singleton
    JdbcTemplate jdbcTemplate() {
        return new JdbcTemplate(dataSource);
    }
}

JdbcTemplateを生成して返すだけ。

データアクセスサービスの実装

今度は、テーブルからデータを引っこ抜いてくるクラスを作る。

package murakumo.service;

import io.micronaut.context.annotation.Requires;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.Transactional;

import javax.inject.Singleton;

@Singleton
@Requires(beans = JdbcTemplate.class)
public class TestService {

    private final JdbcTemplate jdbcTemplate;

    public TestService(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    @Transactional
    public void printSampleTable() {
        jdbcTemplate.query("select * from sample", (rs) -> {
            System.out.println(rs.getString("id"));
            System.out.println(rs.getString("name"));
        });
    }

}

printSampleTableが実際にDBアクセスしている箇所。
ResultSetをLambda使って処理できるのは、今っぽい。
昔だと、resultSet取ってきたら、ぐるぐる回して結果を見るのが多かった。

コントローラクラスからDBアクセス

当然、アクセスは、DIしたものを使ってやる。
アノテーションは、@Injection でできるらしい。
Springは、たしか、@Autowired だったかな?
@Controllerや@Getは、Springに近い動きをするので、なんとなくわかる。

package murakumo.controller;

import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import murakumo.service.TestService;

import javax.inject.Inject;

@Controller("/hello")
public class HelloController {

    @Inject
    private TestService testService;

    @Get("/")
    public String index() {
        testService.printSampleTable();
        return "Goodmorning Saga!!";
    }
}

TestServiceをDIして、indexで使ってるだけ。

起動

./gradlew run で起動して、localhost:8080/helloにアクセス。

すると、ターミナルに、登録したデータが表示されるはず。

感想

なんでだ。。。
何に苦戦してたんだ、俺は。
すんなりできすぎて、逆に怖いんですけど。

あとは、spring-jdbcの知識がつけば、いろいろできそう。

組み込み系のDBは、もうsqlite一択な気がしてきたな。
mysqlやpostgressも考えたけど、環境準備するのが面倒くさいんだよね。
手軽に永続化できるのが、魅力だと思う。
docker使えば、mysqlとかの準備も楽そうな気もするが、dockerの習熟度がまだ足りない。

参考サイト

javaからsqliteに素早く書き込みたい - Qiita

Using Spring's JDBCTemplate with Micronaut

Spring Boot - Spring Boot MavenでSQLite3に接続したい。|teratail

データベースの作成と接続 - SQLite入門

java.lang.reflect.Proxyクラスを試してみる

きっかけ

JavaのAdvent Callendar で、Proxyクラスについて触れている記事があった。
そういえば、試したことが無かったので、暇な年始に試してみた。

実験

環境

java

$java -version
openjdk version "11.0.1" 2018-10-16
OpenJDK Runtime Environment 18.9 (build 11.0.1+13)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.1+13, mixed mode)

os

$sw_vers
ProductName:    Mac OS X
ProductVersion: 10.14.2
BuildVersion:   18C54

実装

今回、結構てこずった。。。。
何にてこずったかと言うと、必要となるクラスが思ったより多かったので、それの役割を理解するのが辛かった。。。
Javaのリフレクションの動きは分かっていたが、クラスが増えると、意外と混乱する。
あと、Javaから離れていたせいか、staticメソッドの制約を忘れていて、ドツボにハマった。。。

まずは、必要となるクラスの説明から

  • Main:実験用に呼び出すクラス
  • IFの定義(interface):今回のテスト対象のクラスのIF定義。なくてもいい気もするが、実装の隠蔽のためのプロキシなので、実際に使われる際の状況を意識するために用意
  • 呼び出すクラス:IF定義を実装したクラス。こいつを呼び出す。
  • Proxy:代理呼び出しの実装をするクラス。
  • Handler:呼び出すクラスとプロキシの間を中継するクラス。

では、実際に実装へ

IF定義

public interface Driveintori {
  public String getStoreName();
}

みんな大好き、ドラ鳥をテーマに実装していきます。
ドラ鳥ってなんだ?って思った人は、「ドライブイン鳥」、もしくは、「ゾンビランドサガ ドラ鳥」で検索してね。

呼び出すクラス

public class DriveintoriImpl implements Driveintori {
  @Override
  public String getStoreName() {
    return "ドライブイン鳥 伊万里店";
  }
}

伊万里店として実装。

Proxy & Handler

ここが一番重要。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class DriveintoriProxy {
  private Driveintori store;
  private Object proxy;

  private DriveintoriProxy(Driveintori store) {
    this.store = store;
    this.proxy = Proxy.newProxyInstance(Driveintori.class.getClassLoader(), new Class[] { Driveintori.class },
        new DriveintoriHandler());
  }

  public static Driveintori createProxy(Driveintori store) {
    DriveintoriProxy dp = new DriveintoriProxy(store);
    return Driveintori.class.cast(dp.proxy);
  }

  /**
   * Proxyのメソッド呼び出しハンドラ.
   */
  private class DriveintoriHandler implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      System.out.println("Let's go Doratori!!");
      Object o = method.invoke(store, args);
      System.out.println("comming agein Doratori!");
      Class type = method.getReturnType();
      return type.cast(o);
    }
  }
}

DriveintoriProxyのコンストラクタで、Proxy.newProxyInstanceしているのが実際のプロキシの生成処理。
一番厄介なのは、Objectで返すところ。
本当は、引数で指定したclassの型を返して欲しいのだが、何か理由があってこういう実装になったのだろうか?
汎用性を意識しすぎて、使いにくい気がしないでもない。 使う側としては、DroiveintoriのIF定義で返して欲しいので、createProxy内でキャストして返してる。

Handlerクラスというのは、DriveintoriHandlerが該当する。
実際に、生成したProxyクラスでメソッド呼び出しをすると、DriveintoriHandlerのinvokeを経由して、Driveintoriの実装クラスであるDriveintoriImplが呼び出される。

Mainクラス

public class Main {
  public static void main(String[] args) {
    System.out.println("start");
    Driveintori proxy = DriveintoriProxy.createProxy(new DriveintoriImpl());
    var name = proxy.getStoreName();
    System.out.println("name:" + name);
    System.out.println("end");
  }
}

各クラスを繋ぎ合わせて実験。

実行結果

実際に実行してみる。

start
Let's go Doratori!!
comming agein Doratori!
name:ドライブイン鳥 伊万里店
end

ドラ鳥の伊万里店が表示されました。

所感

やっぱり、クラス多くなるのがネック。
クラス図描いていかないと、実際の業務で利用するってなった時に、結構迷いそう。

気になったのは、実際にリフレクションするのと、Proxy使うのとで、アクセス時間に差がでるのかが気になった。

使われそうな箇所としては、ログ周りかなと思う。
あとは、DB接続とかの前処理・後処理が必要となる箇所。
切替が必要そうな箇所は、だいたい適用できるのではないかと思う。
ただ、本当に適用が必要なのかは、よくよく考える必要があるとは思うが。

参考サイト

Proxy (Java Platform SE 8)

java.lang.reflect.Proxyの使い方(1) - Qiita