Life is Really Short, Have Your Life!!

ござ先輩の主に技術的なメモ

kintoneに入門した学習メモ

基本のき

  • RDB感覚でいえば、1テーブル=1アプリ
    • RDBと違うのは、子テーブルをN件持つことが可能なので、親子関係を含めて1つのアプリになる
    • 注文を親に持つ注文明細並びに発注明細などを持てる。
  • 入力値に対する関数が少ない
    • SUM, YEN, DATE_FORMAT, IFぐらいしかない
  • 関連するレコードは全部持ってこれる
    • 得意先を親にして、見積明細、受注明細、契約明細、請求明細など、全部持ってこれて、結合条件やソート条件も指定可能。
  • 画面の融通は効かない
    • 例えばボタンだけを置いて他のアプリに画面遷移する、みたいなのができない
    • フォームの画面ではそもそも任意のボタンはおけない
    • 画面遷移はkintoneの仕組みを使って実現するしか無い
  • 親子関係の表現は楽勝だが、孫まではさすがにむり。
  • アプリ間でフィールドのデータコピーが出来る
    • 見積と見積明細をコピーして、契約と契約明細に値をコピーできる
    • なぜか、ルックアップしたやつは引き直しをしないとだめ
  • ルックアップ先の検索条件、原則あいまい検索になってるの助かる
  • ルックアップは値のコピーであって参照のコピーじゃない
    • なので、参照元が100→101に変わっても、追従して変更されない。
    • 得意先コードや品番のような、JOINするキーに該当する値の変更は出来ないようにマスタ管理で縛る。

プロセス管理

複数の人にお伺いを立てることできるし、条件で分岐することも出来る

  • 基本は「ステータス」を作ること
    • 作成中、上長決裁、部長決裁、社長決裁、承認みたいな感じで。
    • ステータスが変わる条件によって、誰にお伺いを立てるかを設定する
    • 金額が1万未満の場合、作成中→即承認。
    • 1万〜5万は、作成中→上長決裁→承認
  • 決裁担当者は複数人選択できるし、自分で選ぶことも出来る
    • 誰か1人でも承認すればOKもあれば、全員承認しないと駄目、も設定できる
    • 選べる作業者の自動設定は無理っぽい。
    • 自分とメンターみたいな関係があった場合、自分のメンターを自動で引っ張るのは無理。

アクセス制限

  • レコード単位及びフィールド単位で制限ができる
    • 他の担当者のレコードは一切見せたらあかんで、みたいなやつ
    • フィールド単位ってことは、金額がN円で担当者のグループがこれで..みたいなのも出来る
    • ディシジョンテーブルに近道なし。頑張りましょう。

通知

  • この3パターンで通知を飛ばせる
    • アプリのデータが操作されたとき
    • アプリのデータが特定の条件を満たしたとき
    • アプリの日時項目の日時が過ぎたとき

標準では出来ないことも非常に多い

イベントハンドリング
  • プルダウン変わったら連動して子供をかえる
  • フィールドの値イベントのフック
    • 計算するフィールドの場合はchangeイベントが走る
    • 計算しないフィールドの場合は、自分でonchangeでフックして頑張る
  • 明細グループの中で一意にする
    • 注文明細で品番がかぶったらエラーにしたいとか
  • ルックアップしたレコードをN件挿入する
    • 商品を10個いっぺんサブテーブルに登録ができない
  • ルックアップのオートコンプリート(いうほど使わない)
  • アプリ間連携
    • 注文入れたら商品の在庫減らす的な
    • 注文入れたら顧客の与信額減らす的な
    • 整合性を取るために、リビジョンを利用して楽観的ロックを行う
      • データ取得時とデータ更新時でリビジョン違ったら例外発生でやり直し。
  • 自動採番
    • JSで自分でMAX値を取りに行って++せなあかん
  • フィールドの表示・非表示
    • JSでコードを書く。
  • 帳票出力(開発)
  • ログインユーザーの取得
    • 自分の名前をユーザーをルックアップした時に初期値に入れる、が出来ない
  • お知らせの権限設定
    • ポータルのお知らせは権限設定ができない。スペース内のスレッドでやるしかないみたい。
  • 関連レコードの集計
  • 関連レコードをcsvに出す

入力チェックが弱い

標準で可能なチェックはこれぐらい。弱い。

  • ユニーク制約
  • 必須
  • 文字数制限
  • 数値の型チェック
    • 数値以外が入ったらエラー
    • 最小値と最大値の範囲外ならエラー

見たところ、こういうのは全部頑張るしか無い。プラグインを活用するようだ。

  • 大小のチェック
    • 開始日と終了日で、終了日<開始日ならエラー
  • フォーマットのチェック
    • メアドとURLしかないらしい
  • 相関チェック
    • Aにチェックが入っているなら、項目Bは絶対に入力して貰う必要がある
  • かなやカナ、半角全角のチェック

割り切って使えってみんな言うけど、ミスを防ぐために割り切れない部分が多すぎるんじゃね。

こら、kintone専業が少ないわけだ。こんな所に振り回されるぐらいならって思うんだろうな。

内製を支援するビジネスに再挑戦

会社を作った当初はそれを目指していたけど、しっくり来るツールがないのと色んな出会いがあってその方向性はトーンダウンしたが、内製を支援する方向に舵を切ろうと思う。PoCが増えてきたのもある。内製出来る規模のシステムを育てていくのが楽しかったし。

コーポレート・エンジニアリングは、内製が基本だと思う。もちろんSaaS・PaaSはあるだろうけど、結局それらをつなげていかねばならないし、そこに特化出来るように業務を変えていくことになりそう。色んなPaaS・開発ツールを触っては試してみたけれど、自分の中でどうやって組み合わせて行きていけばいいか、ピンときていない。

自分の中で再評価しているのがFileMaker。これ、もしかしてすげーやつなんじゃっていう気持ちがどんどん出てきた。明日から、自分で作った販売管理の仕組みをコイツで作ってみて、やれるところまでやってみようと思います。

Accelerate Corporate Engineering.

SQLAlchemyのLazyLoadとEagerLoad

SQLAlchemyには、カラムを指定できるwith_entitiesという関数がある。

こいつを指定してクエリを組み立てるときは、joinによって指定されたテーブルの中身を、予めもってきてくれるようだ。AlchemyのDebug=Trueで確認した。

 db.session.query(Item).join(Category).with_entities(
    Item.id,
   Category.name
  ).all() 

だけど、もちろんbackrefの指定にもよるけれど、カラムをな~んにも指定しない場合は、lazyloadになる。該当のプロパティにアクセスされたと同時に、SQLが走る。

 rs = db.session.query(Item).join(Category).all()
 for v in rs:
    print(rs.category.name) # この度にSQLが走るっぽい

それは困るぜってときは、予めoption関数でjoinした時にもってこいやっていう指定ができる。

 rs = db.session.query(Item).options(joinedload(Item.category)).all()
 for v in rs:
    print(rs.category.name) # DO NOT N+1 !!

docs.sqlalchemy.org

SQLAlchemy 101って本が日本語であれば、1万円でも買います。

追記 2019.12.28

そんなことしなくても、relationship関数のlazyキーワードに、joinedって入れたらそれだけで良いっぽい

# これでJOIN時にFetchしてくれるからN+1にならへん
user = relationship("User", lazy="joined")

レッツゴーFlutter

展示会運営のアプリをAndroidiOSで各々ネイティブで作って運営しているが、やっぱりワンソースでいい感じにやりたい...2つ同じもの作るのは単純に辛い。メンテナンス・コストが単純に倍になるのがだるい。1から勉強したってのもあるけど、フルコミットでリリースできるまで半年近くかかった。

利用しているライブラリの最新化、OSバージョンアップに伴って廃止/非推奨になったコードのメンテ、ルックアンドフィールの変更に伴うメンテ(今回のダークモードみたいなやつ)、テストコードのメンテ、ビルドシステム(Carthage / Gradle)のメンテ... Webアプリのほうが楽かも。UIのロジックとビジネスロジックの切り分けも気をつけないとすぐ肥大化するし。

Flutterが Android/ iOSクロスプラットフォーム開発の本命だと思われるので、こいつを勉強してなんとかワンソースで頑張りたいンゴ... Google Waveのようなことにはならんやろ。頼むで。

雑貨製造業向けの販売管理システムをリリースしました

Windowsフォーム→WPFに刷新して、空いた時間でコツコツ作っていた販売管理システムを、8月にリリースしました。他社利用も始まっており、後には戻れない〜。

f:id:gothedistance:20190910090631p:plain
f:id:gothedistance:20190910090647p:plain

技術的な話

フロントはWPF、バックエンドはPythonで、HTTPSJSONのやり取りを行っています。

MVVMフレームワークに、Prism7.2を採用しています。PythonはFlask/SQLAlchemyで、Nginx+Gunicornのリバースプロキシ入り環境をDockerでコンテナ化してます。

WPFを選んだ理由は以下の通りです。Electronだと無理な要件が多かったため。

  • グリッドのセル入力やセルのフォーカス制御など、グリッドの操作性の高さが必要だった
  • 画面を切り替えても入力中データがローカルに残るため、利便性が高かった
  • 帳票のダイレクト印刷が必要だった
  • キーイベントの実装が簡単

Windowsフォームの開発である程度の知見があったので、そのままWPFにしました。

機能的な話

物売りの商売で一番面倒で重要になるのは「残管理」です。

  • 取置の残管理
  • 出荷残管理(先納期、分納、納入待ち)
  • 注文残(入荷分から出荷する)の管理
  • 入荷の残管理(発注分の入荷予定の管理)
  • 在庫の管理

この辺がいい感じに連動していている販売管理システムは、あまりないと思います。

販売管理システムの切り替えをご検討の方でこの記事をご覧の方が万が一おられましたら、下記の会社フォームまでお問い合わせを頂ければ。僕が代表なので。デモ版のご案内をさせて頂きます。

お問い合わせ - (株) クオリティスタート 〜 IT企画・ITプロジェクト支援の会社です

CASE-WHENでWhere句を動的に組み立てる

kuniku.hatenadiary.jp

日付で挟む時に、解約日があれば開始日〜解約日、なければ開始日〜終了日で挟みたいという事を実現するのに、ビューを作る必要があった。

CASE-WHEN、幅が広い。

WHERE
  startdate >= curdate()
AND
  curdate() <= 
  (
  CASE
      WHEN cancelDate IS NULL THEN endDate
      ELSE cancelDate
  END
  ) 

SQLを学習できるWebサービスを作りました。

www.start-sql.net

Flask with Vue.js

やっと話が見てきた。

qiita.com

Javascript弱者だったため、Vue.js や Vue-cli 並びにJavascriptの開発環境とか、色んなことがつながるまで少し時間がかかった。

Vue.js のコンポーネント化にはCLIが必要

拡張子がvueのファイルにHTML/CSS/Javascriptをまとめてコンポーネント化し、そいつをimport して使うみたいなやり方をするには、ビルドが必要になる。ここでいうビルドはブラウザが理解できる形で変換をかけること。ScssファイルがCSSファイルに変換されるようなアレだ。

Javascriptの言語仕様がPythonJava等に比べて色々足りていないのを、パッケージマネージャやビルドツールを使って頑張っているのだなぁ。JSのビルドには内部的にJSを使っているため、Node.jsベースのパッケージマネージャであるnpmがあるわけやな。

Flask連携

Flask側は大したことやる必要なくて、ポイントはテンプレートフォルダと静的なファイルを置くフォルダをビルドされた環境に合わせるだけ。あとは、その内容をFlaskがレンダリングするというだけの話。

Vue.jsでSPA化したものをPWAで画像関係をキャッシュしてより高速にしたいものだ。