コード書くときのこのエディタの使い方が

docker compose up -d

わかるけど。ちょっと面倒だな。

つぶやく2024年3月17日

ろくでなしブルースもう一回読みたいな。高校1年のときめっちゃ教室で読んでたな。そしてえいちゃんの白い下敷き懐かしい。

今日はちょっとSharePointブログについて調べてみましょうかね。何かを調べながら試して、ノウハウを残すという行為をいっぱいするようになったのだけど、これをきっちりアウトプットする先がほしい。自社の社内ブログ標準のWordpressがサーバが弱すぎるのか遅すぎて、もうちょっとどうにかなってほしいのだが。いっそ外部のnoteとかQiitaを主戦場にしてみるかどうか。Sphinxをブログ風に使うような拡張機能もあるならそれもありだけども。

あとClaudeの件もちゃんと調べないとだし、昨日開発したSimpleRAGを自社のとこに置いてしまうハックもやりたいなー。

と言う前にゼロタッチのノウハウまとめをやらなければ。3月に全体脱稿をまず目指すか。やりたいことたくさんだなあ。

家のサーバの再構築 2024年2-3月

自宅で運用しているサーバの作りを、結構大きく見直した。ハードウェアは何も変わっていないけど。

まず、VMWare ESXiをやめた。それの上に色んなサーバ立てるのも楽しかったのだけど、1サーバごとにCPUコアの使用制限がかかっているのがどうも気になっていたので一度外してみることにした。KVMとか代替手段もあるようなので。いったんハイパーバイザ的なことはやめてUbuntuをクリーンに入れてみた。

しかし、それが簡単にはいかなくて、何が厳しいかというとPCIスロットにカード増設してインストールしたNVMe SSDにOSを入れてやろうとしたものの、どうもこの人はUEFIブートの出発点にできないらしく、LinuxをUSBメモリからそのドライブにインストールすることもできるのだが、起動画面でずっと空振りするようなことになってしまう。

Clover EFIという救世主らしきものに出会ったけど、これもダメで結局SATA HDDにインストールした。ここまででどえらい時間が溶けた。

そして、色んなアプリをインストールしていくのだが、すべてDocker ComposeでやってホストOSはできるだけ何もない状態に、というのを目指してみる。Dockerでやると、Composeファイルとかを全部Gitで管理して、設定ファイルも同じところにおいてVolumeとしてマウントしてあげることで環境がまっさらになっても結構楽ちんで同じものが作れる。データの永続化もHDDにしてから多重化しておくと安心。

これはこれで結構苦労しているけど、現状動かせているアプリケーションやサービスは以下。

  • 家庭内DNSサーバ (unbound)
  • nginxリバプロ
  • WordPress
  • PhotoprismとNextCloud
  • Gitpod (ここでサーバの資材やサービス、Docker関係のファイルを全部管理。簡易シェルにもなって便利)
  • Portainer
  • Gitlab
  • Splunk Free Lisence
  • NFS/SMB
  • Minecraft Bedrock のワールドサーバ
  • Ntfy

この後もうちょっとやりたいのもある。

  • 自前のChatGPT利用したRAGアプリをGradioで作る
  • Djangoで作る勉強用アプリのホスティングと開発環境
  • Mattermost

Mkdocsも手足のように使いこなせるようになっときたいなー。

子供にExcelと経営学について教える

なんでもいいので、お弁当配達サービス。

サービスの単価を設定。朝食とお弁当で300食。単価500円。週6。25 × 150,000で月間売上3,750,000円。

3人は必要で人件費60万円。

原価140万円。

光熱費など10万円。

税金。

広告、配達、パート。

調理場借りるの15万

減価償却費20万円。

なんだか利益出せるかな、くらい。

最近勉強できたこと2023下半期

  • 自動化の社内ツール
  • splunk
  • sphinx(ドキュメンテーション)
  • docker
  • mongodb
  • kubernetes
  • powerautomate
  • gitpod
  • gitlab
  • microsoft graph api
  • python
  • office script

やってみたが断念したもの

  • PowerApps、Dataverse
  • Nuxt.js

CakePHP 4: Consoleコマンドでバッチ処理、PHPのバージョンの切替

Cakephp 4で作ったアプリにバッチ処理も作り足したい場合はコンソールコマンドを使うことになるが、その使用例はこうなっている

$ bin/cake hello

自分が作業していた環境(RHEL)は、phpのバージョンが7.4と8.2がどちらもインストールされており、どちらも使っている。今回8.2で実行したいが、単純にシェルでphpコマンドを打つと今は7.4が有効なので

$ bin/cake
PHP Fatal error:  Your PHP version must be equal or higher than 7.4.x to use CakePHP. in /var/www/html/xxxxx/config/requirements.php on line 24

という感じでエラーが出る。そりゃそうだよね。

Webとかでもあまりはっきり書いてないけど、これで解決する。

$ php82 ./bin/cake.php
No command provided. Choose one of the available commands.

Current Paths:

* app:  src/
* root: /var/www/html/xxxxx/
* core: /var/www/html/xxxxx/vendor/cakephp/cakephp/

Available Commands:

App:
 - help

Bake:
 - bake
 - bake all
 - bake behavior
 - bake cell
 - bake command
 - bake command_helper
 - bake component
 - bake controller
 - bake controller all
 - bake fixture
 - bake fixture all
 - bake form
 - bake helper
 - bake mailer
 - bake middleware
 - bake model
 - bake model all
 - bake plugin
 - bake shell_helper
 - bake template
 - bake template all
 - bake test

Cake/TwigView:
 - twig-view compile

CakePHP:
 - cache clear
 - cache clear_all
 - cache list
 - completion
 - i18n
 - i18n extract
 - i18n init
 - plugin assets copy
 - plugin assets remove
 - plugin assets symlink
 - plugin load
 - plugin loaded
 - plugin unload
 - routes
 - routes check
 - routes generate
 - schema_cache build
 - schema_cache clear
 - server
 - version

DebugKit:
 - benchmark

Migrations:
 - bake migration
 - bake migration_diff
 - bake migration_snapshot
 - bake seed
 - bake simple_migration
 - migrations
 - migrations create
 - migrations dump
 - migrations mark_migrated
 - migrations migrate
 - migrations orm-cache-build
 - migrations orm-cache-clear
 - migrations rollback
 - migrations seed
 - migrations status

To run a command, type `cake command_name [args|options]`
To get help on a specific command, type `cake command_name --help`

Djangoの自動テストをあきらめた話

Python Djangoを使ってWebアプリを作り始めて、今まで自動テストをちゃんとやったことがなかったので、いい加減にこの機会にちゃんと学ぼうと思って、30-40時間を学習と試行に費やしたけど結局諦めたという話。

何のために自動テストを使うのか

テスト駆動開発くらいの言葉もあるし、Qiitaにはこんな素晴らしい投稿をされている人もいて概念自体はとてもいいなと思うものの、作業量があまりにも多すぎる。感覚的には、動くアプリを書いて画面をチェックして開発を進めるだけっていうのの3倍以上の時間がかかる気がする。PythonやDjangoでなくてもなんだって同じだろうなという気がする。

CI/CDなんて概念も、もはや世の中では当たり前だよというような感じで語られているし、自分は、とにかく回帰テストとしてDjangoのテストフレームワークを使いたかった。関数ベースビューが何十にもなって、モデルの数もどんどん増えていき、何か新機能を付けたりバグを修正したりした時に、既存のうまくいっているところが動かなくなるのを防ぐのには確かにうってつけなので。

改修する、それがうまくいっているかテストする、そのテストをWebブラウザを操作して目検で確認するだけでなくコード化する、蓄積されたテストをすべてブン回して何もかもうまくいくことを確認して、本番環境にリリースする。ということが毎回できればよいなというお話です。

学習したこと、試したこと(CLIベースのテスト)

Django付属のTestCaseから試したが、まずこのテストは大きく二つの目的に使える。
その1はモデルのテスト、その2は疑似ブラウザ(Client)を使った画面動作のテスト。

モデルのテストはこんな塩梅になる。

class CompanyModelTests(TestCase):

    def setUp(self):
        self.cp = Company(
            name="test company",
            since=timezone.now(),
            start_year='same',
            start_month=4,
        )
        self.cp.save()
        return super().setUp()

    def test_cp_count(self):
        cp = Company.objects.all().first()
        self.assertEqual(len(Company.objects.all()), 1)

Companyというモデルを1件Saveしてあげて、テストメソッド(test_cp_count)にて、Companyのモデルの数を数えてあげたらちゃんと1になるよね、というテストコードになる。Webのチュートリアルとかを見ても、これくらいのサンプルコードは山ほどあるので、理解はしやすい。

しかし、こんなテストを大量に作ってどこまで意味があるのかと、この作業を延々続けることがばかばかしく思えてしまう。この例はほぼDjangoのフレームワークをテストしているだけだ。じゃあ、Modelに自分で追加したメソッドをテストすればいいということにはそれは賛成なのだけど、結局そんなメソッド単体でテストしたところで、基本はViewのロジックがテストされないと意味ないし、Viewが期待通り動いてくれてるかどうかを見るのが大事なのに、部品のテストにそこまで時間をかけるのが正解かどうか。だいぶ包含されるし。

そして、Viewをテストするとなると、その2.疑似ブラウザ的なClientを利用したテストになる。これはだいぶいいものに思えた。

class CompanyDisplayTests(TestCase):

    fixtures = ['test_data_01']

    def setUp(self):
        self.p_ad = Person.objects.filter(pk=2).first()
        self.client.force_login(self.p_ad.user)
        return super().setUp()

    def test_company_top_suc(self):
        ''' company top normal show'''
        response = self.client.get('/pj01/company_top')
        self.assertContains(response, "Project and Workcodes")
        self.assertEquals(response.status_code, 200)

    def test_wctype_change_order(self):
        ''' wctype_change_order '''
        self.client.force_login(self.p_ad.user)
        data = {"form-0-id": "1",
                "form-0-cp": "1",
                "form-0-name": "Normal",
                "form-0-is_active": "on",
                "form-0-ord": "03",
                "form-1-id": "2",
                "form-1-cp": "1",
                "form-1-name": "AO",
                "form-1-is_active": "on",
                "form-1-ord": "20",
                "form-TOTAL_FORMS": "2",
                "form-INITIAL_FORMS": "1",
                "form-MIN_NUM_FORMS": "0",
                "form-MAX_NUM_FORMS": "20",
                "modify": "Save"}
        
        response = self.client.post('/pj01/mt_wctype', data)
        response = self.client.get('/pj01/mt_wctype')
        self.assertContains(response, 'Succesfully Saved.')
        self.assertEquals(response.status_code, 200)

DjangoのTestCaseでは、self.clientという疑似ブラウザが使える。この例では、’/pj01/company_top’というURLをGETリクエストして、その結果返ってきたHTMLに入っている文字列と、レスポンスのHTTPステータスコードが200であることを検証して、いずれかに問題があればテストがエラーとなる。

同様に、画面に対するPOSTをすることも可能。それが上記サンプルの中のtest_wctype_change_order。postメソッドで呼んで配列を渡してやることでWebブラウザからのデータ入力、そのあとのメッセージの検証や、例からは省略したがModelを使ってDBにデータが想定通り格納されたかを検証させることもできる。

fixtureというDBの基本マスターデータをロードして、毎回まっさらなデータベースを用意してくれる思想もなるほどなと思った。前回のテスト実行の結果でデータが変わっていたら同じ結果が得られないという悩みはない。

そして、こんなコードを手でいちいち書いてトライアンドエラーするのもまた時間がもったいないので、コードを書いたあとに手動でブラウザを動作させてテストしてあげるときにうまくログを吐き出させて、上記のようなテストコードへ流用する情報、主にURLやPOSTデータをTextファイルに吐き出すようにMiddlewareを作ってやることによってテストコードを作る手間を省力化させてもみた。

しかしそれでも、画面でテストした通りのことを、こいつにサクッとやらせるまでにはどうしても至らなかった。
いくつか問題があって

  • Fixtureのデータの中に日付項目があると、なぜかテスト実行時の出力結果にその日付がダラダラと出力されてくる。意味も分からないし、だいぶデバッグもしたが止める方法が不明。
  • Fixtureがすべてのテストに影響するとなると、気軽に直すわけにもいかないし、でもテストを追加するたびにどうしてもFixtureを修正したくなるし非常にストレス。
  • 自分でブラウザからマニュアルテストしてうまくいっている機能が、自動テストでうまくAssertを通らないときに、デバッグしているときの謎の労力(エラーが出てる瞬間のDBの状態も見られないし)
  • 日付関係がしんどい。2022年10月にうまく通っていたテストが2023年2月にコケて、それをまたトラブルシュートすることの空虚さ。
  • テストメソッドをまたぐとDBが初期状態に戻る。このテストメソッドで登録したデータを、別のテストメソッドで参照画面で見よう、と思ってもそうはいかない。結局、データを登録して、削除して、もう一度登録して、編集して、ステータスを変えて、参照画面で見たらここがこう変わってて・・・といったユーザストーリー的なテストは一つのテストメソッドの中にどんどん書き足す必要がある。そして、途中であきらめたけど、登録したはずのデータがなぜかうまく残らなくてテストが通らない。
  • これだけ色々な問題をクリアしたところで、結局人が目で見たときに「あれ、ここ思った通り動いてないな」と気づく力には勝てない。自動テストはassertで指示されたところしかチェックしない。assertを死ぬほど書けばいいし、Djangoの場合は返されたHTMLやステータスコードだけではなくてコンテキストに対してチェックをすることもできるしDBをModel経由でチェックさせることもできるのだが、これも労力があまりにもかかる。

Webで色々調べたけれど、どれもいい解決策に至らず、僕ちゃんにはCI/CDなんてまだ早かったのかな、落ちこぼれだな、と泣いた。何をどうやって見ても、回帰テストが1コマンドでブン回せるというメリットに釣り合うとはとても思えないほどの労力がかかると思われた。

Djangoのtestcase.clientはそれでもどうしても使いこなしたかったので粘った。Seleniumを使ったLiveServerTestCaseも存在は知っていたけど、こちらは気軽にテストが回せないのが気にかかった。本当のWebブラウザをスクリプト操作でテストさせる場合、完全に直列でテストが走るから、テストコードが蓄積するほどに待ち時間が長くなるのが必至。テストコード自体のテストみたいなのが発生するの明白だから、1回あたりの実行時間が長くなるのはどうも気が進まなかった。

でもそれでも、本当にやりたいことは
・VsCodeでアプリを書いて
・横でブラウザでそれを叩いてみて期待通り動作するかを見る
・うまく動いていれば開発を続ける、期待と違ったら修正して再度見る
・一通りうまくいったことを確認したら、ブラウザで確認した手動テストを自動テストコード化して回帰テストとして蓄積する
ということなので、Seleniumにも行ってみることにした

学習したこと、試したこと(LiveServerTestCase)

やりたかったことは
①VsCodeでアプリを書き、manage.py runserverしたテスト環境で叩いて機能を作っていき
②大体満足したところで、Selenium IDEを起動、開発したコードが一通り叩けるような操作をレコード
③それをやる過程で、Selenium IDEのスクリプトの中にAssertを仕込んでいく
④PythonコードをExportする
⑤DjangoのLiveServerTestCaseを継承したテストクラスにスクリプトとして取り込む
⑥テストコードがうまく動くことを確認したら、テストコードとして蓄積していく
という流れ。

②と③は大まかにはうまくいったけど、Assertに関してはHTTPのステータスコードを取得する機能はないことが判明。公式にも、それをやろうとしていること自体が間違ってるよ的な見解が。あれば楽なのになと思ったけど、<h1>タグとかみればええやん、って書いてある。

それではとあきらめてAssert Textを多用していくが、、、全文一致しかAssertが通らず部分一致やる方法がどうもなさそうだ。これもつらい。

Pythonコードを出力した後、LiveServerTestCaseにはめ込んだら一応動いているような気もするが

TypeError: expected str, bytes or os.PathLike object, not NoneType

動作はしているっぽいけど吐き出し続けられる謎のこのエラーは一体何なのか。ググっても何もわからない。

さらに動いている画面を見るとCSSとかが読み込めておらず何とも調子が出ない。これも直し方あるのかな。

あきらめることに

CI/CDとか自動テストがこんなに大変なものなのかと愕然とし、いったん使うのをあきらめることにした。Djangoとして機能がすでに十分そろっていて、自分の頭が足りなくて使いこなせていないだけなのか、世の中の皆さんは大変な労力をかけてちゃんとやっていらっしゃるのか、本当はまだ全然普及してなくてマニュアルテストが大半の世の中なのか、謎。

自動テストは、回帰テストでGetした画面が想定外のステータスコード返してきてないかくらいをチェックするくらいにとどめて、マニュアルテスト基本でやっていくことにする。

ひとことメモ(2022/12/8)

フォートナイトをチャプター3シーズン5は一切プレイしないことにする。うちのお兄ちゃんも受験だしちょうどいい。人を銃で撃って、よっしゃああとか言ってるのも野蛮だし。やらないって決めたら決めたで特に寂しくもない。

小学校の個人懇談いった。先生と大体認識一致。落ち着きがないのよね。

冷凍のシーフードミックスと、トマトとナスとしめじと人参とピーマン、塩とオリーブオイルと鷹の爪にニンニクとショウガ入れて適当に今煮ている。おいしいかなこれ。