読者です 読者をやめる 読者になる 読者になる

ただのブログです

技術的な物とかを主に。主にWeb系がメイン。いつか、職業エンジニアになりたい。

ScalaでJVMの終了時のフック処理を行う

scala

ただのメモ

java.lang.Runtimeを使うとメソッド一個で終わるような処理でも

new Thread {
  override def run() {
  }
}

しなきゃいけなくて、わりとしんどい。あとで読んだ時に。

Playを真似て書いてたので https://github.com/playframework/playframework/blob/2.2.x/framework/src/play/src/main/scala/play/core/server/NettyServer.scala#L233 と使われてるし、それ以外の方法ないのかなぁと思ってたら

というのを教えてもらってのでこれ使いましょう。

https://github.com/scala/scala/blob/v2.10.3/src/library/scala/sys/package.scala#L63-L75

sys.addShutdownHook(dispose)

coffee scriptでrange([z...y])を使う際の注意

jsのコードをcoffeeで書き直してた際に見つけた。

やる前からだいたいわかってたんだけどjavascriptに無限リストはないので

Array::zip = (arr) ->
  base = if (this.length < arr.length) then this else arr
  [0...base.length].map((i) ->
    [this[i], arr[i]]
  , this)

と、書くと

Array.prototype.zip = function(arr) {
  var base, _i, _ref, _results;
  base = this.length < arr.length ? this : arr;
  return (function() {
    _results = [];
    for (var _i = 0, _ref = base.length; 0 <= _ref ? _i < _ref : _i > _ref; 0 <= _ref ? _i++ : _i--){ _results.push(_i); }
    return _results;
  }).apply(this).map(function(i) {
    return [this[i], arr[i]];
  }, this);
};

と変換されて、きっと巨大な配列だと爆死する

LESSについて布教用の資料書いた

LESS

cssを使えなんて縛りがあるわけでもないのにcssでかかれると困るのです。
cssなんてメンテしたくない。

そう、そこで何番煎じか分からないけどlessの布教用の資料の下書き書いた。
あんまためになる情報書いてない。布教用。

scssよりもless派です。
既存のcssをより扱いやすいからlessです。
Play frameworkだってless推奨なんです。

明日から会社でザビエルのごとくLESSを布教してきます。

  1. 事前準備
  2. モジュールのインストール(新規プロジェクト)
  3. モジュールのインストール(既存プロジェクト)
  4. 初めてのLESS
  5. 変数を使う
  6. 自動でcssに変換する
  7. 他のクラスを拡張したクラスを定義する
  8. 他のクラスを拡張したクラスを定義する②
  9. 関数(計算式)を使う
  10. LESSのカッコイイ使い方(!?)

事前準備

Node.js、npmのインストール

Windows

Node.js へ行き、INSTALLからダウンロードされたファイルに従いインストールを完了して下さい。

Mac( Home brewは入っている前提 )

brew install node

次にコンソールを開いてください。(windowsならWindowsキー+Rを押して、cmdと入力します。Macならアプリケーション→ユーティリティからターミナルをクリックしてください) 今回作成するサイトのディレクトリに移動します。

ex)
# windows
cd c:\workspace\html-edu-1
# mac
cd /home/user/workspace/html-edu-1

以降の作業は全てこのディレクトリで行います。(Macであればrootとして実行するか、全てのコマンドの先頭にsudoとつけてください)

grunt-cliのインストール

コンソールで下記のコマンドを実行してください。

npm install -g grunt-cli

必要モジュールのインストール(新規プロジェクトの場合)

ルートディレクトリにpackage.jsonというファイルを作成します。
ファイルの内容は下記で行きましょう。

{
  "name": "html-edu-1",
  "version": "0.0.0"
}

※ npm initというコマンドして、package.jsonを生成する方法もあります。

まず、gruntをインストールします。
このgruntというモジュールは色々便利にしてくれる魔法のモジュールです。

npm install grunt --save-dev

--save-devというのを忘れずに書いてください。
この--save-devを書いて実行すると、先ほどのpackage.jsonにインストールしたモジュールが自動で追記されます。 ためにし、上記のコマンドを実行してみた後にpackage.jsonを開いてみてください。
"devDependencies": {
"grunt": "~0.4.1"
}
のような記載した覚えのないコードが追加されていると思います。

less化するにあたって、lessをcssに変換するモジュールをインストールします。

sudo npm install grunt-contrib-less --save-dev

自動でlessをcssに変更するために、watchモジュールをインストールします。

sudo npm install grunt-contrib-watch --save-dev

Gruntfileの作成

ルートディレクトリにGruntfile.coffeeというファイルを作成します。
このGruntfileに、に色々なツールを実行するための手順を記載していきます。

まずは、下記の内容を記入していきましょう。

# このメソッドの中に全て定義していきます。
module.exports = (grunt) ->
  # 先ほどインストールしたモジュールをロードするようにします
  grunt.loadNpmTasks 'grunt-contrib-less'
  grunt.loadNpmTasks 'grunt-contrib-watch'

  # initConfig
  grunt.initConfig
    # lessの設定を行います
    less:
      compile: 
        files: [
          "css/index.css":"less/index.less"   # less/index.lessファイルを、css/index.cssに変換します
        ]
    # watchの設定を行います
    watch:
      less:
        files: "less/**/*.less"   # lessディレクトリ以下の拡張子がlessのファイルが更新されたのを感知したら
        tasks: ["build"]          # 後述のbuildコマンドを実行します
  
  # end initConfig


  grunt.registerTask "run", ["watch"] # run というコマンドを実行すると watchに設定された動作を行います。
  grunt.registerTask "build", ["less"] # build というコマンドを実行すると lessをcssに変換します。

コンソールで

grunt build

と入力してみてください。

何も間違っていなければ、

Done, without errors

と表示されるはずです。

必要モジュールのインストール(既存プロジェクトの場合)

既に誰かが上記の作業をしている場合、package.jsonやGruntfile.coffeeというファイルは既に存在しているはずです。

その場合は、コンソールで下記のコマンドを入力するだけで作業環境が構築できます。

npm install

初めてのLESS

LESSはCSSへの後方互換を持っています。
そのため、だたのCSSをそのままLESSファイルとして扱うことが出来ます。
試しに、lessフォルダを作成し、
css/index.css

less/index.less
にリネームしてしましょう。

最初の構築で、

    less:
      compile: 
        files: [
          "css/index.css":"less/index.less"   # less/index.lessファイルを、css/index.cssに変換します
        ]

と既に記載されているため、ただリネームするだけでOKです。
もし他のlessファイルもcssに変換したければ

    less:
      compile: 
        files: [
          "css/index.css":"less/index.less"   # less/index.lessファイルを、css/index.cssに変換します
          "css/style.css":"less/style.less"   # 変換するlessを追加する
        ]

と追記して下さい。

ただ、lessに名前変更しただけではもちろんレイアウトは崩れてしまいます。

<link href="css/index.css" rel="stylesheet" type="text/css" media="all" />

そのため、このリンクを切らないようにindex.cssを作成しましょう。

コンソールで下記のコマンドを実行してください。

grunt build

出力結果に、Done without Errorsと出れば成功です。
もし、cssのシンタックスエラー等があればその情報がコンソールに表示されるので該当箇所を修正して下さい。

成功した場合、css/index.cssが作成され、ページのレイアウトも元に戻っていると思います。

LESSはただのCSSを書いても問題ないのです!

変数を使う

通常のcssでは不便な問題が多々あります。
例えば、同じ幅を表現する場合我々は下記のようなコードを書かなければなりません。

.main_section {
  clear:both;
  margin-bottom:50px;
}
.sub_section {
  background:url(../img/bg-section.gif) center repeat-y;
  margin-bottom:50px;
  width:710px;
}

ここでのmargin-bottomに注目してみてみましょう。
この50pxという値は、 .main_sectionと.sub_sectionそれぞれのクラスで同じ値を使用しなければなりません。
もし50pxではなく、48pxにしたい場合、2か所を修正しなければなりません。
この事は作業工数を増加させる他、修正漏れがあった場合にレイアウト崩れが起こってしまう不具合の原因となり得ます。

// 変数宣言
@contents-margin-bottom: 50px;

.main_section {
  clear:both;
  margin-bottom: @contents-margin-bottom;
}

.sub_section {
  background:url(../img/bg-section.gif) center repeat-y;
  margin-bottom: @contents-margin-bottom;
  width:710px;
}

このlessからcssを再度生成するために再度

grunt build

を実行しましょう。

生成されたindex.cssを見てみれば

.main_section {
  clear:both;
  margin-bottom:50px;
}
.sub_section {
  background:url(../img/bg-section.gif) center repeat-y;
  margin-bottom:50px;
  width:710px;
}

となっているのが分かると思います。
こうやって設定値としてもっておけば、幅の調整等はもちろん少ない工数、全箇所を一度に修正ができるようになりますよね?

LESSはこういったCSSの問題を解決してくれる言語なのです!

自動でcssに変換する

先ほどの例では二度

grunt build

というコマンドを打つ必要がありました。
修正するたびに毎回このコマンドを打っていたのでは、非常に面倒です。

そこで、今度は

grunt run

と実行してみましょう。

Runnning "watch" task

と画面に出力されればOKです。

この状態で試しに先ほどの

@contents-margin-bottom: 50px;

@contents-margin-bottom: 80px;

と変更して保存してみましょう。

保存した瞬間に、何やら色々と出力されたと思います。 これは最初にインストールしたgrunt-contrib-watchモジュールを利用して、保存した瞬間にlessをcssに変換ということをやってくれます。

作業の初めに

grunt run

と実行してしまえば、lessからcssの変換作業等いちいち手作業でやらずとも保存した瞬間にcssが作られるようになるのです!

他のクラスを拡張したクラスを定義する

LESSではMixinsと呼ばれる機構を提供しています。
この機構は何かというと、他のクラスを混ぜ合わせたクラスを定義できるという機構です。
説明ではよく分からないので試しに定義してみましょう。

.sub_section:after {
  content: "."; display: block; visibility: hidden; height: 0.1px; font-size: 0.1em; line-height: 0; clear: both;
}

.banner_section ul:after {
  content: "."; display: block; visibility: hidden; height: 0.1px; font-size: 0.1em; line-height: 0; clear: both;
}

この2つのcssはそれぞれ同じスタイルを、違う要素に適用しようとしています。
このスタイルは変更される頻度は低いですが、もし新しいIEがでて、新型IEのバグでこのスタイルでは崩れてしまう。といった状況を考えてみましょう。(無いとは思いますが)
全てのcssを全部変更するのは非常に工数がかかります。
そこで、先にクリアフィックスのクラスを作りそれを利用してみましょう。

.clearfix {
  content: "."; display: block; visibility: hidden; height: 0.1px; font-size: 0.1em; line-height: 0; clear: both;
}
.sub_section:after {
  .clearfix;
}
.banner_section ul:after {
  .clearfix;
}

通常のプロパティの書き方と異なり、同じスタイルを適用するcssのクラス名を記載します。

このように、同じcssを利用したい場合は、コピー&ペーストせずとも簡単に使えますし、もし修正が必要になった場合も.clearfixだけを修正すれば全て修正されるのです!

他のクラスを拡張したクラスを定義する②

先ほどのMixinsという機構はもっと応用的な機能もサポートしています。 例えばborder-radiusを指定する例を見てみましょう。

.border-radius {
  -webkit-border-radius: 5px;
  -moz-border-radius: 5px;
  -ms-border-radius: 5px;
  -o-border-radius: 5px;
  border-radius: 5px;
}

各ブラウザベンダーの独自実装に対応するスタイルを記入しなければなりません。
先ほどのMixinsの例の書き方では、5px以外のスタイルを再利用することができません。
そこで値を変更可能なCSSとして定義してみます。

.border-radius(@radius: 5px) {
  -webkit-border-radius: @radius;
  -moz-border-radius: @radius;
  -ms-border-radius: @radius;
  -o-border-radius: @radius;
  border-radius: @radius;
}

このように書きます。
(変数名:初期値)または(変数名)という宣言が可能です。
このように宣言されたスタイルは

.foo {
  .rounded-corners(10px);
}
.bar {
  .rounded-corners;
  // .rounded-corners(5px);と同じ
}

このように利用可能になり、面倒なブラウザごとの指定方法を一度にまとめて定義できたり、似たようなスタイルをまとめて定義・変更するのに役に立ちます!

関数(計算式を使う)

cssでさらに面倒なことはpxを計算を行わなければならないときです。

@foo-height:45px;
@bar-margin-top:50px; // fooのheightより5px大きくしたい
.foo {
  height:@foo-height;
}
.bar {
  margin-top:@bar-margin-top; 
}

こういった場合

@foo-height:45px;
.foo {
  height:@foo-height;
}
.bar {
  margin-bottom:@foo-height + 5; // heightより5px空けたい
}

このように計算式を利用してスタイルを定義してやることで、毎回毎回px計算する必要を無くすことができます!

LESSのカッコイイ使い方(!?)

かっこいいというほどではないですが、LESSの運用についてプラクティス。

共通lessを分離して管理

  • variables.less
  • utility.less

と言ったファイルを定義します。

variables.lessには全てのレギュレーション定義を記入します。

@red:#f58787;
@green:#87f587;
@blue:#8787f5;
@white:#f5f5f5;
@black:#303030;

このように利用することでカラーデザインの微調整等を一括で行えるようにします。

@nav-height:42px;
@article-width:710px;
@article-padding-rl:10px;
@section-width: @article-width / 2 - @article-padding-rl;

大域レイアウト等もこのように全て一か所で宣言します。

utilities.lessには汎用的なlessを記載すると良いでしょう

.border-radius(@radius) {
  -webkit-border-radius: @radius;
  -moz-border-radius: @radius;
  -ms-border-radius: @radius;
  -o-border-radius: @radius;
  border-radius: @radius;
}

.clearfix {
  content: "."; display: block; visibility: hidden; height: 0.1px; font-size: 0.1em; line-height: 0; clear: both;
}

このようにページデザインとは本来関係ないスタイルを別途定義しておけば、他のウェブページでも再利用できます。

あとはこれらを実際のlessでimportするだけです!

@import "variables.less";
@import "utilities.less";

各パーツを分離して管理

場合によってはcssのファイルが数百行~数千行に及ぶようなデザインが必要な場合があります。 そんな時にはレイアウトファイルの分離を図ってみて下さい。

  • navbar.less
  • footer.less
  • sidebar.less
  • article.less
  • article-thema-green.less
  • article-thema-red.less
  • article-thema-blue.less

パーツごとにlessファイルを分け、 style.lessで

@import "navbar.less;
@import "footer.less;
@import "sidebar.less;
@import "article.less;
@import "article-thema-green.less;
@import "article-thema-red.less;
@import "article-thema-blue.less";

とだけします。

そうすれば、 .article .thema-green .article .thema-red .article .thema-blue 等のスタイルの行を探さなくて済むようになりますし、バージョン管理のコミットログでどのパーツの部分がスタイル変更されたのかが分かりやすくなります。

色をレコメンドする(?)の作り始めました

ちらっと色選びって結構難しいよねーという話になったので、何処でも手軽にいい感じの色をチョイスしたり、リコメンドしてくれるものを作ろうかと思ってます。

Color Recomender

IEは多分動きません。ChromeFireFoxあたりでどうぞ。
デザイン系のツール名はずなのにデザインェ…
まだプロトタイプ段階なのででUI糞。UX糞。多分バグある。コードは糞。使いにくい。と、いろいろとアレな感じですが、どんな色選べばいいかな?って時に使えるようにするつもりです。

既存のサービスだと「既存のセットから選んでいく」とか「ちょっと高機能過ぎてぱぱっとやるのには…」的な物が多いと感じていて、なんか使うことはあるんだけどそんな常用していないなぁと思ったので自分で作ることにしました。

大体の想定ユースケース自体は

  • 細かいところは人間の感覚でやるけど、大枠は適当に生成したい
  • この色使いたい!と思ったときの、組み合わせのとりあえずカラーパレットパターンが欲しい
  • この色にあわせるならどの辺りの色試してみようかな?と思ったときの大体の指標が欲しい

と、アイデアを出すためのベースを作るって意味合いが大きいです。

実際にどんなのがあれば便利だろうとか考えるより先にとりあえずテンプレ作ってみるか、という感じでプロトタイプ書き始めたので、何があったら嬉しいかはこれから考えます←
でも、ここまでで2、3時間くらいで作れたので要望があればガンガン作れるはず…多分。

夢としては
「派手なんだけど優しい色」とか
「危ない感じの赤」とか
「ココロが落ち着く青」
みたいな日本語入力をして、大体のいい感じの色を作り上げるところまでやれたらなぁと思います(モチベーションが続けば…)

社長さんとかに「もっとこう、バーンって感じの色にしてよ!」といわれたときに、その言葉そのまま入力したらバーンとした感じの色作ってくれる的なw

本当にあった怖いコード入賞しました!

最近ずっと社畜しすぎていて全然見れてなかったのですが、

http://codeiq.hatenablog.com/entry/2013/09/04/165809

入賞させて頂きました。ありがとうございます!(?)

会社で転職してきた人とお話すると

旧システム(汎用機・C)をJavaでリプレースした際に、エンジニアのレベルがついてこなかったのと古い設計を引きずったせいで「当初は頑張ったが最終的に全てstatic class。全てpublic staticで作られた」

とか

仕様変更に次ぐ仕様変更とリタイアする人が続出したプロジェクトで死にコードが大量に残っていて訳が分からない。挙句の果てには「いるはずがない…呼ばれることのないはずのコードがバグを引き起こしていた」(※修正とリリース漏れててcronかなんかで稀に旧バージョンが呼ばれていただけらしいです)

とか

全ての機能で使用されている謎のグローバル変数が複数。実行するまでそこに何が入っているか分からない…

みたいな悲惨な話は結構聞いていたので、ちょっと驚きです。

せっかくなので、ヤバイ部分を補足すると

  • ラムダ等は暗黙的に禁止(わからない人がいるから)
  • 高階関数は暗黙的に禁止(値以外を投げるとわからない人がいるから)
  • テンプレートメソッドとかストラテジーとかその辺は、基底クラスごとコピペされる(何故か分からない…)
  • バリデーションメソッドとか作るといつの間にかそこに永続化処理はいってたり、トランザクションかけて永続化処理をまとめてたらいつの間にかそこにバリデーションいたり(たぶん手続き的に通る場所なら何処でもよくて、最初に見つけた場所にコード書いていたみたい)
  • 「クロージャーで閉じ込めたら?」と言ったら「クロージャーってたしか言語ですよね?」と言われた(確かにClozureは言語だけど)
  • リファクタリングはあまりやってはいけない。(手動マージでリリースなので差分が多いと…?)
  • IEって何?って素人ってレベルじゃない人が開発に参加し、実装を始める。(四苦八苦して恐ろしいコードを書きまくるが、最終的に納期があるので直しきれずにリリース)

等など、ヤバイコードが出来る背景にはそういう事情がありました。

怖いコードはそういったプロジェクトの背景が一番怖さを増幅していたと思います。

もし、そういったプロジェクトに参加されている方がいましたら、今すぐ辞退することをお勧めします。 家庭の事情で辞退できない方はレガシーコード改善ガイドの24章には幾度となく励まされましたので、1日3回朝昼晩食後に読むことをお勧めします。

javascriptの俺俺ライブラリ作り始めました

javascript

いつまで続くか分からないけど、作ってみました。

javascriptx

名前は面倒だったから適当に付けただけです。
MonadとかFunctorとかが沢山あるあのライブラリとは関係ありません。

主にはprototype周りを中心に拡張していって行くつもりです。
その他基底になるオブジェクトも多分書いていきます。

サンプル

"0123".toInt()      // 123
"0123".toIntOrZero() // 123
"NaN".toIntOrZero() // 0

"{0} is {1}".format("cat", "cut")    // cat is cute
"0123.45".toHalfNumber()     // 123.45 
"qwrty".toHalfAlphabet()     // qwrty
var f = (function(a,b,c,d){
    return a + b + c + d;
}).curried(); // f(1)(2)(3)(4);

(new Date(2013, 0, 1)).dateDiff("month", new Date(2014, 2, 1)); // 12

と、全角文字を半角にしてくれる入力補助に使うようなものから、日付計算メソッドだったりカリー化とか、まぁなんか統一感と対称性や網羅性がない感じです。

一応

"test Function.prototype.andThen" : function() {
    var f = function(a) { return a + 10; };
    var g = function(a) { return a * 2; };
    var target = f.andThen(g);
    var actual = target(1);
    assertEquals(22, actual);
}

みたいな感じでテストコードは一応書いてあります。jsTestDriverです。


作り始めのきっかけは、jQueryだけだとDOM周りはいいんだけど計算とかなんかもろもろやるのにちょっと痒いところに手が届かないんだよなぁ。
かといって色々乱立しすぎてて、。

と思いちょこちょこ書いてたのが元です。

加毒性が高いコードとか、とりあえずやってみたかっただけー的なコードや、「ナンデそんな書き方してんの?(#^ω^)」的な物はありますが、まぁいつか直そうかなぁと。

必要に応じて適当に書いたコードを組み込んでいく形で修正しようと思いますが、何が問題だったのかよく考えずに見つけた物から書いていってるので、もし使ってくれる方がいらっしゃいましたら、言っていただければ実装したいと思います。