Ajax synchronousの威力

先週木曜日から土曜日と神戸国際会議場および展示場において、CCT 2019が開催されました。あいにくの雨でしたが、企業協賛がありそれなりに人は集まっていました。

その初日夜に、さくら会 高橋病院において鎌倉ライブ臨時実行委員会を開催しました。ここで、例の Ajax async: false を実際に多量データ入力で用いたのです。まるて field testingでした。

結果は? ばっちりでした。やはり僕の予想したように、これまでのつまづきは、Web Browserが非同期で動作していたからなのです。ここでの「非同期」の意味は、Browserの main threadが、各プログラム単位の関数の戻り値を待たずに、その要求を Queに置くだけで、さっさとプログラムを次のものに変更していく、そんな意味です。これは見かけは turn overが早く、ユーザーは待たされません。

しかしながら、必要なデータを受け取らずに次のプログラムユニットに移行してしまう、ということなので、databaseより適切なデータもらう場合にはまずいことになるのです。そこで、同期が必要なのです。つまりmSec単位で戻り値を待つのです。

これを行ったところ、懸案の web databaseとのやりとりでのデータ欠損問題は全て解決しました。ものすごい威力です。データ入力が本当にスムーズに動作するようになったのです。

Ajaxに悩んだ二年間

現代のWeb PageはAjax通信を用いてページの書き換え無しに表示データを更新する仕組みが広く使われています。Ajax = Asynchronous JavaScript and XMLという訳の分からない言葉の頭文字をつなげた造語です。Ajaxが提唱されたのは、古く Internet Explorer5.0の時代に遡ります。ここいら辺に関しては、やはり Microsoft社とIBM社の功績が大きいようです。このIBMのエンジニアが投稿されたブログに詳しく書かれています。

僕もjQueryを用いてこのAjaxという仕組みを用い、データをデータベースから読み出しそれを用いてホームページのDOMを書き換え、動的にページを画面更新無く刷新するようなページをいくつも作成してきました。実はこれもIBMのエンジニアのブログを読んで出来るようになったのです。

さて、jQuery + PHP + MySQLを用いたAjaxはこれまでに色々なサイトで作成してきました。そのほとんどは期待した通りに動作してきたのですが、一つだけ躓く場面があったのです。現在の鎌倉ライブHpは2017年に原型を作り、それを踏襲してきたのですが、基本的概念は、Web上のMySQL databaseにデータを入力して、ユーザー・ページではその databaseからデータを読み出してHpに反映する、そのようにしたのです。

もちろん DBにデータ入力する時にはPWで保護された部分にアクセスし、一般ではアクセスできないようにしています。この時問題となったのは、下記のプログラム部分です。それが不思議なことにうまく行ったり、行かなかったりするのです。

 function ajax_search() {
$( "#search_results" ).show();
var search_val = $( "#search_term" ).val();

$.post( "tri_chair_mod_add01new_backend.php", {
    search_term: search_val
}, function ( data ) {
    if ( data.length > 0 ) {
        $( "#search_results" ).html( data );
    }
} );

  }

これが時にうまく動作して時に動作しないのです。この原因についてどうしても難しすぎて分からなかったのですが、色々考えている内に、Ajaxとは Asynchronous (=非同期)とうのが本質だと思ったのです。Web pageは非同期で表示していかないとユーザーが待たされることになります。ですから、ある画面を描く時にも、あるいはデータを受け取る時にもどちらかがどちらかの完了を待つ(=同期)することが無く、どんどん進んで行くのです。これが原因ではないかと思いました。そこで以下のように変更したのです。

  function ajax_search() {
$( "#search_results" ).show();
var search_val = $( "#search_term" ).val();
        $.ajax({
            type: 'POST',
            url: "tri_chair_mod_add01new_backend.php",
            dataType: 'html',
            data: {
                search_term: search_val
            },
            async: false,
            success: function(data) {
                if ( data.length > 0 ) {
       $( "#search_results" ).html( data );
                }
            },
            error: function(XMLHttpRequest, textStatus, errorThrown) {
                alert("Ajax error happened!");
            }
        });
  }

つまり、Ajaxのdefaultである async: trueというのを敢えて async: falseにしたのです。つまり同期をとるようにしたのです。これで長年の懸案が解決しました。とっても難しい概念です。

こんな馬鹿なことで1週間潰した

さて、今から本格的にプログラム書こうと思っているのが、2019年に学会長を行うように指示されといるとある学会があるのですが、そのいわゆる学会プログラムやその他諸々を handlingするソフトの開発なのです 当然のことながら Smart Phone/Tablet/PCの全てに対応するように “Responsive Web Design”で開発するのです DBは慣れている MySQLを使用し、言語もこれも慣れている PHPを使用します

こんものいちなり書けないのでテスト・プログラムを作成し、local web serverでテスト繰り返すのですが全く作動しないのです

「えーーっ、なんでぇーーー こんな筈は無いはずだあ」と一週間悩んだのです 少しずつ修正しながらテストするのですが全く僕の意図を無視して動作しないのです

まあこんな感じです

// ここれはフロントエンドで SQLに探索語を渡す Ajax通信のルーチン
    $( document ).ready( function () {
      $( "#search_results" ).slideUp();
      $( "#search_term" ).keyup( function ( e ) {
        e.preventDefault();
        ajax_search();
      } );

      function ajax_search() {
        $( "#search_results" ).show();
        var search_val = $( "#search_term" ).val();
        $.post( "dr_role_find_backend.php", {
          search_term: search_val
        }, function ( data ) {
          if ( data.length > 0 ) {
            $( "#search_results" ).html( data );
          }
        } );
      }
    } );

 

そして受け取る方は、PHPとMySQLです

 session_start();
 session_regenerate_id(true);
 require_once('../utilities/config.php');
 require_once('../utilities/lib.php');	
 charSetUTF8();
 //接続
	try {
   // MySQLサーバへ接続
  	$pdo = new PDO("mysql:host=$db_host;dbname=$db_name_sessions;charset=utf8", $db_user, $db_password);
 // 注意: 不要なspaceを挿入すると' $db_host'のようにみなされ、エラーとなる
 } catch(PDOException $e){
   		die($e->getMessage());
 }

 $hp_name = strip_tags(trimBothEndSpace(mb_substr($_POST['search_term'], 0, 100)));	// 前後のspaceなど削除し、文字数を100文字に制限する
 $hp_name = strtoupper(mb_convert_kana($hp_name, 'ashK'));		// 半角英字大文字に変換する

 $stmt = $pdo->prepare("SELECT * FROM `hp_tbls` WHERE `hp_name` LIKE :hp_name ORDER BY `hp_name` ASC;");
 $stmt->bindValue(":hp_name", '%'.$hp_name.'%', PDO::PARAM_STR);
 $flag = $stmt->execute();
 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
 
 if (!$flag) {
   		$infor = $stmt->errorInfo();
     exit($infor[2]);
 }

 

これで、検索語として病院名の一部を入力すれば、DBより検索してくれる筈なのです

しかし、しかし動作しない 本当にこの解決に一週間かかり、先程やっと解決しました

色々な問題があったのです まずは

trimBothEndSpace(mb_substr($_POST['search_term'], 0, 100))

という関数ですが、(1) mb_substrの引数を何時の間にか消去してました つぎに(2) trimBothEndSpaceという関数ですが、これは自作関数なのですが、それをlib.phpに作成してあり(ある筈)、それを読み込んで使用するのですが、何と lib.phpの中にこの関数を書いていなかったのです

この2つのバグのために、phpそのものが走らず結果的に echoで途中経過を出そうと思っても出せない そんな事態に陥っていたのです 本当に大変なバグ退治でした これも Ajax通信によるプログラムだからのことです 本当に非同期通信というのは難しいです これが解決してうまく動作しているデモ画面です

うまく Ajax通信が動作しているところ

Distal Radial Approach (DRA) vs Conventional Radial Approach (CRA)

さて、そろそろこの秘密のテクニックについて公表する時が来ました 何れにしてもライブでは皆の眼に触れることになるのでこれ以上秘密にしていても仕方ありません

DRAに関しては最近僕が推進している三文字略語ですが、未だ主流とはなっていません しかし、臨床試験を企画していますのでそれで主流となるでしょう dTRAとかも使われていますし、PPA (Princeps Pollicis Artery) Approachとか、も使われています これに対して通常の橈骨動脈アプローチについては、区別するために、僕は三文字略語として Conventionalを用いたいと思っています

さて、何故今 DRAが注目されるのでしょうか? 未だに経大腿動脈的冠動脈インターベンション (TFI: Trans Femoral Intervention)にこだわっている頭の固い先生方はここでは相手にはしませんが、経橈骨動脈的冠動脈インターベンション (TRI: Trans Radial Intervention)の優れた点は世界中で明らかになっています しかし、その最大の欠点は術後の橈骨動脈閉塞 (RAO: Radial Artery Occlusion)です これはTRIが生まれた時から悩ましき問題として注目されていました 既に論文にもなっている僕が仕掛けた大規模医師主導型臨床試験である RAP and BEAT trialでもこの点が Primary Endpointとされました

さて、DRAにおいては穿刺部位が何しろ CRAよりも末梢であるため、原理的にRAOが起こる可能性は低いと考えられます しかし、問題は何しろ新しい方法なのでデータがありません 想像のみで医療はできません そこで、僕はこの問題を解決するために無作為臨床試験を規格しているのです これに参加して頂ける施設と医師を求めています もちろん医師主導型臨床試験ですので、基本的にはボランティアとしての参加です 真実を知りたい、という知的意欲の下で参加して頂きたいのです

徐々にその全貌を明らかにしていきたいと思います 例によって、症例登録は Webで行います お金が無いとか色々ありますので、例によって僕が自分の知識を駆使して、html5 + css3 + Javascript + jQuery + Ajax + SQL + PHPでその全てのプログラムを書きます というよりも、既に成功裏に終了した RAP and BEAT試験のプログラムを改変するのです これが、僕が次に考えている大きな仕事です

目標としていた9月1日に何とか間に合いました

鎌倉ライブデモンストレーションのHome Pageの全面改訂を8月の10日頃から行ってきました ある程度公開するのを9月1日と目標設定していたのですが、何とか間に合いました

http://kamakuralive.net/

大きなバグはとれていると思います このページの特徴は、SQL databaseに色々なデータを別の保護されたページにより登録すれば、それが自動的にこのページで更新されていく、ということです

鎌倉ライブデモンストレーションの詳細については未だ確定できない部分も多く、かといって全く分からないままで放置しておくことも良くないので、このような構造にしたのです

僕にとってこれは長年のライブデモンストレーション生活の中での最適解の一つなのですが、それをどのように実現していけば良いのか、それを解決できるだけのスキルも知力も以前の僕にはありませんでした しかし、今は違います これをやり遂げるだけの能力を習得したのです 嬉しいな

これもTAVIがすんなりと治療できるから可能なのです ありがとう SAPIEN3

洗練化するデータ構造

鎌倉ライブデモンストレーションの公式Web Site構築中です こっそりと現在の姿お見せすると

http://kamakuralive.net/23rd/db_read/come_session_all_read.php

となるのですが、もちろん公式には未だ公開していません

このページの特徴は、参加して頂く方のデータを別のページでdatabaseに登録し、そこから読みだしているのです 従ってそのページにアクセスする方々は、常時データを更新することができ、それが瞬時に反映される、ということなのです さらに、データ構造を工夫してあり、たとえば ◯◯さんがどの時間帯に dutyがあり、それがぶつかっていないかどうかもすぐに判明できる、というものにしてあるのです このデータ構造を創造するのには随分と頭を回転させました 知力の勝負ですね

ついに実現しました

本日はCVIT九州沖縄地方会でのサテライトに呼ばれています ここ10年間近く毎年この夏には呼んで頂いています まあ年の功でしょうか?

でも同じ会において毎年呼んで頂いて毎年何らかの話をする、というのは結構辛いものがあるのですよ 毎年何かしら新しい視点を提言させねばならないのです

という訳で暫くしたらば羽田空港から福岡に飛びます

この二日間悩んでしたプログラムが解決しました Ajax通信を用いてページ遷移無く、列名ボタンに応じてクリックする度に、自動的に並び替える、という良くあるインターフェースの実現なのです

久しぶりに jQueryを用いた Ajax通信プログラムを書いたので、昔のことは完璧に忘れており、調べなおしたり大変でした しかし、苦労は報われる、まるでここ数日間の日本選手による金メダル獲得のようです

結局何が悪かったか ことは簡単でした 動的に<Table><th></th><tr><td>・・・</td></tr></table>を生成しているのですが、この中で当然のことながらボタンも生成します しかし、どうしてもそのボタンをクリックしても、click eventが発生していないのです

これには随分と苦しみました jQueryの APIである .live()は既に廃棄されているようであり、現在では .on()に取って代わったとのことです それで .on()を用いて動的生成後にevent handlerをつけてみたりしたのですがどうしてもうまく行きません

ふと気が付き、これまでは

$data.= '<form action="***.php" method="post">';
$data.='<td>';
$data.='<button type="button" name="**">Name</button>';
$data.='</td></form>';

としていたのを

$data.='<td>';
$data.= '<form action="***.php" method="post">';
$data.='<button type="button" name="**">Name</button>';
$data.='</form>';
$data.='</td>';

のようにしたのです 要するに <form></form>要素を <td></td>要素の中に入れたのです 今までこんなこと関係ないだろうと思っていたのですが、それが大間違いでした こうすることにより無事 event handlerもそのまま継続され、思うどおりの動作をするようになりました

大分と理解が進んできたぞーっ

朝6:00AM前に起床し、新古賀病院にPCIで訪問するまでの そうですね実質 1.5時間ぐらい懸案のプログラミングに挑みました

必要要件としては

  1. サーバー側のデータベースから施設あたり登録症例数を取得する
  2. 取得したデータを JSON(JavaScript Object Notation)形式でクライアントに ajax通信する
  3. クライアント側では ajax通信により JSON形式データを取得する
  4. 取得した JSON形式データを加工する
  5. それをグラフとして出力する

というものです まずは1.ですね ここは MySQL database serverに対して SQL文で問い合わせを行います 具体的には

 	try {
    // MySQLサーバへ接続
   	$pdo = new PDO("mysql:host=$db_host;dbname=$db_name;charset=utf8", $db_user, $db_password);
	} catch(PDOException $e){
    	    die($e->getMessage());
	}
	$sql = "SELECT `hp_tbl_id` as `ID`, COUNT(*) as `ENROLL` FROM `pt_tbls` GROUP BY `hp_tbl_id`;";
	$stmt = $pdo->query($sql);
	$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);	

これは、SELECT `hp_tbl_id` as `ID`, COUNT(*) as `ENROLL` FROM `pt_tbls` GROUP BY `hp_tbl_id`; という SQL文により、MySQLに対して、`hp_tbl_id`毎にカウントした数を数えさせているのです

そして、その結果は、$rowsという配列オブジェクトに格納されます しかし、ここでのプログラミング言語は PHPですので、これを JSON形式に変換しないと、その後のデータ処理ができませんので

$json = json_encode($rows);
	
header('Content-type: application/json; charset=UTF-8');
	
echo($json);
exit;

によって、$rowsという php配列オブジェクトを JSONに変換しています そして、 echo($json); という文により、JSON形式のオブジェクトがクライアントに対して通信されているのです ここまでを行うプログラムはサーバー側のものであり、言語は PHPを用いています このプログラム・ファイルを get_each_h_enroll.php としました

次に、これを取得する方のプログラムですが、これはクライアント側のものであり、あくまでも htmlで書かれています ここではファイル名を each_hp_enroll.htmlとしました

ここでのキモは、d3.jsにより JSONデータ取得の ajax通信です それが

d3.json("get_each_hp_enroll.php", function(dataSet){
	var dataE = [];
	for (var key in dataSet) {
		dataE.push(dataSet[key].ENROLL);
	}

というものなのですが、d3.jsで定義されたJSON読み込み関数に従って、get_each_hp_enroll.phpより Ajax通信で渡された JSONデータを dataSetというオブジェクトに読み込みました

そして、それの中からデータとして使用する部分 – ここでは登録症例数 == ENROLLを配列 dataEに入れ込んでいます

後は、このdataEをもちいてグラフを描くだけですが、ここでは d3.jsの強力なデータ描画機能を用いるのです そのために、描画部分も d3という名前空間の中に閉じ込められています 従って さっきの部分も含めると

d3.json("get_each_hp_enroll.php", function(dataSet){
	var dataE = [];
	for (var key in dataSet) {
		dataE.push(dataSet[key].ENROLL);
	}
	
	d3.select("#myGraph")
		.selectAll("rect")
		.data(dataE)
		.enter()
		.append("rect")
		.attr("class", "bar")
		.attr("width", function(d, i) {
			return d;
		})
		.attr("height", 20)
		.attr("x", 0)
		.attr("y", function(d, i) {
			return i*25;
		})
});

ということになります

これを実行する = ブラウザで each_hp_enroll.htmlを開く と、以下のグラフが描画されます

DBから読み取り描かれたグラフ
DBから読み取り描かれたグラフ

これて見栄えは良くありませんが、とりあえずきちんと意図通りに作動するグラフが、SQL, HTML, Javascript, D3.jsを用いて描くことができました

ちなみに、一番重要な基幹技術は SVGなのです SVGというのは Scalable Vector Graphicsの頭文字ですが、その言葉通りに、 scaleできる == サイズを自由に変えることができる ベクトル化された描画 というものであり、HTML5の最新の技術なのです これが今使用されているブラウザで用いることができるようになり世界が変わったのですよっ

その話はまたね

心を鎮め清らかに

心が荒れるのは良くない それでも人間が未熟だから どうしても他者との関係の中で心が荒れる そんな時に人は色々な手段を使って心を鎮めるものです それが、宗教の領域にまで高められれば、座禅という型をとる場合もあるでしょう あるいは一心不乱に神に祈ることもあるでしょう あるいは五家荘の神楽のように神に捧げて一心不乱に踊る場合もあるでしょう

人それぞれ その人にあった方法で心を鎮めれば良いのです またその方法は一人にとって一つである必要は無く、色々な局面で色々な方法を適用すれば良いのです

などと言う前書きが長かったですが、今回僕はその方法として、「この際、理解不十分な部分を習得しよう」と思い立ったのです

実は RAP and BEATという国際共同多施設無作為化医師主導型臨床試験を運営しています 総登録症例数は 1,900例という規模のものです これはインターネット Web Siteを通じて無作為化および症例登録が行われるのですが、そのプログラム全体を僕一人で作成し、そして運用・改良しているのです

既に1,800例以上が登録され、もうすぐ閉じるのですが、大きなトラブルも無く運用されてきています もちろん securityには気をつけ、適宜データベースを backupしながら運用しているのです

前々から思っていて実現できていなかった interfaceとして、「ログインすれば、各施設毎の登録症例数一覧がグラフ表示される」という課題があります

どうすれば良いかは最初から分かっているのです

  1. クライアントがloginする
  2. クライアントの所属する病院IDをサーバーに投げる
  3. DB (database)を検索し、その病院IDおよび全参加病院ID毎の登録症例数をSQLで問い合わせる
  4. サーバーはDB問い合わせ結果をクライアントに投げる
  5. クライアントはそのデータ(Object)を解析し、グラフにする

ということです 3に関しては簡単です SQLさえ知っていれば簡単に一瞬で問い合わせ可能です 問題は4なのです ここではクライアントの画面が遷移しないように、ajax通信をせねばなりません その時には、通常 JSONというデータ形式を使うのが最近の流行りなのです

そして5ではグラフに描くのですが、ここでは javascript librariesを使用しますが、最近の流行りは D3.jsという libraryを用いるのです 問題はもう一方の Javascript librariesの雄である jQueryのようにふんだんに資料が転がっている訳ではないのです

問題点ははっきりしました 当初の課題は「D3.jsを用いて Ajax通信を如何に行うか?」という問題に帰着されたのです あるいは「D3.jsを用いて JSONをどのように扱うか?」と言い換えても良いです

そして苦闘24時間 ほぼ解決しました これで大きな一歩を踏み出せたのです 実際のコードは次回にでも掲載しましょう 何れにしても僕の心は鎮まりました