思い出して書くflaskのWebアプリ・システム☆(^~^)

あっぽっぽ☆(^~^) 公開下書き

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 今どきクラウドやるなら npm / Node.js ぐらい使うのが 平凡の真ん中 ぐらいだと思うんだが、
クラウド別にやりたくないし、誰も保守できないデスクトップ・アプリを 何か新しいものに移行したい……☆
そんなとき Java とか PHP / Laravel とか候補が上がるわけだが、言うこと聞かん坊のわたしが
Elixir ! Golang ! Scalar ! Type script ! とか ミーティングに ジャミング攻撃をするわけだぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 気違いだよな☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 なんで Rust にしないのよ、このヘタレ!」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 すると チームのみんなが知っていて、使える言語は Python という戦わない民主主義みたいな結果に落ち着くわけだぜ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 知名度 1位、2位を争う プログラム言語なのよ! 順当なのよ!」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 で、話しはさかのぼって 面接のときだぜ☆
何か質問は、という いつものやつで質問は適当な1つで済ませて ついでに ジョブ・ディスクリプション に 基本設計 を入れてもらっておいた☆
基本設計、詳細設計、作成、テスト 4つ入っている☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 お父んの開発スキルは わたし ぐらいしか 世に公開されてないだろ☆
Git hub を見ても 作りかけのクソ・コードばかり☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 わたしの派遣社員マンの価値としては だいたいの案件を できます、と言って取って できたり できなかったり することだからな☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 できるって言いましたよね!」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 …………☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 はいっ、差し戻しっ!」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 …………☆(パシッ)」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 もういいです! 引き取ります!(ぐいっ)」

KIFUWARABE_80x100x8_01_Futu.gif
「 お父んは 転職11回分の気違いネタは いっぱい持ってるよな☆
そのうちの7回 契約期間延長なし、クビになったときの会議室ネタとか 持ってるよな☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 もうかばうことはできません!の回とか、 もっと雑談をしてください、の回は面白かったよな☆
ウソは付かないでくださいの回も 外せない☆ 経営者が金持って逃げたことも☆
2004年頃の IT 下請け編 は わたしの社会経験が無い頃で、ウケる☆ 山ほどしゃべれる☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 で、 Ubuntu、 Nginx、 uWSGI、 Python3, Jinja2、 Pyodbc、 MSSQL という平凡な構成にしてみたわけだぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 わたしは知ってるぜ☆ その7つは お父ん 未経験だろ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 はい、できます☆ 得意です☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 得意ってんなら じゃあ やってみなさいよ」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 まず Ubuntu☆ コンピューター将棋選手権でカパックが使っているのを 見たことがある☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 はい、疑義! 見たことがある、 は、経験ではないのでは☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 …………☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 なんか アドリブを返しなさいよ!」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 できなかった こともあるが、 何もしないタイプよりは 少しは できることが多いだろ☆
ちょっとの差も 実務16年 続けば ある程度の差だぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 で、コンピューターについて 押さえておきたいことは 山ほどある☆
OS編、Web編、システム設計編 の3つぐらいに大きく分けれるだろうか☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 その3つとも お父んの専門外なの わらう☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 ツクールで 社内システムを作りなさいよ! Dante98 とか入れないの!?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 細かく見ると 次の通り☆」

  • OS編
    • FHSを覚えよう
    • ファイヤーウォールからポートを開こう
    • デーモンを走らせよう
    • プロセスを知ろう
    • パッケージマネージャーを使おう
    • レポジトリを知ろう
    • gitを知ろう
    • XAASを知ろう
    • カレント・ディレクトリを知ろう
  • Web編
    • RESTを知ろう
    • CRUDを知ろう
    • パスワードはアプリケーションに含めないようにしよう
    • JSONを知ろう
    • OAuth2認証を使おう
    • Microsoft Graphを使おう
  • システム設計編
    • 疎結合
    • 動的計画法
    • コード汚染してはいけない
    • ステートレス
    • ハンガリアンコード禁止
    • 特定のエディターに制限しない
    • Conventions
    • 正規表現

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ダメだ いっぱいある☆ まとまらん☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 もう寝ろ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 ほとんどのことは 他の人が記事にしているはずだから、あんたしか知らないことを選んだ方がよくない?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ほとんどの記事は 入門編とか言って 全然 説明足りないだろ☆
このコードは ベスト・プラクティスではない可能性があります、とか 書いてるだろ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 flaskr は チュートリアルのブログ・アプリケーションの名前だから 別の名前でもいいのに、
フォルダー名を flaskr にしてるだろ☆?
末尾の r って何なのか分からん☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 名前を考えるのも大変だし、 flaskr でいいだろ☆」

  • venv/
  • flaskr/
    • static
      • paginator.js
    • templates
      • index.html
    • app_module.py
  • app.py
  • uwasgi.ini

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 最初は だいたい これぐらいの ファイル、ディレクトリ から始まるだろ☆
これが だんだん 増えていくぜ☆
Python のモジュール・システムの分け分からん具合には 日を跨って悩まされた☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 というか、 Python2、3の違い、pip、venv に悩まされた☆ もうレガシーの名前は 思い出したくないぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 じゃあ すごく大事な話をするかだぜ☆ ディレクトリの分け方について☆」

  • flaskr/
    • base_type
      • uniform_resource
        • single_table.py
      • widget
        • paginator.py
    • customize_type
      • uniform_resource
        • single_table_with_list.py
      • widget
        • my_calendar_ver2.py
    • settings
      • account-master-table.json
      • location-master-table.json
    • static
      • paginator.js
    • templates
      • index.html
      • single-table.html

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 設定ファイルをいじるだけで上手く行きます、という手順書を書くために settings があるといい感じ☆
ただ、ファイル数が多くなると マイナス印象☆ 1つのファイルに 複数の違うものの設定を 共存して詰め込めるようにしておけだぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「  JSONって何☆? みたいなチームだとパーサーに苦しめられるぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 あとは base_type には わたしが作った模範となるものを入れて、
customize_type は誰でも勝手に改造したものを入れろということにする☆
恐らく プログラムの意味ではなく、チームの運用で分けた方がいいはずだぜ、結果は どうなるか知らん☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 本当は☆、」

ダメな例:

  • flaskr/
    • controller
    • model
      • dao
      • ds
      • dto
      • vo
    • view

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ みたいに 意味別で分けたいんだが、そうすると 『これは何ですか』 『これはどこにありますか』 みたいな
質問や、学習が増えてしまう☆
できれば ディレクトリー名に 専門用語は付けない 方が実践的だぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ディレクトリ名の極意は、 『わたしには関係ない』 『わたしには関係がある』 の2つだぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 そうか☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 メンテナンスや、引継ぎでは、ディレクトリ、全部 開けることになる☆
ディレクトリは 無ければ無いほど 実践的だぜ☆」

2020-03-19

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 JSON が使えるかどうかで 困難さは大きく変わる☆
.ini ファイルじゃないと嫌だ、という人もいれば JSON みたいな得体の知れないものは嫌だという人もいる☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 ぶつくさいいながら バリバリ JSON を使ってるじゃないか☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 最終手段として☆、」

{
    "apple": {
        "banana": {
            "cherry": 100
        }
    }
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ は☆、 ↓」

[apple]
apple_banana_cherry = 100

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 のようにする☆ 配列のイテレーションができなくなるが、まあ そのとき考えようぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 あとは メソッド名の種類は少ない方がいい☆
read とか get とか set とか、数を絞るべき☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 Power Shell みたいになるだろ☆」

./flaskr/settings/banana.json:

{
    "food" : {
        "snack": 100,
        "noodle": 110,
        "juice": 120
    }
}

app.py

banana = Banana().read('./flaskr/settings/banana.json', 'food')

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 見た目は よくてここまで☆
これ以上 むずかしかったら 驚き最小の法則 に反する☆ そもそも JSON であることがヤバい☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 ミニマル・コーディングに挑戦してんの?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 してる☆」

app.py:

if request.method == 'POST':
    banana.post(request)
else:
    banana.get(request)

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ これぐらいなら OK☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 Banana は Uniform Resource だったの?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 正確には Banana は 画面操作のよくあるパターンの1つだぜ☆ 型にあたる☆
Uniform Resouce は JSON で設定する☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 なんかもう この先 面白いことは無さそうに思える☆ 話題を変えようぜ☆?」

banana.py

from flaskr.base_type.banana_base import Banana as BananaBase

class Banana(BananaBase):
    def __init__(self):
        self.__creation = Creation()
        self.__reading = Reading()
        self.__update = Update()
        self.__deletion = Deletion()

    def read(path:str, section:str):
        settings = # Omit. Read section on file.
        self.__creation.set_settings(settings)
        self.__reading.set_settings(settings)
        self.__update.set_settings(settings)
        self.__deletion.set_settings(settings)
        return self

    class Creation(BananaBase.Creation):
        def execute():
            # Omit
            pass

    class Reading(BananaBase.Reading):
        def execute():
            # Omit
            pass

    class Update(BananaBase.Update):
        def execute():
            # Omit
            pass

    class Deletion(BananaBase.Deletion):
        def execute():
            # Omit
            pass

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 これぐらい 特に不思議はないだろ☆
コンストラクタで 例外が起こってほしくないので、ファイルの読み込みは 別メソッドにしてるぐらいで☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 1単語の変数名、メソッド名は 避けるんじゃなかったの?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 やさしく! YSSK!」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 オブジェクト指向は使わないんじゃなかったの? 継承していいの?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 post( )get( ) をグローバル関数にする手もあったんだが、ごちゃごちゃして嫌になったので、
やってはいけない例、 機能を継承させるだけの親クラス とかちゅうちょなく作るぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 まったく……☆」

2020-03-20

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ただ、コンストラクターで、使わないものまで メモリに展開するのは 大富豪だぜ☆
あとで CPU使用率が高い とか 言われるの 立腹 なんで……☆、」

class Banana(BananaBase):
    def __init__(self, operation):
        self.__reading = Reading()

        if operation == 'add':
            self.__creation = Creation()
        elif operation == 'update':
            self.__update = Update()
        elif operation == 'delete':
            self.__deletion = Deletion()

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 コンストラクターに フラグ1個 渡すのは 人権を主張しようぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 憲法で保障されていないのでは☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 read() もフラグだらけにならない?」

class Banana(BananaBase):
    def __init__(self, operation):
        self.__reading = Reading()

        if operation == 'add':
            self.__changing = Creation()
        elif operation == 'update':
            self.__changing = Update()
        elif operation == 'delete':
            self.__changing = Deletion()

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ じゃあ 抽象化しようぜ☆?」

    def read(path:str, section:str):
        settings = # Omit. Read section on file.
        self.__reading.set_settings(settings)
        self.__changing.set_settings(settings)
        return self

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ read() の行数も減る☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 黙って オブジェクト指向に従えばいいのに……☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 オブジェクト指向は使わず、プロシージャ言語程度の知識で、オブジェクト指向ぐらいの利便性を得るのが
社会で生きていくコツだぜ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 崖かどこかに その社会はあんの?」

./base_type/banana.py:

class Banana:
    @property
    def reading(self):
        return self.__reading

    @reading.setter
    def reading(self, val):
        self.__reading = val

    @property
    def changing(self):
        return self.__changing

    @reading.setter
    def changing(self, val):
        self.__changing = val

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ そういえば Python はプライベート・フィールドを継承できないのだった☆ 親クラスに プロパティを用意しておけだぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 Banana が Banana を継承したら 循環参照するだろ☆」

class Banana(BananaBase):
    def __init__(self, operation):
        self.reading = Reading()

        if operation == 'add':
            self.changing = Creation()
        elif operation == 'update':
            self.changing = Update()
        elif operation == 'delete':
            self.changing = Deletion()

    def read(path:str, section:str):
        settings = # Omit. Read section on file.
        self.reading.set_settings(settings)
        self.changing.set_settings(settings)
        return self

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 子バナナの文字数も さらに減っただろ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 オブジェクト指向は使ってなくても オブジェクト指向の継承の機能は使ってんじゃないの?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 もう この時点で かなり まずいコードだぜ☆
むしろ 親バナナは Python3 が不出来で必要になってしまうゴミ・コードです と言い張り、
self.changing はグローバル変数です とか 独自の説明をして逃げきれだぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 しかし あまり ゴミ、ゴミ 言っていると 本当に 消されてしまうんで
キャッシュ・ファイルです とか 逃げ道を残しておけだぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 やってることは インスタンスのメモリ展開と 設定ファイル読込の2つなんで、5秒ぐらいで終わらせたいんだが
雰囲気がまずくなると プロジェクトを引き上げ られたりするんで なるべく イカしたコード であることを強調しろだぜ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 read() ってメソッド名じゃ 通らないんじゃないの? made_by() じゃないの?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 プログラムのメソッド名の慣習に倣うと make_by() だな☆」

class Banana(BananaBase):
    def __init__(self, operation):
        self.reading = Reading()

        if operation == 'add':
            self.changing = Creation()
        elif operation == 'update':
            self.changing = Update()
        elif operation == 'delete':
            self.changing = Deletion()

    def make_by(path:str, section:str):
        settings = # Omit. Read section on file.
        self.reading.make_by(settings)
        self.changing.make_by(settings)
        return self

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 逆に プログラマーから 文句が出そうだよな☆ make_by() とか慣習にない☆」

app.py

banana = Banana().make_by('food', './flaskr/settings/banana.json')

if request.method == 'POST':
    banana.post(request)
else:
    banana.get(request)

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 make by とか聞きなれないから made by にしたくなるが、文系は黙らせようぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 もっと 適当にプログラム書いたらいかんのか……☆ こんなん5秒で流すとこだろ……☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 パッと見の 好き嫌い で決まるんだぜ☆
客は プログラムの知識でプログラムを見るのではなく、 本人の知識で本人の思ったプログラムを見るんだぜ☆!」

KIFUWARABE_80x100x8_01_Futu.gif
「 生産性はどこへ……☆ 作文でも書いてんのか……☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 だったら 上流に 理系が来い☆!」

./base_type/banana.py:

class Banana:
    def get(self, request):
        pass

    def post(self, request):
        pass

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 get()post() から ようやく コード・レビュー感が出てくるよな☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 150行を超えてると プロジェクトを引き上げるわよ」

./base_type/banana.py:

class Banana:
    def get(self, request):
        my_request = MyRequest().make_by_getted(request)
        pass

    def post(self, request):
        my_request = MyRequest().make_by_posted(request)
        pass

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 早速 さっき使った make_by() の亜種を作ろうぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 わたしの知見では、 request オブジェクトの中身はバラバラなので、中身を整形する振る舞いをする MyRequest クラスを用意しろだぜ☆」

./base_type/banana.py:

    def get(self, request):
        web_confing = # Omit Read file.
        my_request = MyRequest().make_by_getted(request)
        try:
            credentials = web_config.get_credentials()
            db_conn = # DB connection with credentials
            db_cursor = db_conn.get_cursor()

            self.reading.execute_by(db_cursor)
            for row in db_cursor.fetch_row():
                pass

            render( )
        except Exception as e:
            render( )

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 雰囲気的には だいたい こんな感じになる……、だんだん嫌になってきたぜ☆
Flask でどうやって 非同期処理 書くんだぜ☆?」

PythonのWeb frameworkのパフォーマンス比較 (Django, Flask, responder, FastAPI, japronto)

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 今どき Flask より Responder か FastAPI が流行りかだぜ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 Flask で コーディングを努力するより、 FastAPI に乗り換えて楽にコーディングした方が速いわよ?」

KIFUWARABE_80x100x8_01_Futu.gif
「 よく調べずに お父んが Flask を選ぶから……☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 Python 選んでる時点で 遅いのだから 性能に こだわるなだぜ☆
現状 Flask 未満なのだから マシには なる☆」

<書きかけ>

何度でもクリック!→

むずでょ@きふわらべ第29回世界コンピューター将棋選手権一次予選36位

光速のアカウント凍結されちゃったんで……。ゲームプログラムを独習中なんだぜ☆電王戦IIに出た棋士もコンピューターもみんな好きだぜ☆▲(パソコン将棋)WCSC29一次予選36位、SDT5予選42位▲(パソコン囲碁)AI竜星戦予選16位

Crieitは個人で開発中です。 興味がある方は是非記事の投稿をお願いします! どんな軽い内容でも嬉しいです。
なぜCrieitを作ろうと思ったか

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください!

ボードとは?

むずでょ@きふわらべ第29回世界コンピューター将棋選手権一次予選36位 の最近の記事