システム開発で思うところ

Javaで主にシステム開発をしながら思うところをツラツラを綴る。主に自分向けのメモ。EE関連の情報が少なく自分自身がそういう情報があったら良いなぁということで他の人の参考になれば幸い

パッケージ構成の考察(3)

はじめに

過去2回のパッケージ構成について

vermeer.hatenablog.jp

vermeer.hatenablog.jp

約3年ぶりに改めて考察してみようかと。
DDD関連に影響は受けていると思いますが別物です。
3層+ドメイン を基本とした構成です。

なぜ改めて見直すのか?

Reactなどの開発や参考になる情報も増えてきたり、サーバーサイドについてもWebAPIを作成したり、Spring関連*1の勉強もしたりするの中で、以前の整理では ちょっと良くないなと思うところが自分で読み返しても感じたため。
特に WebAPI(RESTful API)については全く考えていませんでした。

パッケージ構成図

https://raw.githubusercontent.com/vermeer-1977-blog/blog-parts/main/package-%20examination/img/package.drawio.svg

ブラウザで見るには小さいのでリンクからsvgファイルを取得してください。
https://raw.githubusercontent.com/vermeer-1977-blog/blog-parts/main/package-%20examination/img/package.drawio.svg

シーケンス

https://raw.githubusercontent.com/vermeer-1977-blog/blog-parts/main/package-%20examination/img/layer-sequence.drawio.svg

https://raw.githubusercontent.com/vermeer-1977-blog/blog-parts/main/package-%20examination/img/layer-sequence.drawio.svg

所感的な補足

baseとapps

分類として横断的機能と業務遂行の中心となるパッケージを分けました。
非機能要件と機能要件を分けるというのも類似です。
技術要素によったパッケージとして coreでも良いのですが中心というイメージではないかな、と。
また意図としてはshareも近い気がしますが、そういう横断的ではなくて箱庭の枠みたいなイメージで同列性を感じない表現が近しいイメージです。

複数のサービスを参照するものの分類は設けない。

複数のサービスの参照じゃなくなったときに命名やパッケージを変更するというのは、なんか違うかな、と。 そういう「複数のサービスを利用している」「別のサービスからも利用されている」というのは、コード分析(JIGみたいな)で取得して把握すれば必要十分だろうということで設けないことにしました。

RepositoryはDomain以外の場所に配置(Application層 or 独立させる)

ドメインオブジェクトから参照はしないから。 何か関数的な操作をRepositoryに「させる」ことはあっても、Repostoryがドメイン内の操作を「する」ことはない。 もし「ある」場合は、ドメインからIO(副作用)があることになりかねない。
逆に非常に簡易的な参照系システムの場合 Presentation層から直接 Repositoryを使用することもアリかなと思ってもいます(トランザクション境界が不要だから)。
となると、RepositoryはPresentation層から使用も出来るし、Application層からも使用できる場所に配置させるのが妥当ではないかな?という結論に至りました。

Service内でのif分岐はあり

構成図には記載していませんが、かつては、if分岐すらも無しに出来ないかな?と思ったことがあります。
ですが、UMLユースケースでも 代替フローがあるので、さすがにやりすぎだと今は思っています。

Serviceの命名は異論あるかも

個人的にはサービスは動詞がアリだと思うのですが ちょっと万人向けじゃないかもなぁと思っています。
とはいえ ユースケース記述に近い実装のやりやすさを考えると、クラス名もユースケース記述に近い「動詞」が良いんじゃないかなぁと。 ということで、ここは以前の考えのままにしました。

Repositoryに重複データ検証用の問い合わせを設ける

1つの理由は上述の「RepositoryはDomain以外に配置」です。

またドメインサービスの例として重複データ検証があると思います。 重複検証がエンティティに実装する振舞いには不適当だからという文脈からいう理解をしています。 つまり「永続情報から何をもって重複判定を行うのか?」という知識を どこまでコード側(Domain)で扱うか?というところだと思います。 僕は「Repositoryのメソッド名による表明で必要十分」という整理に落ち着きました。 たとえば、Repositoryを経由して問い合わせる先がDBではなく外部APIだったらどうでしょうか? そもそもそういった問い合わせ先の具体的な詳細を隠蔽することがRepositoryを用いたDIPの目的であると考えています。

さて、そうするとドメインサービスはいらないの?という問いが出てきます。
僕としては そもそも僕自身がドメインサービスの理解を誤っていた、というのが結論です。 ドメインサービスは

  • 状態を持たない関数として実装する
  • 複数ドメインオブジェクトを組み合わせて表現されるルールを扱う
  • 複数のドメインオブジェクトを扱うにあたって、どちらのドメインオブジェクトにロジックを配置するのか悩ましいときの解決方法(つまり、どちらにもロジックを配置しない)

こう理解をすると、IOは不要でも違和感はありません。

きっかけは 以下の指摘で理解が進んだ気がという感じです。

なお、僕はドメインサービスという名称はアプリケーションサービスもあって分かりにくいので「ルール(Rule)」としています。

Factoryを省略

集約ルートにメソッドを準備する、クラスとして独立させる、ということは目的と規模に応じて適宜判断するものであると考えました。
何かしら必ず作成するようなものではないので、構成図からは外すことにしました。

ライセンス

構成図は MITなので ご自由に使用してください。
Draw.ioがあれば 修正も出来ます。
なお 説明、パッケージオブジェクト、下地の3つのレイヤーにしてロックしているので、編集時には適宜 レイヤーのロックを解除してください。

参考

GitHub - system-sekkei/isolating-the-domain: architecture sample using : Spring Boot gradle, Spring MVC, Thymeleaf, and MyBatis

Atomic Designをやめてディレクトリ構造を見直した話|食べログ フロントエンドエンジニアブログ|note

さいごに

Draw.io を svg形式で保存できるのは本当に便利。

*1:Spring Bootとか Spring Securityとか

Draw.ioをGitHub管理して画像を埋め込む

はじめに

ブログなどのMarkdownドキュメントにフロー図などを書いた画像を埋めたいなぁと思っているときに、Draw.ioで画像拡張子(png/svg)で編集情報を保持したままで管理できるということを知りました。
ということは、ひょっとして埋め込み画像を直接編集して Gitなどでバージョン管理も出来るのでは?と思い至り試してみました。

何が嬉しいの?

  • ドキュメントに埋め込んだ画像の更新のためにエクスポート・アップロードをしなくて良くなる。
  • Draw.ioはローカルで編集できるのでGit管理ができる。

環境

書かないこと

  • Draw.ioの具体的な使い方

やってみた

Draw.ioファイルを作成

新規ファイル作成するときに拡張子を.dioで作成したら Draw.ioファイルとして認識してくれます。
何か描きます。

f:id:vermeer-1977:20220109122033p:plain

画像形式に変換

[ファイル] > [Convert ...] > [.drawio.svg]
変換したら、svgファイルとしてVS Code上表示されますが 改めてVS Code内で ファイルを開きなおすと ちゃんとDraw.ioファイルとして表示されます。

変わったのは拡張子だけ、という感じ(実際は画像ファイルに Draw.io用の情報が埋め込まれている)

f:id:vermeer-1977:20220109122314p:plain

GitHubに上げて確認

ちゃんと画像として読み込めていることも確認。

f:id:vermeer-1977:20220109130015p:plain

ブログなどに埋め込む

埋め込むURLとして[Raw] からリンクを取得

https://github.com/vermeer-1977-blog/blog-parts/raw/main/drawio-in-blog/test.drawio.svg

以下は、更新編集前のブログにリンクを貼った状態。
ちょっとごちゃついているけど、こんな感じで画像としてブログでも確認できる。

f:id:vermeer-1977:20220109131053p:plain

Draw.ioファイルを更新してGitHubに上げる

以下の画像は上述の手順で更新した GitHub管理下のDraw.io(svg)

https://raw.githubusercontent.com/vermeer-1977-blog/blog-parts/main/drawio-in-blog/test.drawio.svg

上記の通り、自動で更新される。

参考

https://tech.fusic.co.jp/posts/2021-06-15-vscode-draw-io-integration/

https://zenn.dev/kaakaa/articles/qiita-20200728-ff9ab5933cc0fb6fd8d8

さいごに

既存のDraw.ioファイルを変換しても同じことが出来ると思います。

これまでは GoogleDriveで お絵描きをして公開設定をしてリンクを貼っていましたが、これでブログ(に限らず)Git管理下に置けそうです。
Draw.ioはオフライン編集が出来るので、色々とやれることは多そうです。

シーケンス図やクラス図を書くときに、PluntUMLを使ってテキストベースでGit管理をして、それをそのまま画像変換するWebサービスみたいなものがあるのは見たことがある気がします。
もちろんそういうアプローチも良いと思いますが、お絵描き系は やっぱりGUIで描画できるのが直観的で私はDraw.ioの方が好きです*1。 あと、Draw.ioはXML形式で構造的にデータを保持しているのでプラグインとかアドオンとか何か情報取得をするときにやりやすそうな印象も受けました。

*1:PluntUML 毎度毎度 入門と中退を繰り返して一向に履修も卒業も出来る気がしないヨワヨワです

LocalStorageを扱うHooks

何が嬉しいの?

Windowをまたがった情報共有ができる。
ただし多用すると状態管理が散乱するので避けた方良い。

実装

import { useEffect, useState, useRef } from 'react';

const useCrossWindowState = <T>(
  stateKey: string,
  defaultValue: T,
): [state: T, setState: (state: T) => void] => {
  const [state, setState] = useState<T>(defaultValue);
  const isNewSession = useRef(true);

  useEffect(() => {
    if (isNewSession.current) {
      const currentState = localStorage.getItem(stateKey);
      if (currentState) {
        setState(JSON.parse(currentState));
      } else {
        setState(defaultValue);
      }
      isNewSession.current = false;
      return;
    }
    try {
      localStorage.setItem(stateKey, JSON.stringify(state));
    } catch (error) {}
  }, [state, stateKey, defaultValue]);

  useEffect(() => {
    const onReceieveMessage = (e: StorageEvent) => {
      const { key, newValue } = e;
      if (key === stateKey) {
        setState(JSON.parse(newValue ?? ''));
      }
    };
    window.addEventListener('storage', onReceieveMessage);
    return () => window.removeEventListener('storage', onReceieveMessage);
  }, [stateKey, setState]);

  return [state, setState];
};

export default useCrossWindowState;

使い方
useStateと同じ感じ。

const [volume, setVolume] = useCrossWindowState<number>('audioVolume', 15);

参考

react-cross-windows-state - CodeSandbox

さいごに

TypeScript対応をするときの型を探すのが地味に手間。
でもanyに逃げない*1

*1:今回だとStorageEvent

イメージファイルをPDFにまとめるシェルスクリプト

やりたいこと

複数のpngファイルを1つのpdfにまとめたい

環境

Lubuntu20.04(VirtualBox

下準備

ImageMagick をインストール

sudo apt install imagemagick-6.q16

ImageMagickの環境設定

/etc/ImageMagick-6/policy.xml 

の設定値を変更

resource

画像ファイルが中途半端に結合されていて「きっと、作業領域が狭いかったんだろう。」ということで、数値を適当に増やしていきました。

結構 増やしたつもりでも足りないケースがあり、最終的に「えーい、もういいや ビックリするくらい多くとってしまおう」という結果が以下。*1

coder

noneread|writeに変更

これもPDFだけで良いはずですが、とりあえず適当にザクザク設定変更

<policymap>
  <!-- <policy domain="system" name="shred" value="2"/> -->
  <!-- <policy domain="system" name="precision" value="6"/> -->
  <!-- <policy domain="system" name="memory-map" value="anonymous"/> -->
  <!-- <policy domain="system" name="max-memory-request" value="256MiB"/> -->
  <!-- <policy domain="resource" name="temporary-path" value="/tmp"/> -->
  <policy domain="resource" name="memory" value="3GiB"/>
  <policy domain="resource" name="map" value="3GiB"/>
  <policy domain="resource" name="width" value="16KP"/>
  <policy domain="resource" name="height" value="16KP"/>
  <!-- <policy domain="resource" name="list-length" value="128"/> -->
  <policy domain="resource" name="area" value="3GiB"/>
  <policy domain="resource" name="disk" value="3GiB"/>
  <!-- <policy domain="resource" name="file" value="768"/> -->
  <!-- <policy domain="resource" name="thread" value="4"/> -->
  <!-- <policy domain="resource" name="throttle" value="0"/> -->
  <!-- <policy domain="resource" name="time" value="3600"/> -->
  <!-- <policy domain="coder" rights="none" pattern="MVG" /> -->
  <!-- <policy domain="module" rights="none" pattern="{PS,PDF,XPS}" /> -->
  <!-- <policy domain="delegate" rights="none" pattern="HTTPS" /> -->
  <!-- <policy domain="path" rights="none" pattern="@*" /> -->
  <!-- <policy domain="cache" name="memory-map" value="anonymous"/> -->
  <!-- <policy domain="cache" name="synchronize" value="True"/> -->
  <!-- <policy domain="cache" name="shared-secret" value="passphrase" stealth="true"/> -->
  <!-- <policy domain="system" name="pixel-cache-memory" value="anonymous"/> -->
  <!-- <policy domain="system" name="shred" value="2"/> -->
  <!-- <policy domain="system" name="precision" value="6"/> -->
  <!-- not needed due to the need to use explicitly by mvg: -->
  <!-- <policy domain="delegate" rights="none" pattern="MVG" /> -->
  <!-- use curl -->
  <policy domain="delegate" rights="none" pattern="URL" />
  <policy domain="delegate" rights="none" pattern="HTTPS" />
  <policy domain="delegate" rights="none" pattern="HTTP" />
  <!-- in order to avoid to get image with password text -->
  <policy domain="path" rights="none" pattern="@*"/>
  <!-- disable ghostscript format types -->
  <policy domain="coder" rights="read|write" pattern="PS" />
  <policy domain="coder" rights="none" pattern="PS2" />
  <policy domain="coder" rights="none" pattern="PS3" />
  <policy domain="coder" rights="read|write" pattern="EPS" />
  <policy domain="coder" rights="read|write" pattern="PDF" />
  <policy domain="coder" rights="read|write" pattern="XPS" />
</policymap>

実行シェルスクリプト

#!/bin/sh
# パラメータ指定しない場合は、実行shと同列のフォルダ配下全てのpngファイルをpdfにまとめる
# pdfファイル名はフォルダ名
# temp.pdfを一気にファイル名指定ができたら良いんだけど、ちょっとわからない。
# 結果としては、親フォルダ配下にマージしたPDFを集めるということで良しとする

echo "Start ..............."

CURRENT_DIR=`dirname $0`

if [ $# = 1 ]; then
    CURRENT_DIR=$1
fi

items=$CURRENT_DIR/*

for item in $items; do
    if [ -d ${item} ]; then
        cd ${item}
        DIR_NAME=`basename ${item}`
        echo $DIR_NAME
        ls *.png | sort -n | tr '\n' ' ' | sed 's/$/\ temp.pdf/' | xargs convert
        mv -f temp.pdf ../${DIR_NAME}.pdf
    fi
done

echo "............. All Done"

参考

convertで画像をPDFへ変換する - Akionux-wiki

Ubuntu18.04 ImageMagick convertで、not authorized xxx.pdf エラー | Ninton

「さようなら ImageMagick」の考察 - Qiita

さいごに

ImageMagick脆弱性で色々と問題はあるみたいなので ご利用は自己責任で*2

*1:数値に根拠は無いので、各環境にあわせてチューニングしてください

*2:私は作業後に気が付いて、このブログをメモとして残して作業が終わったら削除しました

Karateのメモ

GitHub - karatelabs/karate: Test Automation Made Simple

www.slideshare.net

APIのテスト自動化ツール「Karate」を使ってみる - Reasonable Code

Karateツールを使用してテストケースを並行して実行し、レポートを生成する - その他

Karateに性能試験とUI試験を任せてみる - Taste of Tech Topics

APIテスト自動化ツールKarateをBDDツールとして使う - まっつんの日記

【雑記】国産クラウド(もしくは官公庁で使うクラウド)

デジタル庁が採用したクラウド事業者がAWSGCPという話を受けて個人的に思ったことをツラツラ。

はじめに

www.yomiuri.co.jp

3社から応募があったが、安全面や事業継続性など約350の要件を満たした両社を採用した。

相応の基準をもって選ばれたと思いますし、応募3社からの選定とのことなので そもそも応募もしていなかったかもしれないので、勝手な思いです。

偏った私見を交えつつ、僕が選ぶんだったらこうするかなぁと順番に。
改めて断っておきますが、何の根拠もない ただの感想です(逃げまくり)。

あと国産クラウドといいつつ、富士通以外は情報を持ち合わせていないので 非国産クラウドだったりします。

まぁそれくらい緩い雑記と思っていただければ。

富士通

FUJITSU Cloud Service : 富士通

国産クラウドであるべきかどうか分かりませんが、富士通は国産クラウドサービスを提供しています。
官公庁のサービス基盤として、選べるのであれば国産の方が日本人ならではの細かさへの対応を含めて融通があるように思います。

国内基盤ということは機密に関するデータも扱います。
それが海外サーバに配置されることが個人的には好ましいとは思いません*1
(基本事項のサービス全般に「情報資産はユーザが指示しない限り日本国内に保管されること。」とのことなので、AWSGCPでも要件は満たされていると考えて良さそうですね)

東京リージョンとして独立しているとは思いますし、おそらく先の選定基準の中でも言及されているとは思いますが、デジタル戦争的な話を考えたときに「日本が海外のネットワークから遮断されるリスク」もあるような気がします。

富士通は富岳といった国産基盤を構築や機密保持のノウハウがあると想像するところもあります。

エンタープライズ系としては Java EEJakarta EE)や PostgreSQL などのOSSへの貢献を長く行っています。
富士通東京証券取引所での大量データ高速処理を汎用機からサーバをベースとする基盤にリプレイスした実績もありますし、メーカーとしてサーバー製造できるということは「非常にコアな処理を物理で殴る」ことも出来るという事だと思います。
また東証のように大きめの規模の基盤を準備しておいて有休資材を「官公庁クラスのセキュアな基盤」として民間利用に回すことも出来るかもしれません。

クラウド業者という意味ではメジャーではないのですが、かつてはOracleクラウドのパートナーだったりするので相応のノウハウはあるんじゃないかぁと(Oracleから提携切られはしましたけど)。

ちなみにアプリケーション実行基盤としての使いやすさについては、後述他を含めて 昨今 Kubernetesをベースとしているので そのレイヤーでの差はあまりないのではないかな?と思っています。

MicroSoft(Azure)

ここ数年のOSSへの取り組みや、マネージドなサービスへの取り組みが基盤利用者フレンドリーに感じるからというのがあります。

また、これはJJUGの懇親会で、クラウド基盤を そのままワークステーションのように持ち運べるサービスもあるというの伺ったことがあるから。
物理的にオンプレとクラウドをシームレスに利用できるというのは官公庁としては扱いやすいと思います。 先にも挙げたようにネットワーク的に日本が海外と断絶したとしても、こういうサービスがあれば災対としても有効だと思います。 同じように災害時に狭い範囲(といっても市町村自治体レベル)で独立したサブ官公庁システムを搬入することで早期の部分的復旧も出来るように思います。

Office365をベースとした企業環境基盤も既にあり、そのあたりを新規で作り込まなくて良いというメリットもあるように思います。 富士通もProjectWebとかあるんでしょうけど、、最近色々ありましたし。。あとOffice系サービスは 利用現場においても必要なので MS系で固めてしまって運用の簡便化を図っても良いかなと。

基盤の上のサービスはNTTデータ富士通NEC、日立 などのベンダーが行うとして、MS系がベースにあるのはオールインワンとして便利だと思います。

IBMRed Hat

MSとは僅差というか、同着というか そのくらいの位置。
未知数は日本対応。
東京リージョンはあるので、物理データ置き場が グローバルでミラーされる可能性はAWSGCPと同じ(それをいえばMSも同じかもしれないけど)。
違いは、富士通の時と同じく ハードメーカーの側面があるところ。
ソフト面については Red Hatを含めた多彩さに期待。
とくに実行基盤とアプリの間を埋める部分となるOS周りは Red Hatの強みかなと思う*2

Javaベースの実行基盤としては WildFly もあるし、Camelとか分散システムの実行基ミドルウェア製品などの面が強いイメージがあります。

ルール駆動開発あたりもユーザー主導でシステム構築をするときに有効活用できるんじゃないかなぁ。

その他

Oracleもよぎったのですがクラウドサービスに限れば、そんなことは無いのかもしれないのですが いかんせん高いというイメージが拭えないんですよね。
あと、数年前まで富士通が日本国内の基盤サポートをしていたという記憶があり、だったら運用ノウハウのある富士通で良いんじゃないかな?と。

参考リンク

デジタル庁におけるガバメント・クラウド整備のためのクラウドサービスの提供-令和3年度地方公共団体による先行事業及びデジタル庁WEBサイト構築業務- |デジタル庁

(詳細未読)

さいごに

まぁ、、あれですね。自分の嗜好先であるJavaと 日本IT利用者に親和性があるんじゃないかな、という順みたいな感じになっていますね。
かなり縁故含めてバイアスがありありだとも思います。
再掲ですが、何の根拠もないただの感想です。別にAWSGCPが悪いとか言っているわけではありません。
こんな意見もあるんだなというところで。

*1:データの置き場所の法令に従った扱いになるという認識のため

*2:実際はDockerに吸収されるところなのかもしれないけれど

VirtualBoxの共有フォルダ設定

いつも忘れる、VirtualBoxの共有フォルダ設定のメモ

ツールのインストールに必要なものをインストール

sudo apt install gcc make perl -y

VirtualBoxツールをインストール

インストールディスクを挿入

ディスクのフォルダへ移動

sudo sh VBoxLinuxAdditions.run

ゲストOS再起動

ユーザーをvboxsfグループに加える

sudo gpasswd -a (ユーザー名) vboxsf

共有フォルダを設定

ゲストOS(Linux)のmnt/nas へマウントしたい場合*1

f:id:vermeer-1977:20210830092036p:plain
共有フォルダ設定

*1:サーバーキッティングの予行演習なので 外部ストレージ疑似としてNASへのマウントを意図しています