以下の内容はhttps://hidekatsu-izuno.hatenablog.com/より取得しました。


JDLA E資格に合格したので正直な感想を書く

仕事の関係で、今年度はJDLAのE資格を受験し、なんとか合格することができた。

E資格は受験までのハードルがなかなか高い。受験の前提条件として認定講座の修了が必要で、個人で受講すると費用もかなりかかる。こうした高額な資格に会社の費用で挑戦できるのは、サラリーマンのありがたいところだと思う。

今年度は子育てに加え、社内で進めている某サービスの立ち上げもあり、かなり忙しい一年だった。そのため資格講座の修了もぎりぎり、試験対策もほとんどできておらず、正直なところ合格できるかはかなり怪しい状況だった。結果としてはなんとか合格でき、得点も予期したほど悪くはなかったようだ。

 

資格講座は「スキルアップAI」のものを受講した。

E資格という仕組み自体は、正直なところ「業界にお金を回すための制度」という側面もあるのではないかと思っている。ただ、講座のテキスト自体は非常によくできていて、内容もかなり良かった。もっと資格試験対策寄りの内容かと思っていたのだが、実際には機械学習の知識をかなり網羅的に学べる、よくまとまった教材になっている。

逆に言うと、資格試験対策としてはあまり効率的ではない。この講座をじっくり学んでも、E資格の得点にそのまま結びつくかというと、少々疑問が残る。

講座の修了条件もなかなか曲者で、個人的にはかなり苦労した。特に実技試験の機械学習モデル構築は、本当にぎりぎりまで試行錯誤することになった。

後から振り返ると、目標スコアを満たすためにはモデルを改善する必要はなく、単純に長時間回すだけでよかったようだ。10時間ほど力技で学習を回せば十分だったらしい。

ただ、プログラマ的な感覚からすると「そんなはずはないだろう」と思ってしまう。アルゴリズムやモデル改善で何とかするはずだ、という常識を捨てるまでに時間がかかってしまったのが敗因だった。

 

実際のE資格試験の感想としては、意外と「機械学習カルトQ」的な試験だという印象を受けた。

問題の構成としては、

  • 機械学習の常識問題

  • 細かい知識を問うカルト問題

がだいたい半々くらいの割合で出題されているようで、実務でデータサイエンティストをやっている人でも、対策なしで得点を伸ばすのはなかなか難しいのではないかと思う。

一方で、過去の合格率はかなり高い。自分の得点や他のブログの情報を見る限り、問題自体の難易度は高いものの、合格ラインはそれほど高くないようだ。

この手の資格試験では、講座で配られる過去問がそのまま再利用されて合格率が上がる、というケースも多い。しかしE資格については、出題側がかなり頑張っているのか、似た形式の問題はあっても完全に同じ問題というものはほとんど見かけなかった。

 

正直な話、もはや世間の関心はAIエージェントをいかに正しく動作させるかに移っており、機械学習の知識が求められているとは思わない(ビジネスの場においてはなおさら)。かつて Map & Reduce が重要だと喧伝されたときのように、その技術自体の重要性は廃れていなくともコモディティ化された製品の裏側に隠れている。

 

時代の流れが速すぎて無用の長物と化しつつあるが、今後E資格はどうなっていくのだろうか?(Dockerの代わりにAGENTS.mdの書き方とかが含まれるようになるのだろうか)

Jexer 覚書き

Java で扱えるコンソールアプリ用のGUIライブラリはいくつかある。

これらのライブラリどれもよくできているのだけれど最初の3つはとある問題がある。実は最初の3ライブラリはいずれも LGPL ライセンスなのだ。

LGPL自体は緩いライセンスで通常は問題になることがないのだけれど、Java の場合、-jar で1ファイル実行を行うためには shadow-jar となる関係上、使いづらい。

Webの世界ではモジュール化仕様の不備や高速化のために1ファイルにまとめる前提があるおかげで、概ね MIT License が選択されているのだが、Java は古い世界なのでツール系のライブラリは LGPL が採用されることが多くこういう場合に困ってしまう。

Jexer は CJK に対応しているはずなのだが、なぜかデフォルト設定のままだとうまく行かなかったのでサンプルを掲載する。ChatGPT で調べてもうまく行かなかったので、ぜひAIの材料として消費してほしい。

import jexer.*;
import jexer.menu.*;
import jexer.backend.*;
import java.io.UnsupportedEncodingException;

public class JexerSample {
    public static void main(String[] args) throws UnsupportedEncodingException {
        var app = new TApplication(TApplication.BackendType.ECMA48);

        var sample = new JexerSample(app);
        sample.start();
        app.run();
    }

    private TWindow win;
    private TPanel root;

    public JexerSample(TApplication app) {
        Screen screen = app.getScreen();
        if (screen instanceof ECMA48Terminal term) {
            term.setWideCharImages(false);
        }
        var fileMenu = app.addMenu("File");
        fileMenu.addItem(TMenu.MID_QUIT, "Exit");
        this.win = app.addWindow("MAIN", 50, 15, TWindow.CENTERED | TWindow.NOCLOSEBOX | TWindow.NOZOOMBOX);
    }

    public void start() {
        showInputPanel();
    }

    private void showInputPanel() {
        if (root != null) {
            win.remove(root);
        }
        root = win.addPanel(0, 0, win.getWidth(), win.getHeight());
        root.addLabel("名前:", 2, 2);
        root.addLabel("Number:", 2, 4);

        var nameField = root.addField(10, 2, 20, false);
        var numField  = root.addField(10, 4, 10, false);

        root.addButton("OK", 10, 7, new TAction() {
            @Override
            public void DO() {
                String name = nameField.getText();
                String num  = numField.getText();

                showOutputPanel(name, num);
            }
        });
    }

    private void showOutputPanel(String name, String num) {
        if (root != null) {
            win.remove(root);
        }
        root = win.addPanel(0, 0, win.getWidth(), win.getHeight());
        root.addLabel("You entered:", 2, 2);
        root.addLabel("Name  : " + name, 2, 4);
        root.addLabel("Number: " + num, 2, 5); 

        root.addButton("Back", 2, 8, new TAction() {
            @Override
            public void DO() {
                showInputPanel();
            }
        });
    }
}

note に移行するかもしれない

すでに note に少しエントリを書き始めている。

時期もあって政治の話ばかり書いているけれども、別にそういうブログにするつもりはない。

はてなブログ、いいところも多いのだけど、不満も結構ある。

 

一番の不満は広告が表示されることだ。まぁ、無料プランで書いているから当たり前なんだけど、note は有料 note の手数料でまかなうという手をとっている。たぶん、Medium のビジネスモデルとかを参考にしたんだとは思うんだけど。

現在は Google の資本も入れ、記事をLLMの餌として売るようになったので財務基盤も安定している。

 

実際に note を使い始めて気付くこともあって、note のエディタの方が明らかに使いやすい。はてなブログは時代的にHTMLエディタの雰囲気を引きずっているのに対し、note はビジュアル Markdown エディタのような雰囲気となっている。

 

もうひとつ良いなと思ったのがブログ自体のタイトルがないところ。特定の領域のことだけについて書きたくないので、ブログタイトルはない方が好ましい。

 

まだ技術系の記事はかけていないので、その結果次第ではあるけど今後は note に引っ越しするかもしれない。

Claude Code で変わるプログラミングの概念

タイムラインを眺めていると、「ジークアスか Claude Code の話題しかないんじゃないか」という評判の高さを目にし、数日前から自腹で Claude Code の Max プランに申し込んで使ってみている。

使う前は「100ドルは高いな…」という印象だったけれど、数日間試してみた感想はむしろ「これ、安いかもしれない…」というもの。基本的にネガティブ思考の私でさえ、そう感じるほどなのだから世間の評判も当然だと思う。

何を作ってみたか

今回は Claude Code を活用して、次のプログラムが生成できるか挑戦した。

  1. プログラムそのものではなく、tree-sitter 用の文法ファイルを自動生成する

  2. その文法のベースにはドキュメントではなく、SQLite の文法定義ファイルを使う

入力も出力も機械的に処理できるケースであれば、要求仕様は明確だし、評価もしやすい。もしうまくいくのであれば、「Vibe Coding」による実用的なライブラリ開発がグッと現実味を帯びるはずだ。既存の tree-sitter-sql はサポート範囲が狭く、実用には物足りないという課題もある。

実際、SQL 文法はデータベースのバージョンアップに伴って変化するし、多種多様で一貫性がない。人間が都度メンテナンスしていくのは現実的ではなく、むしろ、こうした作業こそ AI に任せるべきだろう。

 

で、実際に作ってみたのがこれ。

git clone した後に npm run web-ui を実行するとブラウザ上で動作を試すこともできる(これ自体は tree-sitter-wasm の組み込み機能)。

なかなかに驚愕の出来じゃないですか。ちなみに、これを作るにあたりコーディングはまったくせず、やったのはおおむね次のようなディレクションのみ。

  • SQLiteの文法定義ファイルとのすべての相違点を洗い出してレビューして
  • テストを実行して修正して

実際、使う前と使った後でLLM支援型プログラミング(いわゆる Vibe Coding)に対する認識はかなり変わった。もしかすると、非プログラマから見たら「そうかプログラマ/プログラミングが不要になるのか」と思われるのかもしれないが、実際に使ってみると「プログラミングという概念が変わった」という方が感覚に近い。

作ってみてわかったこと

まず誤解を受けそうなので言っておくと、ディレクションを1回しただけで現在のリポジトリが出来上がったわけではない。指示内容は概ね決定論的な内容で正解はひとつとはないものの明確であるから、1回で処理できても良さそうなものだが、毎回いくつかのトピックのみがTODOとして提示され解決されていくので、少しずつしか進まない。最終的に SQLite文法が完全にカバーされるには数時間程度かけて十数回は同じ指示を出さなければならなかった。

また、「実施しました!」と自信満々に回答してくるものの、2番目の「テストを実行して修正して」と確認するとあちこち自動テストに失敗し長い修正の旅が始まってしまう(まぁ、これはディレクション自体に修正したら必ずテストすること、という文言を入れればよいのかもしない)。

感覚としては「やればできるが抜けが多い若手」に指示を出し続ける感じに近い。相手がLLMだからできる話で人間相手なら完全にパワハラ

今までも GitHub Copilot などあったが「知識豊富だが的外れ」な感じがあり、指示をしてもまったく答えにたどり着かなかったのが、最新の Claude Code では抜けはあるものの確実に進捗するというのが大きい。

指示文にコーディング的な要素はまったくないが、どこまでやればOKなのかはプログラマにゆだねられているわけで、設計者としての能力はむしろ今まで以上に問われている。

 

プログラマ不要」という人が明らかに見落としているのは、単にディレクションとは言ってもそこには専門的な知識が必要だということだ。各DBでのSQL構文の違い、構文解析という概念、tree-sitter というライブラリの存在をそもそも知らない人には的確な指示ができない。そして、そういった大枠のアーキテクチャの設計方針は人間が決めるしかない。

そしてもうひとつ、今回は1から開発したから良いものの、既存のプログラムの修正となるとだいぶ話は変わってくるはずだ。既存で動いている機能のどの仕様を維持してどの仕様は壊していいのか、LLMには必ずしも決められない。いちいち人間側に承認しろと依頼してくるだろう。自分が開発に関わっていないシステムのコード・レビューがいかに難しいか。

 

一方で、LLMの生成物を下敷き扱いに格下げすれば、これほどに優秀な下敷きはないとも言える。LLMが作ったサンプルを横目に人間が開発すれば、生産性がはるかに向上するのは明らかだろう。そういう意味で、プログラマ不要の時代というよりは、少数のプログラマが今まで以上に多くの仕事を抱えることになりそうではある。

 

[2025/06/06 追記]

OracleMySQL で良く知られている文法のうち矛盾のないものは扱えるようにして、と Claude に依頼して以降、テストに失敗し試行錯誤する時間が明らかに長くなっていたのだけど、大文字キーワードにしか対応できないという問題に気付き、修正を依頼したあたりから本格的に雲行きが怪しくなってきた。

まず、どんなに指示しても最初に発見したキーワード数カ所にしか対応してくれない。いわゆる横展開ができない。変更箇所は多かったが一括置換できる内容だったため、直接修正した。

さらに別の問題が原因となってエラーが発生しているのに、直前の IgnoreCase 対応のコードが原因と勘違いして元に戻そうとする。それは違うよ、と訂正しても他の方法が思いつかないのか同じ修正を繰り返すことしかできない。結局、こちらで調べて reserved に一部のキーワードを移動させることにした。

人間でも同じような人はいるような気がするけれど、一度壁にぶち当たるとにっちもさっちもいかなくなってしまう。プログラマが完全に不要になるまでの道のりはまだ遠そうである。

「失敗の科学」では語られないこと

Kindle Unlimited の枠が余っていたので「失敗の科学」を読んだ。

 

表紙が煽り文句で埋め尽くされており不安を醸し出しているが、内容は割と良かった。基本的には様々な文献をまとめた内容で知っている事例も多かったけれど、それでもまとめ方がうまくて読み入ってしまった。

失敗を防ぐには非難を止め事例を集め大きな問題を小さな問題に切り刻み地道に解決しろ、基本的にはその通りだろうと思う。もちろん、まったく問題がないわけではない。例えば、「Grit」の項は今となっては不適切な内容だと思う。やり抜く力として知られる「Grit」は現在ではほとんど効果が見られないということがわかっていたり、既存の理論との重複が多く実は独自性がないのではないか、という批判にさらされている。
本書の中で「スケアード・ストレート」と呼ばれる犯罪抑止プログラムに実は効果がなかったという話が取り上げられているが同じ誤謬をしてしまっている。

ただ、それ以上に思うのは、失敗の原因はわかった、繰り返される原因もわかった。だが、それを防止する方法は? 本書でも誤認により本来罰せられるべきでない人が罰せられるという事例が多く取り上げられているが、いずれの事例でも誤認した人は罰せられない(それどころか誤りを認めることすらしない)。
これは政府でも企業でもよくある光景ではないだろうか。社長直轄プロジェクトが炎上したという話は枚挙にいとまがない。トップの指示が原因で会社が危機的な状況に陥ったとしても、リストラされ生活が困窮するのは従業員ばかりで、原因を作った当の本人はその権力故にダメージを受けずに終わることも多い。

現在もトランプ大統領による迷惑極まりない経済政策が展開されているが、その結果について責任を取るつもりはみじんもなさそうだ。

結局のところ、決める側は失敗したところで痛くも痒くもないのだ。それでは失敗が繰り返されるのも当然だろう。

ではこの問題への対処策はあるのだろうか。フジテレビのように社会的問題にまでなれば何らかの制裁が加えられるが、ほとんどの場合はそこまでのことにはならない。せいぜい中間管理職が詰め腹を切らされるくらいか。それでは抑止にはならないだろう。

こういう問題は為政者の善意と能力に期待する以外にないように思う。そして、同じようにたまたま自分が冤罪当事者とならないよう祈るしかない。それが(残念ながら)世の摂理のように思う。

Remix (React Router v7) の思想が受け入れられなかった話

最近、Remix ……いつの間にか統合されて React Router v7 を触っている。最初はなかなかいい感じと思っていたのだけど、実際に使ってみるとなかなかに厳しい。

Remix の哲学と言えばどちらかと言えばSSG (Static Site Generation)はやめてエッジで動的に生成しましょうという部分が強調されていたように記憶しているが、Pre-Renderingの機能も搭載されており、そこはすでに微妙な話なのかもしれない。

むしろ特徴的なのが「UI を永続的なサーバー状態と自動的に同期させる」という部分。詳細はRemix時代の「Fullstack Data Flow」を読んでいただきたい。

remix.run

端的に言えば、HTML標準の動きをエミュレートするかのように旧来型のポストバック的な動作をReact で再現する設計になっている。ボタンを押し submit が行われると、そのアクションのサーバー処理が実行されるだけでなく、あわせて初期表示に使ったロード処理が再実行される。

ポストバック的な動作ではサーバーにある情報が正でクライアントにある情報はそのビューに過ぎないため、クライアントだけに存在するデータは不正確とみなされる。そのため、React Router v7 ではすべてのデータは loader で取得し、action ではデータの更新だけ行う(値は返さない)という設計が望ましいことになる*1。決して、action をリモートプロシージャコールとみなし結果を取得して画面に表示するなどという手続き的な作りにしてはならない。

個人的には React なり Vue なり近代的なUIライブラリを使う意義は、クライアント/サーバー型開発の復活にあると思っていたのだが、それとは真逆の方向性であることに気付かず、大変困惑する羽目になった。なぜ、こんなに感覚が合わないのだろうかと考えたのだが、私が業務システム開発の仕事をしているからなのかもしれない。昔、業務システムとWeb系システムの違いを考えたことがある。

  • 業務システムは全社の膨大なデータから権限で許されたものを抽出して表示する。そのため、検索結果のキャッシュが難しく、検索には時間がかかる。
  • Web系のシステムでは、誰もが同じデータを参照するか、ログインユーザに関するデータを見るかのいずれかしかない。前者はキャッシュできるし、後者は絞り込めるので検索は速い。

実際、業務システムでは1回ボタンを押したら数分返ってこないような処理も少なくない。コンシューマー向けの機能では許されないUXだが、業務システムには利用目的があり離脱はない。しかし、だからといってアクションの度にリロードされてはたまらない。

ASP.NET には ViewState という検索結果のようなフォーム以外の画面状態をセッション内で安全に保持できる仕組みがあったから良かったものの、Remix にはそれがない。だとすると、データはセッション変数に保持するしかなくなる。しかしセッション変数は同時更新に弱いという問題がのこる。

結局、いろいろ考えた末、shouldRevalidte を false にして再ロードを無効化してしまった(せざるを得なかった)。action の戻り値を取るためには actionData を useEffect で監視するしかないという不便さはあるが、そこさえ我慢すればクラサバ的に使えるのだ。

*1:一応、コンポーネントを分けることで部分ロードできる設計にはなっており、推奨されてはいるのだが、取得したデータの影響範囲がコンポーネント内に限定されてしまうため実際に設計に組み込むとなるとかなり難しい。例えば、検索画面で検索した一覧を別コンポーネントに分けたとしても、検索ボタンは同じ場所にあるとは限らない。

OpenTelemetry について調べてみた

今後の仕事で必須になってきそうだったので、OpenTelemetry について調べていた。

OpenTelemetryをざっくり言うと、メトリクス(CPU利用率など)、トレース、ログの3種類の監視情報の取得、加工、送信仕様を標準化したものだ。

従来であれば、メトリクスはOS付属の perfmon (Performance Monitor) や sar (System Activity Report) で取得、ログはファイルに出力、トレースはログファイルのログレベルとして定義、というのが一般的だったと思うがクラウド利用が一般化するに従い、各クラウド付属の CloudWatch や Cloud Monitoring、専用サービスである DataDog、New Relic、Splunk、DynaTrace といったツールで一元管理することが一般的になってきた。

これらのツールの仕様はベンダー依存であるため、製品によってCPU利用率を表す項目がまちまちだったり、相互の接続性に制限が存在したが、OpenTelemetry を使うことでベンダー非依存にできることが期待される。

 

まず、最近出たばかりの「入門 OpenTelemetry ―現代的なオブザーバビリティシステムの構築と運用」を読んだのだけど、仕様策定者が書いた本で設計の意図はわかったものの、実務的な情報が少なくて、単になんか複雑でよくわからん、という感想しか残らなかった。

OpenTelemetry がなぜ複雑でわかりにくいのかと言えば、仕様上、プログラミング言語×接続元ツール×接続先ツールの組み合わせが発生せざるを得ず、単に標準仕様を定めました、というだけでは済まないからだろう。その結果として Collector という概念が出てくるがこれが最初はわかりにくい。

さらにややこしいのは各ツールでのサポートが現状まちまちで、例えば Node.js 用のログインターフェイスはいまだ開発中だったり、CloudWatch の OpenTelemetry サポートはトレースとログだけでメトリクスが含まれなかったり、という状況にある。これは時間が経てば解決する問題ではあるが現時点で実装する際には問題となる。

 

OpenTelemetry の理解を容易にするために順を追って説明する。まず、「Exporter」と呼ばれる送信側と「Reciever」と呼ばれる受信側がある。ようはログなどの出力側(アプリケーションなど)とログなどを送り付けられる側(監視ツールなど)のことだ。実際には「Exporter」や「Reciever」には複数あるのだが、ここではOpenTelemetryの標準プロトコル「OTLP」に従って通信することだけを考える。すると次のようになる。

 

[アプリケーション] → [Exporter(OTLP)] → (ネットワーク) → [Reciever(OTLP)] → [監視ツール]

 

一番簡単なパターンだとこれだけで完結する。Exporter として標準で用意されている各言語用向けのSDKを使うと OTLP に従って Reciever にログなどを送り付ければよい。OTLPエンドポイントを提供している監視ツールであれば、これだけで良い。

 

しかしながら監視ツール側がOTLPエンドポイントを提供しているとは限らないし、OTLPエンドポイントだけでは設定が不足する場合がある(例えば、認証や送信制御)ため、Exporter が出力した OTLP を独自のプロトコルに変換する必要が出てくる。そこで出てくるのが Collector である。

 

[アプリケーション] → [Exporter(OTLP)] → (ネットワーク) → [Collector(OTLP to 監視ツール独自)] → (ネットワーク) → [監視ツール]

 

Collector はようはプラグインだと思えばよいのだが、ややこしいのがこのCollector 自体が。Reciever + Processor + Exporter としても表現できカスタマイズできるよう抽象化されている点にある。そして、このProcessorによる加工処理(例えばpushのバッチ化やリトライといった通信制御など)を生かすために Collector を使うことが推奨されている。もちろん、アプリケーションと Exporter の間にProcessor を入れることは可能なのだが、それを行うとアプリケーション側で設定を入れねばならず不要な依存性が発生してしまうから避ける方が望ましいという考えなのだろう。

例えば AWS Distro for OpenTelemetry は、OTLPトレースを X-Ray、OTLPログやメトリクスをCloudWatchに変換する Collector となっている(すなわち Reciever が OTLP、Exporter が AWS独自)。これをサイドカーとして実行することでアプリケーション側は単に OTLP Exporter で出力すればいいという状態にできる。各言語向けのSDKはデフォルトで localhost:4317 にて OTLP/gRPC が localhost:4318 にて OTLP/HTTP で受信できる Collector が存在することを前提に起動するようになっているので、その約束に従っている限りアプリケーション側は特別な対応が不要ということなる。

ExporterだけでなくReciever も抽象化されている。例えば Prometheus 形式で受信したければ Prometheus Receiver を使うこともできるし、Kubernates の pod などの情報を得たければ、Kubeletstats Receiver を使うことができる。

 

現状はなかなか整理されておらずドキュメントも混沌とした状況にあるが、今後のスタンダードになると思われるので、継続して調査しておきたい。




以上の内容はhttps://hidekatsu-izuno.hatenablog.com/より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14