FM牛鍵屋本舗

プログラマ(弱)の日々精進系ブログ

Haskellことはじめのその1

漠然と、次に覚える言語は今使ってるJava(や、JavaScriptとかPerlとか)以外のパラダイムの言語にしたいなー
と思っていて、ぱっと思い浮かんだのがちょっと前にやけに流行っていた関数型言語

と、いっても関数型言語って結構あるし、どうしよう…。 Lispもいいし、仕事のこと考えるとScalaとか覚えるのもいいかも知れない…。

結論。

理由。

  • なんとなく

環境。

  • mac OSX 10.12.5
  • homebrew 0.9.9

Haskell Platformの公式っぽいところみたら、
普通にインストール方法について親切な記載が。
brewで書きたかったので、

$ brew cask install haskell-platform

でけたー。

$ ghci
GHCi, version 8.0.1: http://www.haskell.org/ghc/  :? for help
Prelude> 
Prelude>sum[1,2,3]
6
Prelude>

native修飾子を使ってみる(JNI)

javaの勉強を始めた頃に 存在を知ったnative修飾子。 java.lang.Systemのソースなどなど 結構使われていたので、ちょっと学んでみました。

以下をはじめ、いろんな情報源を参考にさせてもらいました。
link

そもそもnative修飾子とは

link

nativeのメソッドは一般的にCのような別の言語で書かれた プラットホームに依存するコードにて実装されます(超意訳)

プラットホームに依存した方が 高速な演算の実現は可能、だけど
一方で環境ごとのライブラリが必要になるから “Write once, run anywhere"の思想からは外れる。
まあ元々WORAは言うほどでもないそうですが。

JNIとは

link Javaネイティブメソッドを書いたり、 Java仮想マシンをネイティブアプリケーションに組み込む 標準プログラミングインターフェース。
JREに含まれてます。

とりあえず試してみる

Javaでnativeメソッドを書いてみる

package hoge;

public class Hoge {
  
  // staticイニシャライザ
  static {
    // 共有ライブラリを読み込む
    System.loadLibrary("<span style="color:#FF0000">HogeHoge</span>");
  }

  public static void main(String[] args) {

    Hoge hoge = new Hoge();
    hoge.call();

  }

  // natice修飾子を付与したメソッド
  // 処理内容は記載しない(interface的な感じ)
  public <span style="color:#FF0000">native</span> void call();

}

普通にclassを生成する

javac hoge/Hoge.java

classファイルからヘッダファイルを生成する

javah -jni hoge.Hoge

結果として、以下のファイルが出力される。

/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
/* Header for class hoge_Hoge */

#ifndef _Included_hoge_Hoge
#define _Included_hoge_Hoge
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     hoge_Hoge
 * Method:    call
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_hoge_Hoge_call
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

実装コードを作成する

#include "hoge_Hoge.h"

JNIEXPORT void JNICALL Java_hoge_Hoge_call (JNIEnv *env, jobject obj) {
  printf("Hello, World!"); 
}

ライブラリを作る

僕の環境はMacOSXなのですが、 どうやらライブラリというのは各プラットフォームで色々違うようで。
例えば、WindowsだとDLL形式だとか、Linuxだとlib〜.soだとか。
このあたりは別途詳しく調べるとして、 Macだとdylibというらしいです。

gcc -shared -I /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/include -o lib<span style="color:#FF0000">HogeHoge</span>.dylib hoge_Hoge.c
  • sharedは共有ライブラリを作るオプション
  • -Iは使用するinclude対象を見に行く先。 今回は"jni.h"とそこから参照される"jni_md.h"が必要になるみたい。 find / -name “jni*.h"で探したけど、どうもJDKのinclude及びinclude/darwinにあるみたい。 sudo ln -sでinclude直下にjni_md.hのシンボリックリンクを作りました。
  • Macの場合、共有ライブラリはlib.dylibにしないといけないみたい。 そして、の部分がSystem.loadLibraryの引数になる、と…。

実行する

java -Djava.library.path=. hoge.Hoge

実行結果

hoge$java -Djava.library.path=. hoge.Hoge
Hello, World!%

CODE COMPLETE 第2版 下巻(2)

雨がうっとうしい。

第27章 プログラムサイズが及ぼす影響

  • プロジェクトのメンバーに応じてコミュニケーションパスが乗法的に増加する。
  • プロジェクトの規模が大きくなるとエラーの数は劇的に上昇する。
  • プロジェクトの規模が小さいほうが生産性は高い。
  • プロジェクトの規模が大きくなると、コンストラクション(開発)の割合が相対的に小さくなる
  • 堅苦しいアプローチ(厳格な方法論)は適用を誤ると、利点がオーバーヘッドにより帳消しになる。

第28章 コンストラクションの管理

  • コードが共有資産であることを強調する。
  • PMが理解でいるコードを書く(コードを理解可能な標準を設ける)
  • 構成管理
    • 手順化/体制化
  • スケジュールの遅延に対する対応。
    • 増員はタスクが適切に分割されていないと即時性のある効果を挙げられない
    • プロジェクトの範囲を狭めるのが有効(機能を落とす)
  • プロジェクトで何が起きているかを把握するために、各種の測定(コードの行数、空白行の数、メソッドの引数etc)を行う
  • 技術経験の乏しい管理者に対しては「管理者の管理」を行う
    • こっそり洗脳する

第29章 統合

  • 色々方法はあるが、直前まで統合を行わないフェーズ型(ビックバン)統合はリスクが高い
  • インクリメンタル型統合のうち、適切な手法を用いる。
  • デイリービルドとスモークテストを日次で行う
    • Jenkins使ったことないけど使ってみたいなあ

第30章 プログラミングツール

  • 必要なツールは自作する
  • 将来に渡っても完全な自動化にはならない

第31章 レイアウトとスタイル

  • レイアウトはプログラムの論理構造を明らかにする(特にブロック)
  • 優秀なプログラマでさえも、「期待するレイアウト」に沿ってないコードでは理解力が低下する
  • 良いレイアウトの目標
    • コードの論理構造を正確に表現する
    • コードの論理構造の表現に一貫性がある
    • 可読性を向上させる
    • 変更に耐える(保守し易い)
    • レイアウトスタイル
      • 純粋なブロック
      • 純粋なブロックのエミュレート
      • ブロック境界の指定
      // BAD Pattern.
      if (boolean)
        {
          //statements..
        }
      // BETTER Pattern.
      if (boolean)
        {
        // statements.
        }
    * 行末インデント(原則BADパターン)
        * インデントをあわせることで可読性は高くなるかもしれないが、保守性が著しく低下する
        * 1行ステートメントは使用しない。バグの温床になる&デバッガで実行されたかが不明(確かに!)
        * 代入文の右辺を揃えないこと // 確かによく見かけるなあ
        * データ宣言に関しては後置コメントもあり

第32章 読めばわかるコード

  • プログラムソース自体がドキュメント(内部ドキュメント)
    • 変数名、メソッド名、適切な抽象化、コメント
  • コメントの種類
    • コードの繰り返し(NG)
    • コードの説明(NG)
      • コードの説明が必要な場合は実装、設計自体を見直すこと
    • コードの目印(NG)
      • TODOとか。
    • コードの概要(OK)
    • コードの意図の説明(OK)
    • コード自体では表せない情報(OK)
  • 効率的なコメントの作成
    • PPPの手法を使い、変更で壊れたりしないスタイルを使う
    • 方法でなく理由に充填を置く(適切な抽象化)
  • データの単位はコメントで表す、よりは、変数名に含めたほうがよい
  • 変数、ルーチンの許容される範囲をコメントで表す
  • バージョン管理タグ

第33章 個人の資質

  • どれくらい知的であるかより、自分の知性をいかに集中させるかが大事
    • 複雑さに対処し、脳の負担を減らすこと
  • 粘り強さは邪魔になることが多い

第34章 ソフトウェア職人気質とは

  • 複雑さの克服
  • 規約を策定することで、本当に考えなければならにことに集中できる

第35章 さらに情報を得るには

  • いろんな関連書籍の紹介

【T-SQL】CURSORの使い方

触ってないとすぐ忘れちゃう…。
https://docs.microsoft.com/ja-jp/sql/t-sql/functions/fetch-status-transact-sql
とはいえマニュアルじっくり読んでないから、 ちゃんと読みたい。

CREATE CUROR cursor_name FOR
  SELECT id, name FROM sample_table
;

DECLARE @c_id INT;
DECLARE @c_name NVARCHAR(10);
OPEN cursor_name;
FETCH NEXT FROM cursor_name&#160; INTO
  @c_id, @c_name
;

DECLARE @tmpTable (
  t_id INT,
  t_name NVARCHAR(10)
)

-- @@FETCH_STATUSは
-- -1 : FETCH文失敗か結果セットに収まらない
-- -2 : 取り出した行がない
WHILE @@FETCH_STATUS = 0
 BEGIN
 
 INSERT INTO
 @tmpTable
 VALUES (
   @c_id,
   @c_name
 );

 -- 次を読み込む
 FETCH NEXT FROM cursor_name&#160; INTO
   @c_id, @c_name
 ;

 END

CLOSE cursor_name;
-- @@FETCH_STATUSは初期化されないから注意

あと完全に別件だし、MSDNでも前者だけど、

IF boolean
  BEGIN
    statement
  END

ではなくて

IF boolean
  BEGIN
  statement
  END

モアベターだとか。 CodeCompleteによれば、だけど。

ほなまた!

T-SQL知らなかったメモマン

時間がないからといって API(に限らず)の設計を見切り発車で作成するのは くなかったな、と痛感した今日。

焦ってコンストラクションを行うほうが 結果としてリスクもコストも高くなる悪例でした。

ストアドファンクションでは副作用を伴う処理を行えない

副作用を伴う処理とは、 INSERT/UPDATE/DELETE/EXEC PROCEDUREなど。
(PROCEDUREに関しては、一部の拡張ストアドプロシージャならOKだとか。要調査)
FUNCTION=関数という言葉を、関数型言語の意味の関数で捉えるとわかりやすい。 参照透過性というか。

exec sp_executesqlを使えば、FUCNTION内部からでも無理やり実行できなくはない…と思うが、
言語仕様としてやめとけっていうのに逆らうとろくなことがない。
PROCEDUREでやったほうがわかりやすくて綺麗になる。

あと地味に、BEGIN TRY〜END TRY(CATCHも同様)も使えない。
これはちょっと理由がわからないな…。

Table型パラメータの誤算

ストアドプロシージャのOUTパラメータとして、Table型は使えない。
では可変で複数を取りうる値を返すにはどうするかというと、 statement_bodyにSELECT句を書けば、 結果セットとして返却可能。 ただし、通常のSELECTはすべて結果セットとして返却されてしまうので、API設計(というかパブリックなルーチン設計か?)としては あまりよろしくないかもしれない。 ではどうすればよいかというと、 変数に代入してあげれば、そのステートメントは結果にはならない。 Table型(や、独自ドメイン)はINパラメータとしては使える。

パラメータは2,100個まで。

()で囲めば、IF文の中でもSELECT句をかける。

毎度変数に代入してた…。可読性とのトレードオフになるかとは思うけど。

YYYYMMDD形式が厳密に正しい日付かどうか。

一応、IsDateという関数は提供されているが、 言語やフォーマット変えないと使えないっぽい。 CONVERT使うとエラーになるし、困った。 邪道だけど、TRY-CATCHでなんとかするか、と思ったが、 FUNCTIONでは使えない。 (アンチパターン

うーん、8桁の確認と、substringで分割してIsDateにぶち込むか、 と思ったら、try_convertなる関数があるようで。 変換不可ならNULLを返してくれる(もちろんIsNullと組み合わせればNullオブジェクトっぽくも出来る) 素敵関数。 可搬性は低そうだけど…。

STOREDのCREATE系(一応備忘録)

CREATE PROC[EDURE] proc_name (
@var1 type [READONLY],
@var2 type = default OUT
)
BEGIN
-- 最低1行のステートメント
END
-- FUNCTIONはRETURNSが付く感じ。
-- TABLE型には()を付加して、通常のCreate Tableみたいなカラム定義する

SQL標準も学ばないとな、と決意を新たにしました。

CODE COMPLETE 第2版 下巻

途中までしかまとめられてないけど

第25章 コードチューニング戦略

  1. パフォーマンス ≠ コードチューニング というか、コードの速度向上がパフォーマンス改善の一部分でしかない。 要件、設計レベルの見直しやハードウェアの改善、コンパイラやOSコールなど 改善できるところは多々あるはず。

  2. コードチューニングは基本的に経験則は役に立たない。 立つとすれば、徹底した測定のみ。 ハードウェアや実装言語、コンパイラなどに依存するので 完全な正解は存在しない。

  3. 速いコードを書くことより、たいていの場合正確なコードを書くことのほうが重要だ。 実装が完了してから最適化を行う。

第26章 コードチューニングテクニック

  1. ループのコストが高くなることが多い

    • ループ回数の改善を行うとか
  2. sentinel値 検索の最後に配置し、ループの終了を表す値

    • ループ内の分岐を減らせる
  3. (用途によっては)低級言語の導入

    • Javaもnativeとかある
  4. 基本的に、パフォーマンスの最適化は可読性・保守性はトレードオフになりがち。

【読書】プログラマが知るべき97のこと

全体的に、以下に重点が置かれているのかな、と思う。

「命をふきこむ魔法」「名前重要」の話は特に面白かった。

あまりコードを読んでこなかったので、 今後は新しい言語を学ぶのも含めて、 OSSを色々落として読んでみようと思う。

とりあえず、Javaのsrc.zipから…

01. 分別のある行動

技術的負債 は返す。返せるような仕組みにしておく。

08. ボーイスカウト・ルール

来たときよりも美しく。 コードに編集を加える場合は、チェックアウト時よりも綺麗にして ソースベースにプッシュする。

17. コードに書けないことのみをコメントにする

メソッド名、変数名。

18.
22.
36.
43.

学び方に関する指南。 複数の(パラダイムの)言語を学ぶとか、 勉強会に参加するとかそういう話。

23.

ドメイン特化言語。知らない言葉だった。

25. 見られて恥ずかしいデータは使わないこと

テストデータでふざけたのを投入していて、デモに使われると困る。

33.

OSSで好きなことをやろう。

38. 余分なコードは決して書かない
58.
87.

プログラマとテストエンジニアのあるべき関係について

64. プロのプログラマとは

責任感です。

74. 「イエス」から始める

(要求なども)否定から入るのではなく、 せめて「なぜその仕様変更を行いたいのか」を確認する。 決して無碍にしない。

…次は達人プログラマーを読みたいな。