javascriptでHello World
新年度が始まって「プログラミングが勉強したい!」て話をよく聞くので、javascriptを書いて実行するまでについて書きます
エディタを用意する
おすすめはVisualStudioCodeかatomです 好きな方を選んでください
Visual Studio Code - Visual Studio
コードを書く
エディタを起動して以下のコードを入力してください
<!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が正しく実行されたことを確認する
プログラムを変更してみる
<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
mavenリポジトリにローカルディレクトリを指定する
repositories { mavenCentral() // maven { url 'file://path/to/maven/dir' } }
しらなかったー。
仕様書の表をそのまま書く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を生成することもできそうです
まとめ
github projectsからバーンダウンチャートを作る 調査編
自力でバーンダウンチャートが作りたいなと思ってAPI仕様書を読んだのでメモ
GitHub API v3 | GitHub Developer Guide
認証
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
これでバーンダウンチャートに必要な情報がとれた
情報を定期的に取得して集計すればバーンダウンチャートが作れる
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