Kotlin/JavaScriptを試してみた

Kotolinとは

ググって

KotlinでJavaScriptにトランスコンパイル

スタンドアロンコンパイラを使う方法とGradle等のJVMビルドツールを使う方法がある。実際に開発すると仮定すると、インクリメンタルビルドが可能なGradleを使うことになると思われる。

手順としては、

  1. JREをインストール(JVMAndroid向けの開発も行う場合はJDKが必要だが、JavaScript開発の場合はJREで良い)
  2. Gradleをインストール(当然、Gradle Wrapperを使ってもよい)
  3. プロジェクトのスケルトンを作る(build.gradle)

という感じになる。

Hello World

ブラウザでHello Worldが動くところまでを試してみた。IntelliJ IDEA等のIDEを使えばプロジェクトテンプレートがあるかもしれないが、IDEを使わずにテキストエディタのみでやってみた。

ここに記載する手順は、次の環境で確認した。

  • Windows 10 Creators Update
  • JDK 8
  • Kotlin 1.1.4
  • Gradle 4.1

まずビルドファイルを作る。任意の空ディレクトリ内で次のように build.gradle ファイルを作成する。 ext.kotlin_version の部分は、使いたいKotlinのバージョンを指定する。

group 'org.example'
version '1.0-SNAPSHOT'

buildscript {
    ext.kotlin_version = '1.1.4'
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

apply plugin: 'kotlin2js'

repositories {
    mavenCentral()
}

dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib-js:$kotlin_version"
}

task assembleWeb(type: Sync) {
    configurations.compile.each { File file ->
        from(zipTree(file.absolutePath), {
            includeEmptyDirs = false
            include { fileTreeElement ->
                def path = fileTreeElement.path
                path.endsWith(".js") && (path.startsWith("META-INF/resources/") || 
                    !path.startsWith("META-INF/"))
            }
        })
    }
    from compileKotlin2Js.destinationDir
    into "${projectDir}/web"

    dependsOn classes
}

assemble.dependsOn assembleWeb

次にMainとなるコードを記述する。

fun main(args: Array<String>) {
    println("Hello World")
}

ビルドは gradle build コマンドを実行する。ビルドに成功すると、 web ディレクトリ以下にJavaScriptが生成される。

ブラウザで実行するために、HTMLファイルを作成する。ここでは作業ディレクトリ直下にHTMLファイルを作成する(webディレクトリ配下にHTMLファイルを配置してしまうと、ビルド時に消えてしまう)。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
</head>
<body>
<script type="text/javascript" src="web/kotlin.js"></script>
<script type="text/javascript" src="web/kotlin_main.js"></script>
</body>
</html>

作成したHTMLファイルをブラウザで読み込み、開発者ツールのコンソールを確認すると、 Hello World と表示されているはずである。

試してみた感想

実用レベルだが、自分で積極的に使うことはないかなぁというのが正直な感想。

実用となる根拠としては、

  • DOM操作が可能
  • js()関数で生JavaScriptコードの埋め込みが可能
  • Dynamic型でJavaScript側のオブジェクトが操作可能
  • CommonJS, AMD形式のモジュールとしてビルド可能
  • SourceMapが出力可能
  • dead code elimination (DCE) が使える

というあたり。

一方で積極的に使うことはないなぁという根拠としては、

  • 実行時にKotlin Runtime (kotlin.js) に依存しなければならず、非圧縮状態で1.3MB程度ある

というところが個人的に最大のネックになる。kotlin.jsはminifyすれば数百KB程度になると思われるが、どうせRuntimeに依存しないといけないのであれば、私ならScala.jsを選択する。

Scala.jsの場合、

というメリットがあるため、Kotlinの現状では、チームメンバーがKotlinに精通しまくっているということでもない限りは選ぶことはない。

(蛇足として、そもそもHaxeおじさんなのでScala.jsも積極的には選択しないのだけど、自社の人間はScala.js経験値を積み上げているという…

エンジニアは業務時間外に勉強すべきかの話

他社社長が盛り上がってるみたいなんですが、そこの言説だけが広がっていってもアレだなぁと思ったので、単に自分がやってきた経験値とかを書いてみた。銀の弾丸欲しい。

お前誰よ

  • 零細ITシステム会社経営
    • 従業員5人、エンジニア数だと6人(私自身が含まれる)
    • 会社は設立して4年弱
    • 自社サービスを作っているが、今のところの収益構造は受託・SESが100%
  • 10年ぐらい名古屋でコミュニティ活動に関わってきている(ただし、ここ2年ぐらいは忙しすぎて、ほぼ勉強会に行けてない)

色々やってきて至った基本的な考え方

会社という組織を前提とするのであれば「雇用契約」による利害関係で考えるのがシンプル。

  • 会社は利益を上げたい
  • 利益を上げる手段としては、良いエンジニアが必要(それだけではないが、この話題の本筋ではないので割愛)
  • 良いエンジニアを育むには学習が必要

目的は利益であって、エンジニアの勉強は手段。エンジニアが勉強すべきかみたいな話をしたら、そりゃあ、「エンジニアである以上は生涯学習すべき。ただし、プライベートに勉強を強制させるの(無償労働)はあかん」という一般論にしか終着しない。

「かくあるべき」という話にせず、人事評価(賃金)の話にするのが分かりやすくなる。

  • 業務を遂行する上で必要最低限の教育を、賃金を支払ったうえで行わなくてはならない
    • 賃金が発生する以上、学習成果が上がっているかを人事評価に反映させることは正当となる
  • エンジニア個人の学習成果が収益に直結するのであれば賃金に反映し、新たな事業展開に繋がるような場合はプロジェクトメンバーに抜擢するとか、人事的な面で評価する

これを前提に、会社としてはこういう技術が欲しいとか、こういう人材が不足しているということを伝えて、賃金に反映させる。賃金に繋がるとなれば、学習意欲に繋がって資本主義ヤッターとなる。

当然ならない場合もあるが、賃金に反映されない理由としてはわかりやすい。賃金を払うための収益が改善されないだから、割増する理由がない(これも単純化しすぎたらあかんところではあるけど、割愛)。

強制される勉強の成果は上がらない

サラリーマンプログラマーの時代には、こういうことをやっていたがうまくいかなかった。

terurou.hateblo.jp

会社を作ってから、ある程度の選別をして採用を行ってきているが、すべてのケースにおいて合格点となることはない。そのため、社員教育はやるしかないという意識で取り組んできている。ただ、正直なところ、期待する成果は上がっていない。

振り返ってみて、

  • 本人に興味・素質がある領域や教育を行いやすい領域は伸びるが、そうではないところはほぼ伸びない
  • 期待値が高すぎた

という、当たり前だよねという思いに至っている。

「強制される勉強」というのは「本人に興味がない」とか「学習成果が上がってるように感じない」というところから来るものかと思う。

「本人に興味がない」ケースで、人事評価で釣れないのであれば、これ以上は会社からインセンティブを与える手段はない。ただ、本人に聞いても「やる気はあります!」みたいな答えしか当然出てこないので、外部から「やる気」を評価することはできないように思う。

「学習成果が上がってるように感じない」については、学習カリキュラムやゲーミフィケーションなど、改善余地はあると思う。自社に対してだけ考えると、正直私の力不足(時間不足)感が強いので、やり方を見直さないといけないなぁとは考えている領域にはなっている。 ただ、学習成果の面において、「マニュアル化」「自動化」については、成果が見えやすいと思っている。マニュアルには即効性のある内容が書かれている。自動化は厳密には学習ではないのだけど、そもそも覚えなくてもよい状況にすれば、成果はあがる。

まとめる

割と殺伐としたまとめになるが、雇用契約に基づいて、システマティック・資本主義的に考えるのが素直だと思っている。

端的に「エンジニアは業務時間外でも勉強すべきか」という問いに対して、経営者としての立場の回答は「強制は逆効果になるからNG、インセンティブを明示して社の要望を伝えることは必要」となる。

  • 期待しすぎない
    • ある程度の誘導はできるにしても他人が自分の期待通りに動くわけがないし、銀の弾丸もない
    • 高すぎる期待値は精神衛生上良くない結果になりやすい
  • マニュアル化、自動化等の属人性が排除できる部分を対処していくことで底上げを図る
  • プライベートでの勉強の有無に関係なく、会社の利益につながる人間(端的に業務遂行能力の高い人間)を人事的に評価する

社員のやる気を上げる手段は色々提供することは可能だけど、最終的には、やる気とかいうのは運要素だと考えた方が良い。そういう人が採用できるとも限らないし、興味分野はコロコロ変わるし、ゲームやりたくなったりするし、結婚したりとかで状況は常に変わる、人間だもの。

追記: 「期待しすぎない」は「地に足をつけろ」「着実にやれることをやる」みたいなニュアンス。

おまけ

うちは就業規則GitHubに公開しているので、エンジニアの勉強に関連する制度の現時点の評価を書く。

EmployeeHandbook/005_福利厚生規程.md at master · DenkiYagi/EmployeeHandbook · GitHub

  • 書籍購入補助
    • ほぼ使われていない。私がTwitterや社内チャットで面白そうというワードを見ると、だいたい即購入して社の図書として積読している。社員はそれを借りていくのが普通になっているので、形骸化してしまっている。
  • セミナー補助(勉強会参加補助)
    • 年に数回程度しか使われていない。これは社員が近場の勉強会に行く頻度が高いので、単に費用が発生しない等の理由と思われる。
    • 有償セミナー・トレーニング等については今のところ実績がない。行きたい・行かせたいという具体的なところまで決まりきってないだけ。

その他、社員から機械学習ぶん回したいからサーバーと空調をどうにかしてくれみたいな要望が上がってきたが、マニー・設置スペースの両面で都合がつかなかったので、直近は見送りになっている。

Spring Bootで実装した認証付きWeb APIで異なるAPIのレスポンスが返される問題

発生していた問題

  1. 未ログイン状態で、認証が必要なWebAPI-1にリクエス
    • HTTP 401が返される
  2. ログイン
    • HTTP 200 ログイン成功
    • レスポンスボディなし
  3. WebAPI-2(1とは異なるAPI)を呼び出す
    • WebAPI-1のレスポンスが返される
    • クライアントサイドのリクエストパラメータは、WebAPI-2を指定
    • サーバーログを見る限り、1.でリクエストした際のリクエストパラメータを元に処理が行われ、レスポンスが返されている

Spring Bootのバージョン

  • Spring Boot 1.4.2
  • Spring Security 4.1.3

原因

問題が発生するパターンのSpring Securityの設定は概ねこんな感じ。

public class ApiWebSecurityConfig extends WebSecurityConfigurerAdapter {
    private static final String URL_PATTERN = "xxx";

    @Override
    protected void configure(final HttpSecurity http) throws Exception {
        http.regexMatcher(URL_PATTERN)
                .formLogin()
                .successHandler((req, res, auth) -> res.setStatus(HttpServletResponse.SC_OK))
                .failureHandler((req, res, auth) -> res.setStatus(HttpServletResponse.SC_UNAUTHORIZED))
                .permitAll();

        http.regexMatcher(URL_PATTERN)
                .exceptionHandling()
                .authenticationEntryPoint(new Http401AuthenticationEntryPoint("Bearer error=\"invalid_request\""));

        http.regexMatcher(URL_PATTERN).csrf().disable();
    }
}

また、APIは下記のような実装を行っていた。

  • 単一URLにPOST
  • HTTP Headerによって処理をルーティング

medium.com

この環境下で、前述の再現手順を行うと、以下のようなことが発生していた。

対応策

Spring Securityの設定でリクエストキャッシュを無効にする。

public class ApiWebSecurityConfig extends WebSecurityConfigurerAdapter {
    private static final String URL_PATTERN = "xxx";

    @Override
    protected void configure(final HttpSecurity http) throws Exception {

        http.regexMatcher(URL_PATTERN)
                .requestCache().requestCache(new NullRequestCache());

    }
}

参考URL

http://www.sedooe.com/2016/04/rest-authentication-using-spring-security-and-spring-session/

分散協調サービスのメモ

以前は分散システムの設計をやってたんですが、最近ちょっと離れているので、2017年7月末時点の分散協調サービスについて確認。

自分で使うとしたらこの辺りになるかなぁ。あとは用途要件に合わせて、RabbitMQ + Zabbixみたいな組み合わせと比較していく感じ。

DynamoDBがスケールしねーぞの話に関するメモ

こういう話が流れてきたので元記事を読んでみたのだけど、そもそもDynamoDBの仕組みを把握してなかったので理解ができなかった。ということで、ざっと調べた結果を、自分(Cassandraをがっつり触ってた経験あり)が後から読んでわかればいいや程度のメモに。

DynamoDBとは

DynamoDBのスループット設定の考え方の注意点

このスライドを一回読むとよさそう。

www.slideshare.net

端的には、

f:id:terurou:20170709121701j:plain

100,000RCUを持っていたとしても、パーティションが50個あれば、1パーティションあたりのRCUは2,000となる。

で、パーティションキーを元にアクセスするパーティションを特定する性質上、以下ようなアクセスの偏りが生じるケースがある。

f:id:terurou:20170709122132j:plain

元記事の指摘ポイント

言いたいことはわかるけど、DynamoDBの仕組み(課金の仕組み)を考えると、なかなか難しい問題。分散DBは難しい。

IntelliJ IDEAでHiDPI(Per-monitor DPI)対応

Windows 10 Creators Update(1703) + IntelliJ IDEA 2017.1.2 で確認。これで表示がぼやけなくなった。

idea.propertiesで sun.java2d.uiScale.enabled=true を設定しろということらしい。というか、他にも swing.bufferPerWindow=true みたいなマルチディスプレイに影響しそうな設定が存在するので、 https://github.com/JetBrains/intellij-community/blob/master/bin/idea.properties をそのまま配置した方が無難な気がする。

idea.properties の設定は、IntelliJ IDEAのメニューの Help > Edit Custom Properties... から設定する。

ただ、これだけだとディスプレイ毎フォントサイズの微調整が効かないので、エディタフォントサイズを都度変更する方法で対応する。

IntelliJ IDEA 2017.1 Help :: Zooming in the Editor

XPS15 9560を買った

VAIO Z(2015)を使ってきたが、低電圧版CPUのパワーとメモリ16GBでは開発が厳しくなってきたので、XPS15 9560を買った。

www.dell.com

買ったのは国内モデルのプラチナ(下位モデル:SSD 256GB, MEM 8GB)だが、

  • Core i7 7700HQ以上のCPUで重量・筐体がまともそうな選択肢がこれしかなかった
  • SSDとメモリーは換装する前提
    • 公式の内部コンポーネントの換装マニュアルがあり、ほぼ同筐体の9550の換装報告が多い
    • 筐体設計上はMEM 32GBまでサポートされているが、国内の上位モデルでは16GBまでしか選択できない
    • ついでにSSDも自分で好きなやつにしたい
  • 15インチFull HD
    • 上位モデルだと4Kだが、このディスプレイサイズだと確実に持て余す
    • どうせメインユースでは外部ディスプレイに接続する
    • タッチパネルはあれば便利だが、開発端末にはなくてもいい
  • 上位モデルよりバッテリーセルが小さいが、その分は軽い
    • Let'snoteも持ってるので、モバイル性を気にする場合はそちらを使う
    • そもそもバッテリー容量を気にするユースケース・機種ではない
  • VAIO Zのデジタイザ、年に数回しか使わなかった…

といった選定基準でこれにした。

XPS15 9560のクーポン

旧モデルの9550だった頃を含めて3-4か月はクーポンの監視していたが、XPS15の場合では8,000円/15,000円引きクーポンはカス、15%引きはまずまず、それ以上はたまにしか来ないという感じになっている。

ちなみに自分は期末/年初期の17%引きクーポンが来るのを狙って買ったので、約3万円引きの15万弱で購入している。次の高レートクーポンはおそらく夏のボーナス期に出てくると思われる。

換装したSSDとメモリ

Samsung SM961 512GB

同じSamsungの960 ProやPM961の上位と悩んだが、SM961でも実用上は十分爆速で、MTBFの差ぐらいになるので、価格と相談してSM961で十分と判断した。約3万円。

ちなみに、SamsungSSDの現行モデルについては、 Samsung V-NAND採用NVMe M.2フォームファクタSSDにリテール版 「SSD 960 PRO」と「SSD 960 EVO」が登場 | Ark Tech and Market News Vol.3001037 を参考にした。

PC4-21300 16GB * 2

XPS15 9560標準のメモリモジュールはPC4-19200が搭載されているが、仕様上はPC4-21300まで対応していることがわかったので、これを買った。3万円強。

コンポーネントの換装

分解の仕方は、この動画を見るのが手っ取り早い。

www.youtube.com

  • コンポーネントの換装を行う前に、USBリカバリメディアを作成する
  • 筐体を分解するために、通常のプラス精密ドライバーのほか、星形ドライバー(T-5)が必要になる
  • 爪がかみ合っているが結構弱いので、ツールはなくても分解できる。黒いヒンジ側に指がかかるので、動画の通りこちらから引っぺがせば簡単に底面パネルが外せる

ちなみに底面パネルを外すとこんな感じになっていた。画像がぼけているが、中央部にメモリスロット、その左側にM.2スロットがある。

左下には2.5インチ用のマウンタがあり、ここにもドライブを増設できる。ここは97Whrバッテリーセルの場合は埋まっている。

また、左上にはネットワークカードスロットがあり、これも換装可能となっている。

f:id:terurou:20170422235420j:plain

SSDの認識

BIOSでストレージのモードをRAIDからAHCIにしないとSM961は認識してくれなかった。引っかかったのはこれぐらい。

Windows 10 1703(Creators Update)のインストール

ISOイメージをダウンロードしてきて、RufusでUSBブータブルメディアを作成した。パーティション構成をGPTにしないとブート時に認識してくれなかった。

OSをインストールするとWiFiまでは認識してくれたので、あとはWindows Updateから自動でドライバを適用した。 ただ、これではSM961用のNVMe Driverドライバーが不足するので、これだけは自分でインストールした。

Tools & Software | Download | Samsung Memory & Storage

まとめ

分解するため、保障がアレになるが、22万円弱でこんな感じのスペックになった。わーい。

f:id:terurou:20170423160437p:plain

SM961はシステムドライブとして使ってるので、すこしベンチマークが悪くなっているが、それでも爆速には変わりはない。 f:id:terurou:20170423160447p:plain