技術とか戦略とか

IT技術者が技術や戦略について書くブログです。

立教池袋中学校・高等学校文化祭(2018年)-数理研究部の展示の紹介

Facebookでの紹介で、立教池袋中学校・高等学校文化祭(RIF)の数理研究部の展示を見に行きました。
金融系SEとして多くの感銘を受けたので、その感動をぜひ共有したいと思い技術ブログでも記事を上げます。特に、技術者の方々にはぜひ見て欲しいです。
 
理研究部は、理数学の知見をベースとして、数学・経済学・情報学の分野の活動を行う部活です。
2018年の展示内容は以下の通りでした。
 
VR(仮想現実)やMR(複合現実)の技術を用いた作品の展示
 人の動きで仮想空間上の自分を操る技術を利用・開発し、作品を作っていた。
 火災からの避難を扱った作品や、ブロック崩しゲームが展示されていた。
 VR作品は、文化祭のみでなく様々なコンクールで出展されており、
 11月14~16日のIVRC(http://ivrc.net/2018/)にも出展予定である。
 
・自作ゲームの展示
 数理研究部の昔からの恒例展示。
 今年はUnity(ゲームエンジン)等を用いた自作ゲームが多数展示されていた。
 コンピュータゲームのみでなく、テーブルゲームについても展示されていた。
 
・情報学のアルゴリズムに関する展示
 言語学習や二分検索等に関する展示が行われていた。
 
・日経ストックリーグの展示
 日経ストックリーグとは、社会的テーマに基づいた仮想的な投資を行い、
 そのレポートの完成度を競う学生向けのコンクールである。
 数理研究部も参加しており、レポートを要約したパネルが展示されていた。
 
・算数クイズ
 中1が担当する数理研究部の昔からの恒例展示。
 中学受験レベルの自作の問題を解いてもらうというもので、
 数学的な興味をそそられるユニークな問題が出題されていた。
 
・数学甲子園の展示
 残念ながら本戦には出られなかったようだが、
 数学甲子園の紹介や出場記録が展示されていた。
 
・その他数学の展示
 ハノイの塔を解き方について説明した展示が行われていた。
 その他、メロスの走る速さを数学的に求めた展示等、
 動画にして上げたら受けそうな面白い展示もあった。
 
文章だけでは雰囲気が伝わりにくい所もあるので、写真も撮影しました。
(顧問の内田先生、及び被写体の方々には許可を取っていますが、万が一問題があればコメントでお知らせください。写真の加工若しくは写真の消去で対応致します。)
 
これは、火災から避難を扱ったVR作品「Avoid the Risks of CO」のプレイの様子を撮影した写真です。
仮想空間上をあたかもリアルの空間のように動く様子が伝われば幸いです。

f:id:akira2kun:20181103190728j:plain

 
また、これは技術者として特に感銘を受けた展示ボードです。PDFファイルでまとめています。
私の文章では要約しすぎていて伝わらない所もあるので、こちらも是非見てほしいです。

https://1drv.ms/b/s!AivF3bzWXOzuhQFXk5hscKYqkLkM
 
全ての展示を紹介しきれないのが残念ですが、もしも感動が少しでも共有できたなら幸いです。

サクラエディタ:特定の文字列を含まない行をgrepで抽出する

UNIXgrepコマンドだと-vオプションで指定した文字列を含まない行を抽出することができますが、サクラエディタgrepだと一見できないように見えるので。
 
結論から言うと、
^((?!hoge).)*$
と指定すればできます(「hoge」は任意の文字列)。
 
以下、おまじないは怖いという人向けに説明です。
 
【例】
grep対象のファイル
____hoge____
____fuga____
____piyo____
 
・失敗例…[^...](否定)を使った場合
[^...](否定)だとできません。一文字しか判断できないので。
 
□検索条件  "[^hoge]"
C:\tmp\a.txt(1,1)  [SJIS]: ____hoge____
C:\tmp\a.txt(2,1)  [SJIS]: ____fuga____
C:\tmp\a.txt(3,1)  [SJIS]: ____piyo____
3 個が検索されました。
 
□検索条件  "[^h][^o][^g][^e]"
C:\tmp\a.txt(1,1)  [SJIS]: ____hoge____
C:\tmp\a.txt(2,1)  [SJIS]: ____fuga____
C:\tmp\a.txt(3,1)  [SJIS]: ____piyo____
3 個が検索されました。
 
・成功例…(?!式)(否定先読み)を使った場合
(?!式)(否定先読み)だと文字列で判断できるので可能です。
 
□検索条件  "^((?!hoge).)*$"
C:\tmp\a.txt(2,1)  [SJIS]: ____fuga____
C:\tmp\a.txt(3,1)  [SJIS]: ____piyo____
2 個が検索されました。
 
【説明】
・否定先読みについて
公式ドキュメント参照ですが、Sakuraでは否定先読みができます。
 
利用可能な正規表現

http://sakura-editor.sourceforge.net/htmlhelp/HLP000089.html
 
否定先読みの機能の説明については、以下のページが参考になります。
 
正規表現の先読み・後読みを極める! - あらびき日記

https://abicky.net/2010/05/30/135112/
 
・今回の指定条件について
(?!hoge). とすることで、直後にhogeが続く箇所以外の全ての箇所がヒットします。
上記の例で言うと、「hoge」の1文字目の「h」以外は全てヒットします。

(なお、.(?!hoge) だと、「hoge」の直前の「_」以外が全てヒットします。これだと、文頭がhogeで始まる場合に問題が生じることになります。)
 
((?!hoge).)* とすることで、ヒット箇所の0回以上の繰り返しを表現できます。
 
^((?!hoge).)*$ とすることで、行頭から行末までヒット箇所の0回以上の繰り返し、となります。
ヒット箇所は何回繰り返されても良いのですが、文頭から文末まで続いている必要があります。
「____hoge____」は途中でヒットしない箇所が出てくるので、この条件には引っかかりません。
なお、0回の繰り返しを含むので、空行(改行のみの行)でも条件に引っかかります。
(上記の例を作った後に、念のために空行も引っかかることを確認しました)

java:enum型を使うと何が嬉しいのか調べてみた

実務でenum型が出てきたのですが、私が使った入門書にはenum型に関する説明がなかったので、改めて調べてみました。
 
enum型とは、複数の定数をまとめるための型です。
文法的には以下のページで解説されている通りです。
 
Java入門】Enum(列挙型)の使い方総まとめ  侍エンジニア塾ブログ  プログラミング入門者向け学習情報サイト

https://www.sejuku.net/blog/14779
 
ただ、このページには文法については書いてあっても、enumを使うと何か嬉しいことがあるのかどうかはわからず…。
「int型やString型で定数を定義した方が楽なのでは」と思ってしまったので、もう少し調べてみました。
 
enumを使うメリットについては、このページの解説がわかりやすかったです。
 
テックノート - 今さら聞けないenumの基本を解説

http://javatechnology.net/java/enum/
 
どうやら、呼び出し側から見てどのような値を指定すれば良いのかがわかりやすくなるのがメリットのようです。
確かに、クラスの中に定数を持たせるよりは、enum型のクラスとして定数を外出しにした方が可読性は上がるかもしれません。
 
なお、enumはstaticインポートすることが可能とのことです。
(実務で出くわしたのはこのケースでした)
 
5. static インポート  TECHSCORE(テックスコア)

http://www.techscore.com/tech/Java/JavaSE/JavaLanguage/5/
 
色々調べてみて、定数を色々なクラスで使い回せるというメリットもありそうだと思いました。
それを確かめるためのサンプルプログラムは以下です。
 
【サンプルプログラム】
・ExamplEnum.java
package enumTest;

public enum ExamplEnum{
    OK(1),
    Error(2);

    private int id;

    public int getId() {
        return id;
    }

    private ExamplEnum (int id) {
      this.id = id;
    }

    public static ExamplEnum valueOf(int id) {
        ExamplEnum array = values();
        for(ExamplEnum num : array) {
            if (id == num.getId()){
                return num;
            }
        }
        return null;
    }
}
 
・Main1.java
package enumTest;
import enumTest.ExamplEnum;

public class Main1 {

    public static void main(String args) {
        int param = 1;
        ExamplEnum examplEnum = ExamplEnum.valueOf(param);
        System.out.println("enum : " + examplEnum);
    }
}
 
・Main2.java
package enumTest;
import enumTest.ExamplEnum;

public class Main2 {

    public static void main(String[] args) {
        int param = 2;
        ExamplEnum examplEnum = ExamplEnum.valueOf(param);
        System.out.println("enum : " + examplEnum);
    }
}
 
【実行結果】
・Main1.java
コンソールに下記文字列が出力される。
enum : OK
 
・Main2.java
コンソールに下記文字列が出力される。
enum : Error

Oracle:CBO(オプティマイザ統計)についてOracle現場ワザで勉強してみた

実務を行う上でOracleの実行計画のことが良く分からずに困っていたので、少し古い本ですが「新・門外不出のOracle現場ワザ エキスパートが明かす運用・管理の極意」という本を読んで勉強しました。
 
詳しい内容は本書参照ですが、簡単に内容をかいつまんで書くと以下の通りです。
 
CBOの概要説明】
RBOCBO
 従来はSQL文だけを解析するRBOが使われていた。
 しかし、現在ではオプティマイザを使用するCBOが使われている。
 (Oracle7でCBOが登場し、Oracle10gでRBOがサポートされなくなった)
 
・ソフトパースとハードパース
 SQLの実行時に、ソフトパースとハードパースのどちらかが行われる。
 ソフトパースは共有プールにキャッシュが存在する場合に使用される。
 ハードパースは共有プールにキャッシュが存在しない場合に使用される。
 (初めてSQLを実行する場合 or キャッシュアウトされている場合)
 ハードパース時に、オプティマイザは使用される。
 
オプティマイザの内容
 オプティマイザは統計情報を収集している。
 下記の統計を収集している。
 -表統計(行数、ブロック数、平均行長)
 -列統計(列内の平均個数、列内のNULL数、データ分布)
 -索引統計(リーフブロック数、ツリーの高さ、クラスタリングファクタ)
 -システム統計(I/OやCPUのパフォーマンス)
 
・実行計画
 オプティマイザから実行計画が作成される。
 実行計画では、表からどのようにデータを取り出し、
 どのような順番・方法で結合するかを定めている。
 
CBOの判断内容】
クラスタリングファクタ(索引の偏り具合を示す値)
 一般的には、条件指定により15%以下にデータを絞り込める場合は、
 フルテーブルスキャンよりもインデックスアクセスの方が高速とされている。
 しかし、索引の偏り具合によっては、
 フルテーブルスキャンの方が高速な場合もある。
 CBOでは、索引の偏り具合をクラスタリングファクタを見て判断し、
 場合によってはフルテーブルスキャンを使用する。
 
・データ分布(最大値/最小値/ヒストグラム統計)
 CBOではSQL文の条件指定を見て、何%の行がヒットするのかを予測する。
 予測次第で、フルテーブルスキャンを使うか、
 インデックスアクセスを使うかを判断する。
 しかし、条件指定だけを見ると、データに偏りがある場合に判断を誤る。
 そこで、CBOではデータの偏り具合をヒストグラム統計として取得し、
 ヒストグラム統計を見ることで、
 データが偏りがある場合にも正確に予測できるようにしている。
 
・バインド変数とバインドピーク機能
 select hogeCol1 from hogeTBL where hogeCol2 = :hogeVer;
 のようなSQL文があった場合、「:hogeVer」のことを「バインド変数」と呼ぶ。
 バインド変数には、外部から値を指定することができる。
 バインド変数を用いると、共有プールメモリ使用量が減少し、
 ハードパース発生率も減少するメリットがある。
 しかし、バインド変数を使用する場合、バインドピーク機能を使わないと、
 デフォルトで「5%の値がヒットする」とCBOは判断してしまう。
 そこで、バインドピーク機能を使用することで、
 バインド変数にセットされた値を覗き(peekし)、
 ヒストグラム統計等を用いて何%の行がヒットするか
 予測することができるようになる。
 
・CURSOR SHARING パラメータ
 リテラル値(...= 10 のような定数)を使用したSQL文に対して、
 共有カーソルを共有することでバインド変数使用時と同じように、
 共有プールメモリ使用量減少等のメリットを得ることができる。
 デフォルト値は「EXACT」で、共有カーソルは共有されない。
 「FORCE」とした場合は、共有カーソルは共有される。
 「SIMILAR」とした場合は、
 実行計画が確実に同じになる場合のみ共有カーソルが共有される。
 
・CPU+I/Oコストモデル
 オプティマイザは、I/OやCPUのパフォーマンスを取ることで、
 システム固有の性能や特性を考慮した実行計画を生成できる。
 そのため、オンライン時間帯やバッチ時間帯を想定した
 ワークロードを流して統計を取ることで、
 より実運用に適した統計情報を生成することができる。
 なお、オプティマイザは、
 索引ブロックがバッファキャッシュ上に残っていることを見落とし、
 実際よりもI/Oが多く発生すると見積もる可能性がある。
 この場合、フルテーブルスキャンが選択されやすくなるため、
 下記のパラメータにより補正することができる。
 -OPTIMIZER_INDEX_CACHING
 -OPTIMIZER_INDEX_COST_ADJ
 
スループット重視/レスポンス重視
 スループット重視とは、最後の行を返すまでに時間を最速にするものであり、
 バッチ処理に適している。
 OPTIMIZER_MODEを「ALL_ROWS」にすることでスループット重視になり、
 デフォルトではこの状態になっている。
 それに対して、レスポンス重視とは、
 最初の数行を返すまでの時間を最速にするものであり、
 最後の行まで読まれない可能性があるオンライン処理に適している。
 OPTIMIZER_MODEを「FIRST_ROWS_n」(n=1,10,100,1000)にすることで
 レスポンス重視になる。
 OPTIMIZER_MODEはセッションレベルやSQLレベルで指定可能である。
 
・テーブル結合
 テーブル結合では、CBOは実行計画作成時に以下について検討する。
 -アクセスパス
  各表からのデータの取り出し方法。
  (フルテーブルスキャン、インデックスアクセス等)
 -テーブルの結合順序
 -テーブルの結合方法
  (ネステッドループ結合、ソートマージ結合、ハッシュ結合)
 
 本当に最適な方法を計算するとその計算自体に時間がかかってしまう。
 そのため、以下の方策により、準最適な方法を短時間で割り出している。
 -ヒット件数の少ないと見積もられる順に結合
 -ベストコストの保持とコスト計算の途中打ち切り
 -評価する結合順序の上限数の設定
 
CBOの実運用】
・自動統計収集
 Oracleでは、更新された行の割合が増える度に、
 自動的にオプティマイザ統計を収集することができる。
 これにより、常に最適な実行計画を生成できるようになる。
 デフォルトでは自動統計収集がオンになっており、
 自動統計収集の詳細は以下のパラメータで設定できる。
 -GATHER_STATS_JOB
  自動統計収集のジョブのスケジュール設定
 -DBMS_STATS.GATHER_DATABASE_STATS_JOB_PROC
  統計取得内容の詳細の設定
 しかし、ミッションクリティカルなシステムでは、
 意図せずオプティマイザ統計(やそこから生成される実行計画)
 が変更されることを受け入れられないこともある。
 その場合は、自動統計収集をオフにし、
 手動で統計収集を取りメンテナンスする必要がある。
 
・統計再収集時の注意点
 統計を再収集することで、却って不適切なオプティマイザになるリスクがある。
 そのリスクを回避するためには、統計取得時に以下に注意する必要がある。
 -統計収集対象に漏れがないこと
 -適切なサンプルサイズで統計が取られること
 -データの変動に応じた適切な頻度で統計が取られること
 -システムの利用状況に応じて統計が取られること
 -統計情報のインポート/エキスポートにより、統計情報のバックアップをすること
 
・動的サンプリング
 事前にオプティマイザ統計が取得されていない表に対して、
 ハードパースを行った際、動的に統計情報を収集することができる。
 (デフォルトではこの設定がONになっている)
 統計情報収集時のオーバーヘッドは無視できないものの、
 データ量が少ない一時表に対してはこのオーバーヘッドが少ないため効果が高い。
 また、列同士の相関関係(例:JOB='MANAGER'だとSALARYが高い)を
 考慮できるというメリットもある。
 
・実行計画の固定
 使用頻度や重要性が高いSQL文に対しては、
 実行計画が変更されないように固定することが有効になる。
 ヒント句の記述やプランスタビリティの機能で固定が可能である。
 
・自動チューニングオプティマイザ
 自動チューニングオプティマイザを使用することで、
 性能面で問題のあるSQL文の自動検出が可能になる。
 自動検出されたSQL文について、どのような点が問題なのかも知ることができる。
 

IT業界での業務知識の重要性

昨日の記事ではアクセス履歴の話から業務知識の話まで脱線してしまいました。
せっかくなので、業務知識の重要性について別記事で書きたいと思います。
 
前職では、証券総合取引システムを開発する元請け企業で保守開発を担当していました。
金融系のシステムは金融庁が定める複雑なビジネスルールを網羅する必要があるため、規模が大きくなり、自社の社員だけではシステムを完成させられません。特に製造やテストといった末端の作業では人手が必要です。
そこで協力会社に技術者派遣を依頼するのですが、自社の社員ではないため、派遣される技術者の知識レベルや技術力はまちまちです。
この問題に対処するため、このような大きなシステムの開発には独自のフレームワークが用いられ、誰が作業しても同じような成果物が上がるように仕組み化されています。
(これは私の勤めていた会社がたまたまそうだったという話ではなく、日本のIT業界に通じる一般論です)
 
このような背景があるので、「言われたことをコードに起こしてテストできる」というレベルの技術者であれば、仕事にありつくことができます。
しかし、このレベルに留まったのであれば、二次請けや三次請けの、あまり条件の良くない仕事しか取ってくることはできません。
実際に、私が前職で直接やり取りしていたIT企業は以下の2つの内のどちらかの条件を満たす企業でした。
 
①パッケージベンダー
②業務知識に強みがある協力会社
 
①について具体的に言うと、独自のフレームワークに組み込めるようなパッケージや、証券総合取引システムと連携できるインターフェースを持ったパッケージを開発する会社のことを指しています。
自社パッケージを作成し取り入れてもらうためには高い技術力が必要になります。
(偉そうに言っている私も、残念ながらパッケージ開発を主導できるような技術力は持っていません)
 
②に関しては、言い換えると「言われたこと」を超える判断ができる技術者を派遣できる協力会社のことを指しています。
そのシステムに関する業務知識がなければ、「言われたこと」が正しいのかどうかの判断がつきません。
しかし、業務知識があれば、どのようなシステムを作るべきか自分の中でイメージすることができるため、要件定義や仕様策定にも関われますし、末端の作業をするにしても仕様の誤りやテスト結果の妥当性の判断を行うことができます。
技術力が多少足りなくても、そこはフレームワークで補われます。特定の言語しかわからない(知らない技術には抵抗感がある)、というのでなければ大丈夫だと思います。
 
私が昨日提案した「金融業界の業務知識を身に付ける」というのは、②の方向性を目指すための提案です。
COBOLで新しいパッケージを作る理由はないと思うので、COBOLを勉強する時点で②の方向性を目指すことになるとは思います)
 
なお、未経験の状態からスタートする場合、業務知識を身に付け知識を有していることを外に示すためには、その業務に関する資格を取るのが良い方法だと思います。
例えば証券業界では証券外務員という資格があります(私も持っています)。

アクセス履歴を見て思ったこと

少し生々しい話になるのですが、当ブログのアクセス履歴を見て気付いたことなど。
途中から話が飛躍するのは仕様なので気にしないでください。
 
ブログを始めた当初は1日あたり10PVも行かなかったのですが、ある記事を書いた後にアクセス数が伸び初め、今は1日あたり30PVを超えるようになりました。
そのある記事とは、「Windows上にopensource COBOLの環境を構築してみた」という記事です。
 
実際、Windows上にCOBOLの開発環境を作ろうと思うと大変です。
そもそも参考になるページを見つけるのが大変です。諦めているページもありました。
参考になるページを見つけたとしてもエラーにぶち当たるのはザラで、都度自力で調べながら進める必要があります。
今回の記事は、最も参考になるページを紹介し、足りない所を補足するという形で作成しました。
多くのことは紹介先のページに書いてあるため私が書いた所は僅かなのですが、そのような記事でも誰かの参考になっているのなら幸いです。
 
また、アクセス先のページとしては、COBOL環境構築の記事以外も満遍なくアクセスされている感じでした。
強いて傾向を言うなら、COBOLの記事はどの記事もアクセスされているというのはありました。
実際、COBOLの情報は少ないので、調べものをする時に困ったりします。
学習する際も、経験者が近くにいなければどこから手を付けたらよいかわからないかもしれません。
 
COBOLは信頼性が求められる金融業界を中心に、今でも使われている言語です。
近年では「メインフレーム環境をオープン化した」「COBOLを一掃した」といったかっこよいニュースをよく耳にしますが、実態としてはCOBOLやJCLで書かれたコードをエミュレートして動かしていたり、言語こそ最新の言語でも中身のロジックはまんまCOBOL&JCLだったりします。
(移行時のリスクや開発者のスキルチェンジの問題を考慮してそのような形になっているものと思われます)
しかし、COBOLは今でも使われる言語でありながら、これまで挙げてきたように学習する環境が整っていないという問題があります。
この問題を克服することができれば、会社や私自身の強みになるのでは、と思いました。
 
COBOLを強みにするなら、金融業界の業務知識を一緒に身に付けるのも一つの手です。
現に、金融業界での経験や業務知識を強み(コアコンピタンス)として前面に押し出し、良い条件の仕事を取ってくる企業は珍しくありません。
小さいIT企業を成長させる一つの方向性としてはアリなのではないかなと思っています。

COBOLでのデータベース連携概論

COBOLOracleDB2等のリレーショナルデータベースと連携することが可能です。
単に opensource COBOL を入れただけだとデータベース連携はできませんが、書き方の簡単な紹介だけでもしてみます。
 
【参考文献】
今回の記事は以下のページを参考にして作成しています。
COBOLOracleと接続する際のマニュアルです。
 
ProCOBOL プログラマーズ・ガイド -- 目次

http://otndnld.oracle.co.jp/document/products/oracle10g/102/doc_cd/appdev.102/E05652-01/toc.html
 
【基本的なプログラムの作り方】
業務プログラムを製造する者としては、最低限以下の文法を抑えておけば良いでしょう。
以下の文法だけでは不十分ですが、これで足りない分は現場毎で補足されるはずです。
 
・単発のSQL発行
以下のように EXEC SQL文でSQL発行が可能です。
:がついている変数はCOBOL中で定義された変数(ワークエリア)を指しています。
SELECT文のINTO句はSELECT文の発行結果をCOBOLの変数に入れるためのもので、ENAME列の値がEMP-NAME、JOB列の値がJOB-TITLE、SAL列の値がSALARYにセットされます。
 
以下はSELECT文を発行する例ですが、INSERT文やUPDATE文やDELETE文、COMMIT文やROLLBACK文も発行可能です。
 
なお、本当はSQLの戻り値に応じたエラーハンドルやNULL値が返された場合のロジック(多くの場合はLOW-VALUEに置き換える)が必要です。
また、複数行返されるSELECT文の場合は、後述するカーソルが必要です。
 
     EXEC SQL EXECUTE
     BEGIN
        SELECT ENAME, JOB, SAL
            INTO :EMP-NAME, :JOB-TITLE, :SALARY
            FROM EMP
            WHERE EMPNO = :EMP-NUMBER;
     END;
     END-EXEC.
 
・カーソルの使用
複数行返されるSELECT文を発行する場合は、カーソルを使用して1行1行取得する必要があります。
 
まず、下記のようにCURSOR文を発行し、カーソルを定義します。
下記の例ではカーソル名は「EMPCURSOR」になります。
 
     EXEC SQL DECLARE EMPCURSOR CURSOR
         FOR SELECT ENAME, JOB, SAL
         FROM EMP
         WHERE DEPTNO = :DEPTNO
     END-EXEC.
 
次に、定義したカーソルをOPENします。
これでデータ取得が可能になります。
 
     EXEC SQL OPEN EMPCURSOR END-EXEC.
 
次に、SELECT文の結果をFETCH文で1行1行取得します。
(ロジック中では、ファイルで言うREAD文と同じように、1件先読み及びループ中で使用します)
 
     EXEC SQL FETCH EMPCURSOR INTO :EMP-NAME, :JOB-TITLE, :SALARY  END-EXEC.
 
必要な結果をFETCH文で取得したら、最後にカーソルをCLOSEします。
 
     EXEC SQL CLOSE EMPCURSOR END-EXEC.