javascriptでHello World

新年度が始まって「プログラミングが勉強したい!」て話をよく聞くので、javascriptを書いて実行するまでについて書きます

エディタを用意する

おすすめはVisualStudioCodeかatomです 好きな方を選んでください

Visual Studio Code - Visual Studio

Atom

コードを書く

エディタを起動して以下のコードを入力してください

<!DOCTYPE html>
<h1>sample</h1>
<script>
console.log('Hello world');
</script>

少し解説すると、
このプログラムは、画面にsampleと表示し、コンソールにHello worldと表示するプログラムです
コンソールとは「開発者用の画面」だと思ってください

<script>より前の部分がhtmlを記述する部分です
今回は<h1>sample</h1>と書きましたが、これは「大きな文字でsampleと表示する」というプログラムです

<script>から</script>の部分がjavascriptを記述する部分です
今回はconsole.log('Hello world');と書きましたが、これは「コンソールにHello worldと表示する」というプログラムです

保存する

ファイル名は何でもいいですが、拡張子はhtmlで保存してください
今回であれば、たとえばhello.htmlとか

ブラウザで表示を確認する

ブラウザはとりあえずchromeでお願いします
chromeを開いて、先ほど保存したhtmlファイルをchromeドラッグアンドドロップしてください
「sample」という文字が表示されたと思います

次にコンソールでHello worldが表示されることを確認します

  • ページの適当な場所で右クリックして「検証」をクリック
  • 出てきたウィンドウの「Console」タブをクリック
  • コンソールを開にHello worldが表示され、javascriptが正しく実行されたことを確認する

f:id:naosim:20180426064709p:plain

プログラムを変更してみる

<h1>sample</h1><h1>sample sample</h1>に変更し、 console.log('Hello world');console.log('Hello world, Hello world');に変更し、保存してください
その後ブラウザを更新すると、ページとコンソールに変更が反映されたことが確認できると思います

まとめ

ブラウザでjavascriptを動かすまでの手順を載せました
今回のコードを書いてブラウザで表示するまでの流れを反復練習して、何も見なくてもできるレベルになってほしいと思います

Springのcomponentをライブラリとして公開する方法

最近ライブラリ作りをたくさんやってます
そこで作りたくなるのがcomponentのライブラリ
今日はその作り方を紹介します
以下、gradleで作ることを前提で話します

辛み:普通に作ると問題がサイレントに起きる

ライブラリを作る上で少し注意すべきことがあるのでそれを書きます
componentライブラリを作るには、普通に考えたら、gradle.buildのdependeciesにcompile 'spring'的なことを書いて作ればイイと思うかもしれませんが、それだとspringのバージョン周りで問題が起きる可能性があります
例えばライブラリのspringのバージョンがv5で、ライブラリを使う側でv4を使っていたら最終的にspringのバージョンは何になるでしょう?
gradleはdependeciesに同じライブラリが複数定義された場合、バージョンが新しい方が採用されます
なのでこの例ではv5になります
つまりライブラリ側が安易に最新バージョンを指定すると、使う側のバージョンがサイレントに上がってしまいます
たぶん不具合が起きない限り、上がったことに気づかない...
怖いですね...

参考: Gradleで陥りやすい問題点の解決策TIPS集
http://kkoudev.github.io/blog/2014/03/30/gradle-tips/

なのでライブラリとしてはバージョンに対して控えめな感じにしておかないといけないです

dependenciesをcompileOnlyにする

解決策は簡単で、依存をcompileOnlyで指定します
これでコンパイル時だけspringのv5に依存して、ライブラリを使う側は依存が見えないようになります
仮にライブラリ側で最新バージョンでないと使えないような機能を使ってたらマズいですが、ただのcomponentを作りたいだけならまぁ問題はおきません

componentライブラリを作る

上記のことを気にしつつ、ライブラリを作ります
とりあえずgradle.buildはこんな感じ
group名やmavenの設定は適当に変えてください

group 'com.naosim'
version '1.0-SNAPSHOT'

apply plugin: 'groovy'
apply plugin: 'java'
apply plugin: 'maven' //ライブラリとして公開するため

sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {
    // ライブラリを使う側のバージョンに合わせるためにcompileOnlyにする
    compileOnly group: 'org.springframework', name: 'spring-context', version: '5.0.5.RELEASE'
    compileOnly group: 'org.projectlombok', name: 'lombok', version: '1.16.20'
}

// maven用の設定
uploadArchives {
    repositories {
        mavenDeployer {
            repository url: "file://${rootDir}/docs"
            pom.version = '0.1.0'
            pom.groupId = 'com.naosim'
            pom.artifactId = 'componentlib'
        }
    }
}

作りたいライブラリ

package com.naosim.componentlib;

import org.springframework.stereotype.Component;

@Component
public class SampleComponent {
    public String hello() {
        return "hello";
    }
}

これでライブラリは完成です

テストする

ライブラリができたので、次はテスト
gradleにdependenciesにテスト用のライブラリを追加します

dependencies {
    // ライブラリを使う側のバージョンに合わせるためにcompileOnlyにする
    compileOnly group: 'org.springframework', name: 'spring-context', version: '5.0.5.RELEASE'
    compileOnly group: 'org.projectlombok', name: 'lombok', version: '1.16.20'

    // test
    testCompile 'org.codehaus.groovy:groovy-all:2.3.11'
    testCompile group: 'junit', name: 'junit', version: '4.12'
    testCompile group: 'org.spockframework', name: 'spock-core', version: '1.1-groovy-2.4'
    testCompile group: 'org.spockframework', name: 'spock-spring', version: '1.1-groovy-2.4'
    // spring
    testCompile group: 'org.springframework', name: 'spring-context', version: '5.0.5.RELEASE'
    testCompile("org.springframework.boot:spring-boot-starter-web:2.0.1.RELEASE")
    testCompile group: 'org.springframework.boot', name: 'spring-boot-starter-test', version: '2.0.0.RELEASE'

    testCompileOnly group: 'org.projectlombok', name: 'lombok', version: '1.16.20'
}

次はテストコード側
springを立ち上げるにはApplicationクラスが必要になりますが、それをテスト側に書きます
/src/test/..../Application.java

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

最後にテストコード

@Unroll
@SpringBootTest
@TestConfiguration
class SampleComponentSpec extends Specification {
    @Autowired
    SampleComponent sut;

    def "test"() {
        expect:
        sut.hello() == "hello"
    }

}

まとめ

componentライブラリの作り方を紹介しました
コード全体をgithubに置いておきます
github.com

仕様書の表をそのまま書くenumテーブルパタン

最近のenumはただ値を列挙するだけでなく、フィールドやメソッドを持てることが多いです
そうゆう機能を最大限にいかす方法としてenumテーブルパタンを紹介します

たとえば各商品の原価に対して値段を決める仕様があるとします 仕様書はこんな感じ

商品と値段の仕様

商品ID 商品名 原価率 課税
P001 りんご 30% 課税
P002 みかん 50% 課税
P003 笑顔 100% 非課税

それぞれの商品について原価から値段を算出するプログラムを書きます

if文地獄な書き方

int createPrice(String productId, int cost) {
  if(productId.equals("P001")) {
    return ((int)(cost * 100 / 30)) * 108 / 100;
  }
  if(productId.equals("P002")) {
    return ((int)(cost * 100 / 50)) * 108 / 100;
  }
  if(productId.equals("P003")) {
    return cost
  }
  throw new RuntimeException(“product not found”);
}

商品が増えたら辛いですね
仕様書通りに実装できているかチェックするのも大変そう

enumテーブルパタンで書く

enumを使って仕様書をできるだけそのまま再現します

enum Product {
    apple("P001", "りんご", 原価率30per, 課税),
    orange("P002", "オレンジ", 原価率50per, 課税),
    smile("P003", "スマイル", 原価率100per, 非課税);

    private final String productId;
    private final String name;
    private final CostRate costRate;
    private final Tax tax;

    Product(String productId, String name, CostRate costRate, Tax tax) {
        this.productId = productId;
        this.name = name;
        this.costRate = costRate;
        this.tax = tax;
    }

    int price(int cost) {
        return Stream.of(cost)
                .map(costRate::calc)
                .map(tax::calc)
                .findFirst()
                .get();
    }
}

enum CostRate {
    原価率30per(30),
    原価率50per(50),
    原価率100per(100);
    private final int p;

    CostRate(int p) {
        this.p = p;
    }

    int calc(int v) {
        return v * 100 / p;
    }
}

enum Tax {
    課税(108),
    非課税(100);
    private final int p;
    Tax(int p) {
        this.p = p;
    }
    int calc(int v) {
        return v * p / 100;
    }
}

仕様書の表の見た目をそのままにProductクラスを作れました
これならコードレビューも楽だし、ジェネレータを作って仕様書から直接enumを生成することもできそうです

まとめ

enumの特性を活用したenumテーブルパタンを使うと、仕様書の表をそのままコードにできる

github projectsからバーンダウンチャートを作る 調査編

自力でバーンダウンチャートが作りたいなと思ってAPI仕様書を読んだのでメモ
GitHub API v3 | GitHub Developer Guide

認証

方法はBASIC認証と認証トークンの2種類ある

BASIC認証

もはやcurlの使い方だけどとりあえずメモ

curl -u "username" https://api.github.com

これを叩くとパスワードを聞かれるので入力すると認証完了

usernameのところにパスワードも書いて

curl -u "username:password" https://api.github.com

にするとパスワード入力をスキップできる
ただしパスワードが丸見えなのでオススメはしない

認証トーク

認証トークンの載せ方は2つある

認証トークンをヘッダに載せる

curl -H "Authorization: token OAUTH-TOKEN" https://api.github.com

認証トークンをqueryに載せる

curl https://api.github.com/?access_token=OAUTH-TOKEN

Project(カンバン)の情報を取得する

ここからが本題
以下のサンプルでは認証はBASIC認証で記します

事前準備

リポジトリ単位で取得するのリポジトリオーナー名リポジトリ名を調べておいてください

リポジトリ内のプロジェクト一覧を取得する

curl -u "username" -H 'Accept:application/vnd.github.inertia-preview+json' https://api.github.com/repos/:owner/:repo/projects

:owner:repoに先ほど調べた値を入れる
これでリポジトリ内のプロジェクト一覧が取れるので、見たいプロジェクトIDをメモる

プロジェクトのカラムを取得する

curl -u "username" -H 'Accept:application/vnd.github.inertia-preview+json' https://api.github.com/projects/:projectid/columns

カラム単位でカード一覧を取得する

curl -u "username" -H 'Accept:application/vnd.github.inertia-preview+json' https://api.github.com/projects/columns/:columnid/cards

これでバーンダウンチャートに必要な情報がとれた
情報を定期的に取得して集計すればバーンダウンチャートが作れる

スクロールするとメニューがでるやつ作った

最近のサイトでよく見るやつ
ライブラリが欲しかったけど、検索ワードがわからなかったり、jquery依存だったりでイイのが当たらなかったので自作しました

コード

ある要素が画面外に出たら通知するスクリプトです

使い方と動作

See the Pen menu by なおしむ (@naosim) on CodePen.

registerに監視対象のselectorを渡します
監視対象が画面外にでるとコールバックが来るので、それに応じてメニューの表示/非表示を切り替えます

これがあるだけで一気に今風のサイトに見えるから不思議w

IF仕様書にない値を受け取ったときに耐えるデザインパターン

外部とシステム連携する場合、必ずIF仕様書を作成します
そこでよくあるのがenum
例えばアンパンマンに登場するパンだったらIF仕様書には

パン: アンパン | 食パン | カレーパン

と必ず書いてある
ただ先方から急にIF仕様書に無い値が連携されてくることがあります
たとえばメロンパンとか

聞いてないし!!

この場合、通常は受け取ったタイミングでバリデーションエラーにしますが、いろいろな事情により一旦これを受け取った方が良いこともあります
今日はそうゆうときに私がやってるデザインパタンを紹介します

def-undefパターン

パターン名は今決めましたw
もっといい名前があったら教えてください
先ほどのパンのデータをdefinedとundefinedというクラスに分けて管理します
definedの方はIF仕様書通りのenumで、undefinedの方はStringを保持するバリューオブジェクトです
kotlinで書くとこんな感じ

enum class PanDefined {
    あんぱん, 食パン, カレーパン
}

data class PanUndefined(val value: String)

data class Pan(private val obj: Either<PanUndefined, PanDefined>) {
    val value: String
        get() =  obj.fold({ it.value }, { it.name })
}

使う側はPanのみを使います
保持しているdefinedやundefinedのクラスは意識しません

何が良いのか

IF仕様外のデータを全てエラーにしてしまうと、処理がエラーになった際に、状況確認のために参照画面で表示したら参照画面もエラーになってしまいます
(この時は結局サーバに入って生データを直接見るはめに... )
つまりここでの要件は「処理上は落ちるべきだが、参照の時はそのまま出してほしい」なのです
そうゆう時に上記のようなデザインにしておくとエラーにするかどうかをAPI単位で変更できるので、柔軟に対応できます

まとめ

def-undefパターンを使うとenumに知らない値が来ても柔軟に対応できる
IF仕様書が信用ならない相手と連携する場合は有効ですw