プログラマメモ2 - programmer no memo2

目次

java7でのwebstart実行のためのマニフェストとjnlpの記述について 2014/02/24

java7です。webstartです。

いろいろセキュリティ要件をクリアしないと配布できなくなっています。

いまのところAntでjarを作成しているのですが、どうもマニフェストに書きこみが必要なようです。
なくても起動はできたのですが、とはいっても、動かしたい端末での設定はしました。
マニフェストに必要な文言がないと、コンソール上でワーニングはでます。

 マニフェストに書き込むのに使ったのは以下の命令
 参考
             <manifest>
                <attribute name="Permissions" value="all-permissions" />
                <attribute name="Codebase" value="http://deiji.jp/tools/t/t023/" />
                <attribute name="Application-Name" value="まとめて変換1号" />
            </manifest>
 all-permissionsにしたい理由は、ファイルをドロップして、読み取る機能を実現したいからです。
 これでjarにマニフェストを追加して、あとjnlpに
追加
<security>
   <all-permissions/>
</security>

 JNLPにこれを書かないと最後ではじかれます。

 証明書はオレオレで行っています。

 とりあえず、これで動かしてファイルをドロップして読み込めたのまでは確認できました。



文字数が多いもの順に並ばせる Comparatorを使って - java 2014/02/22
2014/02/24

文字数が多いもの順に並ばせる Comparatorを使ってソートします。

2014/02/24 追記 同じ文字数の場合の判定してなかった.....

package collections; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; public class TestSort { public static void main(String[] args) { Comparator<String> c = new Comparator<String>() { @Override public int compare(String o1, String o2) { int len1 = o1.length(); int len2 = o2.length(); if (len1 == len2){      return o1.compareTo(o2); } return (len1 > len2) ? -1:1; } }; String[] ss = {"いい", "いいい","い","あ", "ああ", "あああ"}; List<String> list = Arrays.asList(ss); Collections.sort(list, c); // 結果 // [いいい, あああ, いい, ああ, い, あ] System.out.println(list); } }


えくせるでてすとでーたをつくるその1 2014/02/22

プロジェクトごとというか、会社さんというか、開発時のテストデータの作り方はいろいろありますね。

プログラムの仕様や、組んだSQL(これから組むであろう)の特性などから、テストケースおこして、それにあわせて、テストデータをつくるというのが一般的な流れかなとは思います。


エクセルで組んで出力するところもあれば、直接SQLをテキストファイルのSQLを編集しているところや、あとは、XMLや、CSV形式や、規模ややりやすさや修練度や、いろいろな兼ね合いがあります。

組あわせ数が多い場合、テストデータを検討する際にはやはりエクセル便利だなと。

それで、
「表」で表現できるのがエクセルの強みですが、テストデータを組むさいに、縦でもたせる場合をみたことなくて、たいてい、横に並べるパターンが多いかなというのが感想です。

個人的には、たいていのテーブル定義書が、縦で表現されているところから、縦に書いていくのが好きです(縦といっているのは項目のこと)。左に項目名を用意して、列がふえていく感じです。

ただし、この記述方法ですと、古いエクセルは列数の制限から、テストデータを多く作るのには向いてなくて、やはり、項目は縦にもたせるよりは、横なのかなー。

エクセルのマクロが嫌い(苦手)なのですが、なんか最後にはエクセルなんですよね。

というわけで、こんなの考えてみました。


作成するにあたって、はじめて、 TRANSPOSEを知りました。

とりあえず、downloadできる場所に

Index of /download/excel

いくつかのユーザー関数を定義しています。


' ******************************** ' 改変自由 2014/02/22 ' deiji.jp ' ******************************** ' ******************************** ' コンキャッツ ' いい名前がうかばなかったので ' ******************************** Function CONCATS(rng As Range, Optional a As Variant = ",") As String Dim cnt As Integer Dim ret As String Dim m As Integer Dim i As Integer i = 0 m = rng.Count ' Debug.Print m For Each r In rng i = i + 1 ret = ret & r.Value If i < m Then ret = ret & a End If Next CONCATS = ret End Function ' ******************************** ' 参照、クォート、コンキャッツ ' いい名前がうかばなかったので ' ******************************** Function REF_QT_CONCATS(ref As String, rng As Range, Optional a As Variant = ",") As String Dim ret As String Dim m As Integer Dim i As Integer i = 0 m = rng.Count ' Debug.Print m ' 同行にある、値をチェックして囲むか決定する For Each r In rng i = i + 1 ' Debug.Print ">>>" & ref & r.Row 'シングルクォートするかはSQTで判断する ret = ret & SQT(Range(ref & r.Row).Value, r.Value) If i < m Then ret = ret & a End If Next REF_QT_CONCATS = ret End Function 'シングルクォート Function SQT(a As String, b As String) As String ' "○"なら囲む If a = "○" Then SQT = "'" + b + "'" Else SQT = b End If End Function



お尻のというか、最後に出現する全角のピリオドを変換したい。 2014/02/20

javaです。
最後に出現する全角のピリオドを変換したい。

どいうことかというと

ああ.いい.うう.ええ
とある場合

 ああ.いい.うう.ええ
 ということ

はじめ、
 "(.*).(.*)$"➡"$1.$2"
という正規表現を考えて、お尻からマッチだと思ったけど、"(.*).(.*)"でよかったみたい。

ためしたコードと結果は以下

package regex; import java.util.regex.Pattern; public class TestZenkakuDot { public static void main(String[] args) { a(); } static void a() { test置き換え("", ""); test置き換え("あああ", "あああ"); test置き換え(".", "."); test置き換え("..", ".."); test置き換え("...", "..."); test置き換え("....", "...."); test置き換え("あああ.いいい.ううう", "あああ.いいい.ううう"); test置き換え("あああ.いいい.ううう.", "あああ.いいい.ううう."); test置き換え("あああ.いいい.ううう..", "あああ.いいい.ううう.."); test置き換え(".あああ.いいい.ううう..", ".あああ.いいい.ううう.."); test置き換え("ああ.いい.うう.ええ", "ああ.いい.うう.ええ"); } static void test置き換え(String target, String expected) { // return Pattern.compile(regex).matcher(this).replaceAll(replacement); final String REGEX = "(.*).(.*)"; // final String REGEX = "(.*).(.*)$"; String s; s = target.replaceAll(REGEX, "$1.$2"); System.out.printf("%s actual:[%s] == expected:[%s]%n", s.equals(expected) ? "ok" : "ng", s, expected); } }

結果
ok actual:[] == expected:[]
ok actual:[あああ] == expected:[あああ]
ok actual:[.] == expected:[.]
ok actual:[..] == expected:[..]
ok actual:[...] == expected:[...]
ok actual:[....] == expected:[....]
ok actual:[あああ.いいい.ううう] == expected:[あああ.いいい.ううう]
ok actual:[あああ.いいい.ううう.] == expected:[あああ.いいい.ううう.]
ok actual:[あああ.いいい.ううう..] == expected:[あああ.いいい.ううう..]
ok actual:[.あああ.いいい.ううう..] == expected:[.あああ.いいい.ううう..]
ok actual:[ああ.いい.うう.ええ] == expected:[ああ.いい.うう.ええ]


まさかの2083文字問題に出会いました。 2014/02/19

まさかの2083文字問題に出会いました。


開発で使用している古いstruts でというタグを使い、つぎの画面にフォームの内容に転送しました。

実際、タグが展開されてレンダリングされた状態をみたところ、getのパラメータとしてフォームの内容が連結されていました。それで、キーが日本語を使っていたため、urlencode?されていたため、文字数をさらに消費して、2083文字オーバでフレームから次のページが読み取れないという流れになってしまった。

あと開発でターゲットにしているブラウザは、IE8なのでした。

シリアル値の計算 その3 エクセル - java POI頼み 2014/02/16

前回の記事の検証
実際に、org.apache.poi.ss.usermodel.DateUtilを使ってみる。


 今回試したコード

package poi; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import org.apache.poi.ss.usermodel.DateUtil; public class TestSerial2 { public static void main(String[] args) { a(); } static void a() { SimpleDateFormat format1 = new SimpleDateFormat("yyyy/MM/dd"); SimpleDateFormat format2 = new SimpleDateFormat("yyyy年MM月dd"); Calendar c = Calendar.getInstance(); c.set(1900, 0, 1);// 月は0スタート // とりあえず9000日 for (int i = 0; i < 9000; i++) { Date date = c.getTime(); System.out.printf("%s\t%s\t%f%n", format1.format(date), format2.format(date), toExcelSerial(c)); c.add(Calendar.DATE, 1); } } /** * excelで使用するシリアル値に変換します。 * * @param c * @return */ static double toExcelSerial(Calendar c) { return DateUtil.getExcelDate(c.getTime()); } }

出力された結果をエクセルシートにはりつけてみると
右の列が、書式設定している



SimpleDateFormatを使って、日付フォーマット - 再び 2014/02/16

javaです。日付フォーマットです。

何度も似たようなものではまってる自分がいるので、メモ

今回、SimpleDateFormatをシンプルに使った場合の動作の確認が目的
使うフォーマットは、yyyyMMdd

lenientは設定しない(デフォルト)
設定する(true)ですと、今回試した値は全て例外となります。

00000000 00021130
99999999 100070607
19990000 19981130
00009900 00080229
00000099 00010308
19990099 19990309
20130230 20130302
20140231 20140303
Unparseable date: "2013"
Unparseable date: "201401"
2014020 20140131


 使ったコードは、
import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public class TestSimplaDateFormat { public static void main(String[] args) throws ParseException { a(); } static void a() throws ParseException { // 文字列から日付の生成 { // どういう値になるかチェック test("00000000"); test("99999999"); test("19990000");// test("00009900"); test("00000099"); test("19990099"); } { // 存在しない日付 test("20130230"); test("20140231"); } { // 桁が足りない testNoThrowE("2013");// 4桁(月日なし) testNoThrowE("201401");// 6桁(日なし) testNoThrowE("2014020"); // 7桁 } } static void testNoThrowE(String s) { try { test(s); } catch (ParseException e) { System.out.println(e.getMessage()); } } static void test(String s) throws ParseException { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd"); Date date = dateFormat.parse(s); System.out.printf("%s\t%s\n", s, dateFormat.format(date)); } }

シリアル値の計算、その2 エクセル - java POI頼み 2014/02/15

エクセルで使われるシリアル値の計算についてです。
と、実は、自前で計算しようとすると、とても面倒な気が....

これ素直に、ライブラリまかせのほういいと思う。
「下手に手出すと帰ってこれない」いつものパターン



poiに渡すまえに計算して、渡すのではなく、Dateかカレンダーにして渡すのがよいと思う。自前で、計算すると、正しいかどうか、ちょっと検証するのつらそうなのと、実績あるpoiのほうが、3.8888倍(当社比)信頼性が高いと思うのであった。

HSSFCellに実装みると、シリアル値にしてから設定しているのがわかる。
3.10-finalのコード参照

public void setCellValue(Calendar value) { setCellValue( HSSFDateUtil.getExcelDate(value, _book.getWorkbook().isUsing1904DateWindowing()) ); }

public void setCellValue(Date value) { setCellValue(HSSFDateUtil.getExcelDate(value, _book.getWorkbook().isUsing1904DateWindowing())); }

使うエクセルの設定によっては、1900 年日付システムと 1904 年日付システムを区別する必要があるのが上記のコードからもみてとれる。自前で、算出する場合、これも考慮しないといけないので、素直にpoiまかせで。

お試しとして、シリアル値が必要なら、HSSFDateUtilを使うのよいと思う。

変換自体のロジックはorg.apache.poi.ss.usermodel.DateUtilあるようです。
以下、poiのソースコードから
org.apache.poi.ss.usermodel.DateUtil
private static double internalGetExcelDate(Calendar date, boolean use1904windowing) { if ((!use1904windowing && date.get(Calendar.YEAR) < 1900) || (use1904windowing && date.get(Calendar.YEAR) < 1904)) { return BAD_DATE; } // Because of daylight time saving we cannot use // date.getTime() - calStart.getTimeInMillis() // as the difference in milliseconds between 00:00 and 04:00 // can be 3, 4 or 5 hours but Excel expects it to always // be 4 hours. // E.g. 2004-03-28 04:00 CEST - 2004-03-28 00:00 CET is 3 hours // and 2004-10-31 04:00 CET - 2004-10-31 00:00 CEST is 5 hours double fraction = (((date.get(Calendar.HOUR_OF_DAY) * 60 + date.get(Calendar.MINUTE) ) * 60 + date.get(Calendar.SECOND) ) * 1000 + date.get(Calendar.MILLISECOND) ) / ( double ) DAY_MILLISECONDS; Calendar calStart = dayStart(date); double value = fraction + absoluteDay(calStart, use1904windowing); if (!use1904windowing && value >= 60) { value++; } else if (use1904windowing) { value--; } return value; }

時刻形式のための、シリアル値の計算、その1 エクセル - java 2014/02/14

Javaです。エクセル操作をおこなうためにpoiを使ってたりします。
時刻形式のフォーマットをエクセルファイルの書式で設定して、poiを使ってシリアル値を渡すための計算を模索してたりします。
 できてるっぽいです。

結果




参考


以下、コード

 
package poi; public class TestSerial { public static void main(String[] args) { a(); } static void a() { for (int i = 0; i <= 23; i++) { for (int j = 0; j <= 59; j++) { String sHH = "" + i; String sMM = "" + j; System.out.printf("%d:%d\t%f%n", i, j, toExcelSerial(sHH, sMM)); } } } /** * 参考<br/> * http://oshiete.goo.ne.jp/qa/4947261.html <br/> * 00:00 - 99:99<br/> * まで計算できるが時間の妥当性と数値チェックはおこなっていません。<br/> * * @param sHH * @param sMM * @return */ static public double toExcelSerial(String sHH, String sMM) { if (sHH == null || sMM == null) return 0.; if (!(sHH.length() <= 2 || sMM.length() <= 2)) return 0.; double hh = Double.parseDouble(sHH) * (1.0 / 24.0); double mm = Double.parseDouble(sMM) * (1.0 / 24.0 / 60.0); return (hh + mm); } }

2665 2014/02/11

ひさびさ
自力じゃない....




package p2665; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); do { int L = scanner.nextInt(); int M = scanner.nextInt(); if (L == 0 && M == 0) break; L++; for (int i = 0; i < M; i++) { int s = scanner.nextInt(); int e = scanner.nextInt() + 1; L -= e - s; } System.out.println(L); } while (true); } }

楽観はいた webでひきまわしの刑 2014/02/11

楽観排他制御です。

もう《後勝ち(あとがち)》でいいじゃんと思ったりしないでもない瞬間はありますが、排他大事ですね。お金の値とか、いろいろ大事な数字を厳密、そう、厳密、厳格(幻覚)にあつかわなければならないから。

じゃっ実際問題、排他にひっかかった場合、「入力したデータどうするんだよー」というのがあります。この辺、「あきらめて」最初から入力してくださいというのが現実なのかしら....

実現方法の案です。
更新時間を画面間でひきまわします。hiddenで引き回すぐらいでいいと思う。



ここで、更新時間(Timestamp型)を、画面でもたせるときに、タイムスタンプをいったん数値にしてもたせるのがいいかなと。





 これだとテストは大変じゃないブラウザをふたつ立ち上げてやればOK
が、SELECT ... FOR UPDATE使って、そのあとにUPDATEやってる場合、デバッガ使って、止めてとか、単体テストできちんとテストしとかないと、もうあとの工程でテストする機会がなくなると思われるので、テストきちんとしとかないとね。



参考

タイムスタンプから文字列へ、文字列からタイムスタンプへ 2014/02/10
2014/03/26

追記 2014/03/27 下の記事もあわせて参照のこと
プログラマメモ2: java.sql.TimestampからgetTimeすると、もとの精度にはもどせないことに注意せよ。

javaです。

java.sql.Timestampを文字列表現にします。それから文字列をTimestampに復元します。
元のTimestampと比較して等値かどうか調べるような場合を想定しています。

簡単に2種類ほど方法はあるかと思います。

ひとつはSimpleDateFormatを使うやり方。
もうひつとは、long値をとりだしてそれを文字列として扱うやり方です。

SimpleDateFormatを使う場合はのフォーマットは

yyyy-MM-dd HH:mm:ss.SSS
になります。
ただ僕的には、ちょっと違和感があります。

これよりlong値にして引き回した方がいいかなーと思います。
ただし、SimpleDateFormatのほうが、人が理解しやすい、ヒューマンリーダブルな感じです。

試したコードは以下


import java.sql.Timestamp; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public class TestTimestamp { public static void main(String[] args) throws ParseException { a(); } static void a() throws ParseException { // タイムスタンプを生成 final Timestamp timestamp = new Timestamp(new Date().getTime()); System.out.println(timestamp); final String stt = timestamp.toString(); {// がんばって文字列からTimestampを作り直す SimpleDateFormat simpleDateFormat = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss.SSS"); Date date = simpleDateFormat.parse(stt); Timestamp timestamp2 = new Timestamp(date.getTime()); if (timestamp.equals(timestamp2)) { System.out.println("*** BINGO!"); } else { System.out.println("*** ouch"); } } {// longから文字列にしてそれをもとにもどしてからTimestamp作って比較 String slong = timestamp.getTime() + ""; long l = Long.parseLong(slong); Timestamp timestamp2 = new Timestamp(l); if (timestamp.equals(timestamp2)) { System.out.println("*** BINGO!"); } else { System.out.println("*** ouch"); } } } }


結果はこんな感じ
2014-02-11 00:11:49.034
*** BINGO!
*** BINGO!

javaはちのまえにjavaななもこころもとない 2014/02/10

java8がそろそろやってきますね。ラムダ式、クロージャー、streamAPI、このあたり正直よくわってないですが、これらの衝撃あるのかなと期待しつつ、まだ、実はjava8試してないです。

groovyとかscalaとかjava上で動作する言語はたくさんありますが、java自体で、シンプルに書けて、表現力が大きくなる?のはいいことかなと。

実際の現場で、使われることは少ないでしょうが... とんがったところではがんがんなんでしょうが、僕の知っている範囲ですと、いまだにjava6....とか。

実は、僕もjava7あたりから、java自体に執着しなくなった感じがしてまして、ただ、自分のプログラミングの土台は、javaでして、javaが後方互換性のために、他の言語(プラットフォーム)C#ですとかに遅れをとるのはちょっと悲しいなーと感じてたりしてました。

いろいろな言語をちょこっと触ったり、調べてたりしているうちに、やはりjavaかなーと思ってます。とはいっても、java+clojureとか、まあ他のエッセンスも交えてなのでが。

あと気になるのはIDEですかねー、Age for javaからの流れで、eclipseが好きなのですが、java8に対応間にあってるのかなーと心配(とくに調べてないです)。

java8がくるまえにjava7をおさらいしときたいなー




プログラムで、いまさらながらマニュフェストを読み込み 2014/02/09

javaです。
いろいろあってマニュフェストです。

編集するツール群がなければ、自力でごにょごにょしないといけないので、念のため準備はしておこうと思うのでした。

  java.util.jar.Manifestがあるので読みこんで、追加したい項目を追加したの書き出すという流れになるかなと思います。

バージョンjava7です。

実行結果はこんな感じ
[Implementation-Title=xxxx, Manifest-Version=1.0, aaaa=OK]
[Implementation-Title=ooo, Manifest-Version=1.1, aaaa=OK]

package mf; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URL; import java.util.jar.Attributes; import java.util.jar.Manifest; public class TestReadMf { public static void main(String[] args) throws IOException { a(); } static void a() throws IOException { String smf = "/doc-files/MANIFEST2.MF"; URL url = TestReadMf.class.getResource(smf); System.out.println(url); Manifest mf = new Manifest(); // java7 この書き方でいいのか自信ないけど // 読み込み try (InputStream is = url.openStream()) { mf.read(is); System.out.println(mf.getMainAttributes().entrySet()); } // 書き込み try (OutputStream outputStream = new FileOutputStream(url.getFile())) { Attributes a = mf.getMainAttributes(); a.put(Attributes.Name.MANIFEST_VERSION, "1.1"); a.put(Attributes.Name.IMPLEMENTATION_TITLE, "ooo"); a.put(new Attributes.Name("aaaa"), "OK"); mf.write(outputStream); System.out.println(mf.getMainAttributes().entrySet()); } } }

ビルド設定でsrcフォルダにあるファイルを全部includedしたい ALL - eclipse 2014/02/09

eclipseです。
はまったのでメモ。

昔から、ファイルの読み込みとかちょっとした実験するときに、src/doc-filesとか、doc-filesフォルダを使ってやってます。

eclipseでソースフォルダにフォルダを作成するとパッケージとして扱われますが、ハイフンが入っているとフォルダとして表示されます。

そこで、テキストファイルとかおいて、実験してたのですが、いろいろやっている間に、おいたファイルがbin(クラスフォルダ)にコピーされなくなってしまってました。

うーん、と悩んで悩んで。

ビルドの設定で含める(include)がjavaソースだけになっていたからでした。
下記のような設定




これが全て(ALL)でないと クラスフォルダに転送してくれなくなります。
※もしくはピンポイントでファイル指定。

設定したいのはこんな感じ


ALLを指定したい場合は、editでパターンを全部消すとALLになります。



 これで、まるっとコピーしてくれるので、doc-filesになんでもかんでも入れれます。

 一体、何年、eclipseを使ってこんなことにはまるんだろう.....

javaから実行その7コンパイルして、invokeしてeval実行 - Clojure 2014/02/08

clojureです。
そろそろ行き詰まってきた感があります。

evalを試してみました。
まずevalを内部で実行する関数を用意して、それにlistを渡してあげるというイメージです。

参考


実行結果

#'clojure.core/m
class clojure.lang.Var
hello



package jp.deiji.ext; import java.io.StringReader; import clojure.lang.Compiler; import clojure.lang.PersistentList; import clojure.lang.Var; public class ExtClojure07 { public static void main(String[] args) { a(); } static void a() { new clojure.lang.RT(); {// // evalする関数を定義 String str = "(defn m[s](eval s))"; Object o = Compiler.load(new StringReader(str)); System.out.println(o); System.out.println(o.getClass()); // listを生成 Object o2 = Compiler.load(new StringReader( "(list (symbol (str \"print\" \"ln\")) \"hello\")")); Var v = (Var) o; v.invoke(o2); } } }

javaから実行その6コンパイル エラー - Clojure 2014/02/08

clojureです。
どう使っていこうかというアイデアを練っている最中です。

ロード時にエラーです。

適当なコードをloadすると

Exception in thread "main" java.lang.RuntimeException: EOF while reading, starting at line 1, compiling:(null:1:1) at clojure.lang.Compiler.load(Compiler.java:7071) at clojure.lang.Compiler.load(Compiler.java:7029) at jp.deiji.ext.ExtClojure06.a(ExtClojure06.java:18) at jp.deiji.ext.ExtClojure06.main(ExtClojure06.java:11) Caused by: java.lang.RuntimeException: EOF while reading, starting at line 1 at clojure.lang.Util.runtimeException(Util.java:219) at clojure.lang.LispReader.readDelimitedList(LispReader.java:1139) at clojure.lang.LispReader$ListReader.invoke(LispReader.java:982) at clojure.lang.LispReader.read(LispReader.java:185) at clojure.lang.Compiler.load(Compiler.java:7059) ... 3 more

package jp.deiji.ext; import java.io.StringReader; import clojure.lang.Compiler; import clojure.lang.Var; public class ExtClojure06 { public static void main(String[] args) { a(); } static void a() { new clojure.lang.RT(); {// エラー String str = "(defppppp"; Object o = Compiler.load(new StringReader(str)); } } }

点と点をむすぶものとしての - 詳細設計書 2014/02/08

《作る(コーディング)》する上で必要な情報がない。
リバースエンジニアリングみたいなことして、プログラムを書くような状態って、《謎とき》で楽しいのははじめのうちで、時間に追われていると、メモ書きでも残っていたらと思う。

この設計書が無駄だと思う瞬間は、これから《作ろうとされモノ、作るモノ》を表現するのに足りないからと知っているからなのだけど、この足りない隙間を埋めるのがプログラマーだと思われるのかと思うと、ちと悲しい。

 《作る》上で、役に立つ設計書とは何かなーと考えるのだけど、《どこに何をどう入れる》が《全量》書いてあること。理想はコードと設計書が1対1ぐらいになるようなイメージ。もちろん表現が違うけど、情報が対になるぐらいに。《全量》大事。やるなら《全量》希望。

そこまでできれば、あと表現を変えれば、ソースから設計書へ、設計書からソースへと。
(本当にそうできるかはわからないけどな、へへへ)

そこまでいくと、設計書って何よって話になるのかなと思うけど、人がシステムとか、《これから作られようとするモノ》、《既に作られたモノ》を理解するのに役に立つ何かというのが、僕の定義 。

常に変化し続けるシステムがあって、そういケースは、《転記(コピペ)するだけの設計書》なんていらないというのもあるだろうけどな。

アルゴリズムというかロジックというか処理の流れを、フローチャートを使わずに書く記法みたいなものを採用して欲しい。

フローチャートって、最初に起こすコストより、メンテナンスするコストのほうが高いような気がする。エクセルで、図の編集ってひとつひとつ動かさないいけないでしょう。

コピペだけの労働集約的な作業をもっと、品質あげたり、ユーザーのためにであったりと そういうところにエネルギーと費やしたいよねと。

《点と点》と思うのは、一般的な、画面にDBの中身を表示するようなプログラムで、点(DBのこのテーブルのこの項目)を点(画面のどこそこの位置)にだすので、それを《結ぶ》のプログラムであり、設計書の役割かなーと。単純に考えてみた。

徒然に。



マシンリーダブル(machine readable)な設計書 2014/02/04

 最近、「設計書を設計する」というのが自分の中でキーワードになってたりします。

「設計書」にはそのINPUTとなる情報があるわけですが、同じようにコードを書くためのINPUTとなる「設計書」が散文調ですと、それをベースにコードにおこすのが面倒だったりします。

 たいがいの設計書は、エクセルだと思うのです(ぜひともエクセルではないという例を知りたい)が、シートの配置や、記入するセルの位置、とか微妙に違うだけで、機械的な読みとりが難しくなります(人手を必要とする)

 その辺考えとくと、プログラマがわざわざ、エクセルからコピペしてXMLの設定ファイルを書いたりとかせずに、機械的にマクロとかもしくは類似な仕組みで、どーんと出力して、定義が一カ所にまとまっていて(リポジトリ)、何度でも同じように出力できる(再現性)をもたせることができるわけです。

転記(コピー)するの もコストです。「それコピペですむよ」というのはすんごい罠になることもあります。

最近、PDFにされた手書きのシステム設計書をみる機会があって、そういう時代があったんだと感動。

マシーンリーダブルとタイトルつけたけど、とくに深い意味なし。

 徒然に。


jspを返すrestlet 2014/02/03

jspを返すrestlet です。
とはいいつつ、これは正確な言い回しではないかもです。
GAE上で、Restletを使っていろいろ試しているところなのですが、restletで返すページ(この言い回しが正しいか微妙ですが)で、jspを指定して返したいなと。
で、いろいろ調べていて
jspってコンテナ上で、コンパイルされて処理されるものなので、どうもRestlet経由で、おこなうものっていうものでないらしく、僕が想像しているような感じのものがみつかりませんでした。


ただ、方法として、とりあえず、それっぽいものがあったので、忘れないように記事にしておきます。


 いまいち、決めてに欠ける理由に、こういう処理をしたいというニーズがないのかなと不安になりますが、海外で上記のやりとりがあるところから、JSPを処理して返したいという人々もいるのでしょう。

ルーターとして処理をしてくれるなら、なんでもそこを通して処理をしたいというの人の性(さが)というもので、いちいとweb.xmlとルーターで処理を分けるのもかったるいというか。。。

 と、Restletをさわりはじめて数日なので、的外れな意見かもしれませんが。

とにもかくにも忘れないうちにコードを残しておきます。

使い方は、そのものずばり

router.attach("/mng/kind/{name}/dummy", new JspRestlet(getContext(), "/ok.jsp"));

 それで、JspRestletの本体は、こんな感じ。


package jp.deiji.application; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.io.StringWriter; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; import org.restlet.Context; import org.restlet.Request; import org.restlet.Response; import org.restlet.Restlet; import org.restlet.data.MediaType; import org.restlet.engine.adapter.HttpRequest; import org.restlet.ext.servlet.internal.ServletCall; import org.restlet.representation.InputRepresentation; import org.restlet.representation.Representation; public class JspRestlet extends Restlet { String path; public JspRestlet(Context context, String path) { super(context); this.path = path; } @Override public void handle(Request request, Response response) { ServletCall httpCall = (ServletCall) ((HttpRequest) request) .getHttpCall(); RequestDispatcher dispatcher = httpCall.getRequest() .getRequestDispatcher(this.path); HttpServletRequest proxyReq = new HttpServletRequestWrapper( httpCall.getRequest()); BufferedServletResponseWrapper proxyResp = new BufferedServletResponseWrapper( httpCall.getResponse()); try { dispatcher.include(proxyReq, proxyResp); } catch (ServletException | IOException e) { e.printStackTrace(); } Representation rep = new InputRepresentation(proxyResp.toInputStream(), MediaType.TEXT_PLAIN); response.setEntity(rep); } /** * http://permalink.gmane.org/gmane.comp.java.restlet/8441 * * */ public class BufferedServletResponseWrapper extends HttpServletResponseWrapper { private StringWriter writer; private PrintWriter printWriter; private ByteArrayOutputStream outBuffer; private ServletOutputStream out; public BufferedServletResponseWrapper( HttpServletResponse httpServletResponse) { super(httpServletResponse); } public ServletOutputStream getOutputStream() throws IOException { if (printWriter != null) { throw new UnsupportedOperationException( "Outputstream cannot beobtained - getWriter already called"); } if (out == null) { outBuffer = new ByteArrayOutputStream(); out = new ServletOutputStream() { public void write(int b) throws IOException { outBuffer.write(b); } }; } return out; } public PrintWriter getWriter() throws IOException { if (out != null) { throw new UnsupportedOperationException( "Writer cannot beobtained - getOutputStream already called"); } if (printWriter == null) { writer = new StringWriter(); printWriter = new PrintWriter(writer); } return printWriter; } /** * This method is not supported, as it makes no sense to send a redirect * on a ServletResponse that is not connected. * * <at> param s <at> throws UnsupportedOperationException always */ public void sendRedirect(String s) throws IOException { throw new UnsupportedOperationException( "sendRedirect no supportedin restlet proxy"); } /** * Returns the content of the buffer as a string * * <at> return the content of the buffer */ public InputStream toInputStream() { if (printWriter != null) { printWriter.flush(); return new ByteArrayInputStream(writer.getBuffer().toString() .getBytes()); } else if (out != null) { return new ByteArrayInputStream(outBuffer.toByteArray()); } else { return new ByteArrayInputStream(new byte[] {}); } } } }






javaから実行その5コンパイルして、invokeする - Clojure 2014/02/02

clojureです。
javaから実行その5コンパイルして、invokeするです。
ふたつdefnで関数が定義されている場合、varのinvokeを呼ぶと最後に定義されたものが呼ばれるようにみえます。
ふたつdefnで関数定義されていてひつと前に定義されていたものを呼ぶことができました。

package jp.deiji.ext; import java.io.StringReader; import clojure.lang.Compiler; import clojure.lang.Var; public class ExtClojure05 { public static void main(String[] args) { a(); } static void a() { new clojure.lang.RT(); {// 二つdefnで定義されていた場合どちらを呼ぶか実験 String str = "(defn p1[](println \"その1\" )) (defn p2[](println \"その2\")) "; Object o = Compiler.load(new StringReader(str)); System.out.println(o); System.out.println(o.getClass()); Var v = (Var) o; v.invoke(); } {// 二つdefnで定義されており、呼ばれた関数から定義済みのものを呼び出す String str = "(defn p1[](println \"その1\" )) (defn p2[](p1)) "; Object o = Compiler.load(new StringReader(str)); System.out.println(o); System.out.println(o.getClass()); Var v = (Var) o; v.invoke(); } } }

結果
#'clojure.core/p2
class clojure.lang.Var
その2
#'clojure.core/p2
class clojure.lang.Var
その1


個人開発でも、メトリクスするススメ 2014/02/01

自分の生産性はどれぐらいなものだろうと思うとやはり計測してないとそれには答えられないなと。

お仕事だと、準備のできてるプロジェクトにいく場合、いろいろ決まり事ができてる状態で、 ベンダーがもつ過去のプロジェクトの資産があったりで、数値的な予測はたてられたりするけど、僕自身はどうなのだろうかと。

空いた時間でしか、いろいろ作れないので、ゴールを決めて、そこに到達するまで、どれぐらいのものを作らないといけいのか、どれぐらいの時間がかかるのか、知りたいなと思った次第。

まあ、経験で、《目標たてて、最後までいかないパターン》だなーと思うケースがしばしなのだけど、もしも実現するなら、どれぐらい《時間というコスト》がかかるのか予測をたてたい。

新しいことだと概念を学習する時間が必要だったり、調べものしたり、で時間がかかることはわかるが、不確定要素も見積もりできたらよい。

《メトリクスする》という言い回しが正しいかわからないけど、計測すること大事ということで、どう《自分の数値》ベースを知るか。

どこからはじめるかなというわけで、毎日書いたメモとか、ソースコードから、生産量をはかろうかなと。まあ、アイデアとしてFLOC(File Lines Of Code)を使い、毎日、記録をとる。ソースコードのコピペとか定型文とか、コメントとか考慮に入れず、ライン数のみで数える。

LOC(Lines Of Code)って手あかにまみれた指標だけど、比較する対象が、 《自分》だけなら、なにか見えてくるのではなないかなと期待。

LOCとバグ数って、まあ、とりあえず集めやすいし....

どのタイミングで数値を集めるかは、一日の作業終了時に記録をとるかんじかな。

ただのライン数だけど、前日の計測値とくらべて、《どれぐらい変化》があったかで、生産性みたいなものを計るための指標にできないかというのがいまのアイデアです。

削除されたラインでも《その前の状態(前日)》と比較すれば、そのダイナミズムみたいなものはわかる。

収集するのは、
ファイルパス、ファイルサイズ、タイムスタンプ、ファイルの内容のハッシュ値。

収集するときのロジックは、

a.前日(前回)収集されていないものであれば記録する。
b.ファイルのタイムスタンプとファイルサイズを前日のものとくらべて、変化があれば、そのライン数を記録する。
ただしタイムスタンプが変更されていて、ファイルサイズが同じ場合は、ファイルのハッシュ値をもとめて、違いがあれば記録する。
 
という感じになるのかな。

 収集対象外のファイルも指定できたらよいなー。

記録を格納するのは、db(javaならH2とか)に。












この前、エクセル列名から、位置をもとめたのでその逆をやってみます。 その2 2014/02/01

この前、エクセル列名から、位置をもとめたのでその逆をやってみます。 その2です。
前回は、再帰使ったので、今回はそうでないやり方で。



 このやり方、挑戦して、すぐできなかったので、あきらめたのだけど。
26進数ということだと思うのだが。

メソッドはこんな感じ。
0〜の数値をエクセルの列の英字に変換します。


public static String rpos(final int p) { final StringBuilder builder = new StringBuilder(); final int n = 26;// n進数 int[] a = { p, 0 }; do { a = new int[] { a[0] / n, a[0] % n }; builder.insert(0, (char) ('A' + a[1])); a[0] -= 1; } while (0 <= a[0]); return builder.toString(); }