<前回の記事>
「 できるプログラマーの話しには飽きただろ☆ 手抜きをしようぜ☆?」
「 時給2000円分以上の仕事はしないことに 魂が燃えているわよね」
「 自社と どの会社が競合してるか 分からんよな☆
ホワイトリストから外れ いろいろなソフトがインストールできない環境で
Power shell は Windows に最初から入っている☆ これを使っていこう☆」
「 営業部門ではないので 手抜きをしながら 要望だけ満たして あとはコーヒーでも飲んでいればいいわけだが、
Windows と同じ Microsoft だから安全とかいう根拠のない理由で Visual studio code をインストールしたわたしは
レジスタをいじって .ps1
をダブルクリックして 起動できるようにした☆」
「 C# も Java も PHP も Rust も Python3 も JavaScript も書けるお父んが 行きついた答えは Power shell かだぜ☆」
practice-2
|
+-- main-2.ps1
|
+-- modules
|
+-- module-2.ps1
「 とりあえず modules
というフォルダーを作って サブルーチンは全部 そこへ投げ入れろだぜ☆
『ファイル数が多すぎる』 とか、 『フォルダー数が多すぎる』 とかいった小言は封殺できる☆」
「 『mainなんとかをダブルクリックするだけですよ』 という言葉は
休日に起こされてエラー対応するエンジニアに安心感を与える☆」
「 本当は Privilege
へ昇格させたり、コマンドライン・パラメーターを手抜きする方法などいろいろあって もう少し手間をかけるが
今は省く☆」
「 Visual studio code を出せだぜ☆ Power shell を使って コールバック を書く方法を教えてやる☆
たとえ話を聞くより早いだろう☆」
「 10個ぐらいの短いサンプル・プログラムを書くと 頭に叩き込めると思う☆ おそらく最速だぜ☆」
main-ep1.ps1
# +
# | Episode 1.
# +
# +
# | Hash map.
# | In another language, it is also called a dictionary.
# +
$dict = @{
Food = "palm";
Plice = 20;
}
# - Function definition.
function Invoke-Main($dict) {
Write-Host "I bought $($dict.Food) for $($dict.Plice) yen."
$dict.Plice += 50
}
# - Function call.
Invoke-Main $dict
# - End.
Write-Host "Info | $($dict.Plice) yen."
Write-Host "Info | Finished."
Output
I bought palm for 20 yen.
Info | 70 yen.
Info | Finished.
「 めんどくさいんで 適当に書いたが、
連想配列、関数定義、関数呼出し、参照渡し の説明は終わった☆
何それと思ったら勝手に調べろだぜ☆」
main-ep2.ps1
# +
# | Episode 2.
# +
# +
# | Hash map.
# | In another language, it is also called a dictionary.
# +
$dict = @{
Food = "palm";
Plice = 20;
# - You can also include functions.
OnStarted = {
Write-Host "Info | Started."
};
OnFinished = {
Write-Host "Info | Finished."
};
}
# - Function definition.
function Invoke-Main($dict) {
$dict.OnStarted.Invoke()
Write-Host "I bought $($dict.Food) for $($dict.Plice) yen."
$dict.Plice += 50
$dict.OnFinished.Invoke()
}
# - Function call.
Invoke-Main $dict
# - End.
Write-Host "Info | $($dict.Plice) yen."
Write-Host "Info | Finished."
Output
Info | Started.
I bought palm for 20 yen.
Info | Finished.
Info | 70 yen.
Info | Finished.
「 処理 を1本にまとめたいときに使う☆ 使っていれば そのうち分かる☆
どんどん行こう☆」
main-ep3.ps1
# +
# | Episode 3.
# +
# +
# | Hash map.
# | In another language, it is also called a dictionary.
# +
$dict = @{
Food = "palm";
Plice = 20;
# - You can also include functions.
OnStarted = {
$dict = $args[0]
Write-Host "Info | Started. [$($dict.Message)]"
};
OnFinished = {
Write-Host "Info | Finished."
};
}
# - Function definition.
function Invoke-Main($dict) {
$dict2nd = @{
Message = "Hello, Old man.";
};
$dict.OnStarted.Invoke($dict2nd)
Write-Host "I bought $($dict.Food) for $($dict.Plice) yen."
$dict.Plice += 50
$dict.OnFinished.Invoke()
}
# - Function call.
Invoke-Main $dict
# - End.
Write-Host "Info | $($dict.Plice) yen."
Write-Host "Info | Finished."
Output
Info | Started. [Hello, Old man.]
I bought palm for 20 yen.
Info | Finished.
Info | 70 yen.
Info | Finished.
「 コールバック関数が引数を受け取ることもできる☆
連想配列を1個受け取るのが 手っ取り早いぜ☆ 細かいことやってたら プログラムが分けわからなくなる☆」
「 連想配列の参照を渡しているようでは グローバル変数をマウントしてるのと変わらんけどな☆」
「 そうそう……☆
設計するより グローバル変数をマウント する方が手っ取り早い……☆」
「 エラーの影響を切り分けすることを 諦めろ だぜ☆
どこかがミスったら システムは落ちる☆」
「 一旦、 メイン・ルーチン と サブ・ルーチン を分けてみようぜ☆?」
episode-4
|
+-- modules
| |
| +-- module-1.ps1
|
+-- i-have-banana.ps1
|
+-- i-have-parm.ps1
「 フォルダー階層は 練習なんで こうしておくかだぜ☆
慣れてくると もっといい方法があるが 一度にやると 覚えられないだろうからな☆」
「 みんな ググって最初に出てくる サンプル・プログラム みたいなコード書くわよね。
それが コンピューター だと思って疑問に思わず メンテナンス してるのよ」
episode-4\modules\module-1.ps1
# +
# | Episode 4.
# +
# - Function definition.
function Invoke-Main($dict) {
# - You can also include functions.
$dict.OnStarted = {
$dict = $args[0]
Write-Host "Info | Started. [$($dict.Message)]"
};
$dict.OnFinished = {
Write-Host "Info | Finished."
};
$dict2nd = @{
Message = "Hello, Old man.";
};
$dict.OnStarted.Invoke($dict2nd)
Write-Host "I bought $($dict.Food) for $($dict.Plice) yen."
$dict.Plice += 50
$dict.OnFinished.Invoke()
# - End.
Write-Host "Info | $($dict.Plice) yen."
Write-Host "Info | Finished."
}
「 modules
フォルダーの下にあるスクリプトは 誰も読まないから 伸び伸び書けるぜ☆」
i-have-banana.ps1
# +
# | Episode 4.
# +
# +---------+
# | Ready |
# +---------+
$dict = @{
Food = "banana";
Plice = 160;
}
# +------+
# | Go |
# +------+
Write-Host "Exit | $(Get-Location)"
Set-Location $PSScriptRoot
Write-Host "Enter | $(Get-Location)"
# Read script. (Dot source)
. ".\modules\module-1.ps1"
Invoke-Main $dict
Output
Exit | C:\Users\むずでょ\OneDrive\ドキュメント\practice-ps1
Enter | C:\Users\むずでょ\OneDrive\ドキュメント\practice-ps1\practice-2\episode-4
Info | Started. [Hello, Old man.]
I bought banana for 160 yen.
Info | Finished.
Info | 210 yen.
Info | Finished.
「 いわゆる メイン・プログラム には、 Ready
セクションと Go
セクション だけをおけだぜ☆
まだ 設定ファイル を利用したり改善の余地はあるが、
だいたい これ以上 複雑にすると プログラマーは自分の首を絞めることになるぜ☆」
「 電話を掛けている机の向かいの システム・エンジニアが IPアドレス を質問してきたりするわよね」
「 だいたい どんなプログラム書いたっけ と忘れた頃に 客先のIPアドレスが変わったりする☆
リモート・サーバーにログインして 動いているプログラムの設定ファイルを見るのが手っ取り早い☆
ちょっと調べるふりをして 30秒 ぐらいで返事ができると 電話を折り返さず 仕事が スムーズに進むぜ☆」
i-have-palm.ps1
# +
# | Episode 4.
# +
# +---------+
# | Ready |
# +---------+
$dict = @{
Food = "palm";
Plice = 20;
}
# +------+
# | Go |
# +------+
Write-Host "Exit | $(Get-Location)"
Set-Location $PSScriptRoot
Write-Host "Enter | $(Get-Location)"
# Read script. (Dot source)
. ".\modules\module-1.ps1"
Invoke-Main $dict
Output
Exit | C:\Users\むずでょ\OneDrive\ドキュメント\practice-ps1\practice-2\episode-4
Enter | C:\Users\むずでょ\OneDrive\ドキュメント\practice-ps1\practice-2\episode-4
Info | Started. [Hello, Old man.]
I bought palm for 20 yen.
Info | Finished.
Info | 70 yen.
Info | Finished.
「 ここでは パラメーターを変えれる 例だけ紹介しているが、もちろんコールバック関数を利用して 処理も変えれる☆
例えば Product と UAT の2つに分けれる☆」
「 本番用(Prod)と、受入テスト環境用(UAT)で同じプログラムを走らせるが、受入テスト環境用には処理をちょっと足したいというときは
コールバック関数を使って 処理を挟み込めだぜ☆」
$dict2nd = @{
Message = "Hello, Old man.";
};
$dict.OnStarted.Invoke($dict2nd)
「 練習用に 連想配列を使って コールバック関数の引数として渡していたが……☆」
function Invoke-Main($dict) {
$dict.Message = "Hello, Elder brother.";
$dict.OnStarted.Invoke($dict)
}
「 メイン・プログラムの最初に作った連想配列に ぶら下げて 一気通貫 するのもOK☆」
「 自分しか いじらない プログラム という前提よね。
複数の会社で いじるプログラム だと 隣の会社は指示下にないわ、修正できないから メインコード捨てて勝手にやるわ、
定められたフォーマットの仕様上 挟めるメモリ空間が足りないわと
可能を不可能にするプログラム の始まりなのよ」
「 わたしのプログラムの書き方は 捨てるプログラム 、 一から書き直すプログラム だぜ☆
秘伝のタレ なんか持ってて いつまでも捨てないプログラムを書いている人には 評判が悪いだろうなんだぜ☆」
「 git で差分更新して管理しているくせに全部捨てて 全部新しいファイルになってたりするよな☆」
「 まだ 手抜きのための便利アイテムを説明しきっていないので、説明していくぜ☆」
「 JavaScript には Handlebars という便利なものがあるんだが、
Power shell にはないので 簡単なものを 自作するぜ☆ やることは……☆」
My name is {{userName}}.
My name is Muzudho.
「 に置換することだけ できるようにしようぜ☆
これだけで 逃げ道は広がる、手抜きができる ☆」
「 Power shell で UTF-8 エンコーディングしたファイルは with BOM になるから 他のスクリプト言語で読めなくて役に立たないのよ」
「 UTF-8 without BOM で出力する方法も説明する☆」
config-TEMPLATE.ini
[Profile]
Name = {{userName}}
Age = {{age}}
「 全部変数にするみたいな書き方をしたら あんまり設定ファイルの意味は無いが
練習で 設定ファイルに プレースホルダーを書いておくぜ☆」
config.ini
[Profile]
Name = Muzudho
Age = 39
「 こんな感じに変換してくれれば便利だぜ☆
例えば 設定ファイル と ドキュメント の両方を テンプレート にしておけば 齟齬がなくなる☆」
config-STEREOTYPE.ini
userName = Muzudho
age = 39
「 タネ になる方も 設定ファイルにしておけだぜ☆
手書きするのではなく、プログラムで動的に出力することになると思う☆」
main.ps1
# +
# | Episode 5.
# +
# +---------+
# | Ready |
# +---------+
$dict = @{
# Absolute path.
Locations = @{
StereotypeDir = "$($PSScriptRoot)\@auto-gen"
};
}
# +------+
# | Go |
# +------+
Write-Host "Exit | $(Get-Location)"
Set-Location $PSScriptRoot
Write-Host "Enter | $(Get-Location)"
# Read script. (Dot source)
. ".\modules\module-1.ps1"
New-Stereotype $dict
modules\module-1.ps1
function New-Stereotype($dict) {
$path = $dict.Locations.StereotypeDir
$file = "$($path)\config-STEREOTYPE.ini"
$text = @"
userName = Muzudho
age = 39
"@
$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding $False
# - Create a directory if it not exists.
if ( !(Test-Path $path) ) {
Write-Host "Create | [$($path)] directory."
New-Item -ItemType directory -Path $path
}
# - Write a file.
Write-Host "Write | [$($file)]."
[System.IO.File]::WriteAllLines($file, $text, $Utf8NoBomEncoding)
}
「 頭に @
が付いているファイルは リリースしない、本番環境に入れない、
ぐらいの意味で 勝手にルールを作って 使っている☆
@auto-gen
は auto-generated
の略☆」
「 前にも書いたが、前の記事を探すのがめんどくさいんで再掲するぜ☆」
modules\ini-parser.ps1
# +
# | See also:
# | INI file parsing in PowerShell
# | https://stackoverflow.com/questions/417798/ini-file-parsing-in-powershell
# +
Function Read-IniFile ($file) {
$ini = @{ }
# Create a default section if none exist in the file. Like a java prop file.
$section = "NO_SECTION"
$ini[$section] = @{ }
switch -regex -file $file {
"^\[(.+)\]$" {
$section = $matches[1].Trim()
$ini[$section] = @{ }
}
"^\s*([^#].+?)\s*=\s*(.*)" {
$name, $value = $matches[1..2]
# skip comments that start with semicolon:
if (!($name.StartsWith(";"))) {
$ini[$section][$name] = $value.Trim()
}
}
}
$ini
}
main-2.ps1
# +
# | Episode 5.
# +
# +---------+
# | Ready |
# +---------+
$dict = @{
# Absolute path.
Locations = @{
StereotypeDir = "$($PSScriptRoot)\@auto-gen"
};
}
# +------+
# | Go |
# +------+
Write-Host "Exit | $(Get-Location)"
Set-Location $PSScriptRoot
Write-Host "Enter | $(Get-Location)"
# Read script. (Dot source)
. ".\modules\ini-parser.ps1"
$cnf = Read-IniFile "$($dict.Locations.StereotypeDir)\config-STEREOTYPE.ini"
$cnf.GetEnumerator() | ForEach-Object {
$section = $_;
Write-Host "Section | [$($section.Name)]";
$section.Value.GetEnumerator() | ForEach-Object {
$item = $_;
Write-Host "Item | [$($item.Name)] = [$($item.Value)]";
}
}
Output
Exit | C:\Users\むずでょ\OneDrive\ドキュメント\practice-ps1\practice-3
Enter | C:\Users\むずでょ\OneDrive\ドキュメント\practice-ps1\practice-3
Section | [NO_SECTION]
Item | [age] = [39]
Item | [userName] = [Muzudho]
「 業務に関係のあるページですか? とか出てきて会社のPCから見れないんだけど?」
「 .ini ファイルを 連想配列ではなく ただのテキストとして読み込む方法を紹介する☆」
main-3.ps1
# +
# | Episode 5.
# +
# +---------+
# | Ready |
# +---------+
$dict = @{
# Absolute path.
Locations = @{
ConfigDir = "$($PSScriptRoot)";
};
}
# +------+
# | Go |
# +------+
Write-Host "Exit | $(Get-Location)"
Set-Location $PSScriptRoot
Write-Host "Enter | $(Get-Location)"
$file = "$($dict.Locations.ConfigDir)\config-TEMPLATE.ini"
$text = [System.IO.File]::ReadAllLines($file) -join "`r`n"
Write-Host "Conf | v";
Write-Host $text
Write-Host "Conf | ^";
Output
Exit | C:\Users\むずでょ\OneDrive\ドキュメント\practice-ps1\practice-3
Enter | C:\Users\むずでょ\OneDrive\ドキュメント\practice-ps1\practice-3
Conf | v
[Profile]
Name = {{userName}}
Age = {{age}}
Conf | ^
「 とりあえず、開発が進むごとに 処理が遅くなるBADなアルゴリズムで書いてみるぜ☆」
main-4.ps1
# +
# | Episode 5.
# +
# +---------+
# | Ready |
# +---------+
$dict = @{
# Absolute path.
Locations = @{
ConfigDir = "$($PSScriptRoot)";
StereotypeDir = "$($PSScriptRoot)\@auto-gen";
};
}
# +------+
# | Go |
# +------+
Write-Host "Exit | $(Get-Location)"
Set-Location $PSScriptRoot
Write-Host "Enter | $(Get-Location)"
# Read script. (Dot source)
. ".\modules\ini-parser.ps1"
$ster = Read-IniFile "$($dict.Locations.StereotypeDir)\config-STEREOTYPE.ini"
$file = "$($dict.Locations.ConfigDir)\config-TEMPLATE.ini"
$text = [System.IO.File]::ReadAllLines($file) -join "`r`n"
# Replace. But, *BAD* algorithm.
$ster.GetEnumerator() | ForEach-Object {
$section = $_;
$section.Value.GetEnumerator() | ForEach-Object {
$item = $_;
$text = $text.Replace( "{{$($item.Name)}}", $item.Value)
}
}
Write-Host "Conf | v";
Write-Host $text
Write-Host "Conf | ^";
Output
Exit | C:\Users\むずでょ\OneDrive\ドキュメント\practice-ps1\practice-3
Enter | C:\Users\むずでょ\OneDrive\ドキュメント\practice-ps1\practice-3
Conf | v
[Profile]
Name = Muzudho
Age = 39
Conf | ^
「 リクツが分かれば 高速化しろだぜ☆ ファイルも書き出せだぜ☆」
config-TEMPLATE.ini
[Profile]
Name = {{userName}}
Age = {{age}}
main.ps1
# +
# | Episode 5.
# +
# +---------+
# | Ready |
# +---------+
$dict = @{
# Absolute path.
Locations = @{
ScriptDir = "$($PSScriptRoot)";
AutoGenDir = "$($PSScriptRoot)\@auto-gen";
};
}
# +------+
# | Go |
# +------+
Write-Host "Exit | $(Get-Location)"
Set-Location $PSScriptRoot
Write-Host "Enter | $(Get-Location)"
# Read script. (Dot source)
. ".\modules\ini-parser.ps1"
. ".\modules\module-1.ps1"
# Out-Null waits for the process to finish.
New-Stereotype $dict | Out-Null
$stereotype = Read-IniFile "$($dict.Locations.AutoGenDir)\config-STEREOTYPE.ini"
$text = Read-File "$($dict.Locations.ScriptDir)\config-TEMPLATE.ini"
$text = Edit-PlaceHolder $text $stereotype
Write-File "$($dict.Locations.AutoGenDir)\config.ini" $text | Out-Null
# - End.
Write-Host "Info | Finished."
modules\ini-parser.ps1
# +
# | See also:
# | INI file parsing in PowerShell
# | https://stackoverflow.com/questions/417798/ini-file-parsing-in-powershell
# +
Function Read-IniFile ($file) {
Write-Host "Read | [$($file)]."
$ini = @{ }
# Create a default section if none exist in the file. Like a java prop file.
$section = "NO_SECTION"
$ini[$section] = @{ }
switch -regex -file $file {
"^\[(.+)\]$" {
$section = $matches[1].Trim()
$ini[$section] = @{ }
}
"^\s*([^#].+?)\s*=\s*(.*)" {
$name, $value = $matches[1..2]
# skip comments that start with semicolon:
if (!($name.StartsWith(";"))) {
$ini[$section][$name] = $value.Trim()
}
}
}
$ini
}
modules\module-1.ps1
function New-Stereotype($dict) {
$path = $dict.Locations.AutoGenDir
$file = "$($path)\config-STEREOTYPE.ini"
$text = @"
userName = Muzudho
age = $(10+29)
"@
# - Create a directory if it not exists.
if ( !(Test-Path $path) ) {
Write-Host "Create | [$($path)] directory."
New-Item -ItemType directory -Path $path
}
# - Write a file.
Write-Host "Write | [$($file)]."
[System.IO.File]::WriteAllLines($file, $text)
}
function Read-File($file) {
Write-Host "Read | [$($file)]."
[System.IO.File]::ReadAllLines($file) -join "`r`n"
}
function Write-File($file, $text) {
$path = Split-Path $file -parent
# - Create a directory if it not exists.
if ( !(Test-Path $path) ) {
Write-Host "Create | [$($path)] directory."
New-Item -ItemType directory -Path $path
}
# - Write a file.
Write-Host "Write | [$($file)]."
[System.IO.File]::WriteAllLines($file, $text)
}
function Edit-PlaceHolder($text, $stereotype) {
# Replace. But, *BAD* algorithm.
$stereotype.GetEnumerator() | ForEach-Object {
$section = $_;
$section.Value.GetEnumerator() | ForEach-Object {
$item = $_;
$text = $text.Replace( "{{$($item.Name)}}", $item.Value)
}
}
$text
}
client-1
+
|
+-- config.ini
|
+-- README.md
|
+-- source.ps1
「 設定ファイルがあって 実行ファイルがある、ぐらいの構成だろ☆
よくて リードミーが付くぐらい☆」
「 作っているときは 手抜きができる が、
開発が進むと 手抜きができなくなる☆
もっと運用が進んで追加の要求がきた時を見据えて 大きな手抜きをしたい とは思わないかだぜ☆?」
「 モジュールの追加 と サブシステム化、 プラットフォーム変更によるデプロイ が今後起こる☆」
「 例えば Windows 10 とか 一生使い続けれると思っているかも知れないが、
10年後に Windows 30 とかになるか分からないぜ☆?」
「 Windows 40 が出たときまで そんなことが言ってられるかだぜ☆?」
Case 1 : BAD
client-1
+
|
+-- config.ini
|
+-- README.md
|
+-- source.ps1
# Command line parameter `--mode 1` or `--mode 2`
Case 2: BAD
client-1
+
|
+-- config.ini
|
+-- README.md
|
+-- source.ps1
|
+-- source-2.ps1
Case 3: BAD
C:\
|
+-- client-1
| |
| +-- config.ini
| |
| +-- README.md
| |
| +-- source.ps1
|
+-- client-1-2
|
+-- config.ini
|
+-- README.md
|
+-- source.ps1
「 アプリケーションを追加すると こうなる☆
他にも データベースを使うなり やりようはあるかもしれないが、
現場で何が起こるか 見えていないのは
プログラマーはあんまりチーム作業しない個人技 なところからくるのだろう☆」
「 お客は 最初 2社とか 3社かも知れないが、
そのうち 10社 20社 と増えていき、さらに 会社ごとに 前株なのか後株なのか、
データベースの表示列名を短縮したり、短縮してはいけなかったり、
メッセージは外出しして 対応できるフォーマット にしておいたり、
UTF-8 でいいのか Shift-JIS にこだわるのかも 分かれる☆
設定ファイルは .ini を メモ帳(Windows Notepad) で触りたい お客さんもいる☆」
「 あと見えていないが そもそも ログ・ファイル の出力先フォルダーと、
受け取ったデータを蓄積していく 月別アーカイブ フォルダーが どこかにある☆」
「 Case 3 がダメな理由は簡単だぜ☆
IP アドレスが変わった時に config.ini ファイルが10個あったとき、
担当者にここを直してくださいと ファイル10個分の ファイルパスを並べて 指示を出すのは いかがなものなのか☆?」
「 自分で直すなら 10個ぐらい と思うかもしれないが それもダメだぜ☆
50個なら どうなのか? 100個なら?」
「 お客さんが 1つ あるなら、
その お客さん1つ に対応した 設定ファイル を1つ を用意しろだぜ☆
余分と思うのは お前の勘違い だぜ☆」
Case 4 : Good
client-1.ini
[Profile]
IPAddress = 127.0.0.1
Suffix = ABC
「 IPアドレスを書いておく 設定ファイル は1か所にしろだぜ☆
お客の短い頭文字も 社内で決めておけだぜ☆ フォルダー名や、インターナルなエラー通知メールの件名に使う☆」
Case 5 : Better
C:\
|
+-- client-1
|
+-- feature-1
| |
| +-- README.md
| |
| +-- source.ps1
|
+-- feature-1
| |
| +-- README.md
| |
| +-- source.ps1
|
+-- etc
|
+-- client.ini
|
+-- modules
|
+-- feature-1.ini
|
+-- feature-2.ini
「 設定ファイルは etc
フォルダーを作って その中に まとめて入れろだぜ☆
オペレーターが触ることのない設定ファイルは etc\modules
の下に隠せだぜ☆」
「 なんで etc
とかいう 分け分かんないフォルダー名の中に 設定ファイルを入れてしまうの?」
「 相手に合わせて 3段階 の説明を用意しておくことは プログラマーの作法だぜ☆」
「 まず相手が 手練れ の場合☆
Linux で 設定ファイルを etc フォルダーの下に置くことに慣れてるんでフォルダー名を真似した☆
この説明で 歯向かってこられたら 手抜きは諦めろ だぜ☆
売り上げに貢献しないルーチンを身に付ける精神修養をしろだぜ☆」
「 次に相手が サンプル・プログラムぐらいは書ける人 の場合☆
Linuxで ファイルの置き場所は FHS という仕様で決まっている☆ 自分の選ぶ仕様を1つ明示しておけば他の人も真似することができる☆
この説明で 歯向かってこられたら 手抜きは諦めろ だぜ☆
みなそれぞれ 売り上げに貢献しない そのときの気分で名付けたフォルダー名に悩む趣味でも愛でろだぜ☆」
「 次に相手が コンピューターはわたしを上から目線で見下してくるゴミくずだと思っている人 の場合☆
その他フォルダーに入れておきました☆
この説明で 歯向かってこられたら 手抜きは諦めろ だぜ☆
どう考えても etc
より文字数が長くなるフォルダー名を 明日止めてしまうかもしれない担当者の好みで付けて その後もメンテナンスしろだぜ☆」
「 そんな こんな で 現場で改善していくと ある程度落ち着く 冗長なデザイン というものがある☆
わたしが勝手に トリニティ・デザイン と名付けた☆ 説明しよう☆」
「 だいたい この3段階の階層構造 で、いろいろ対応できる☆ よく使うんで省略すると☆」
「 クリー、 フィート、 オパー の3つだぜ☆ これは ファイル・パスの付け方 を方向づけしている☆」
# Tri pattern.
Clie\Feat\Oper
# Destination tri pattern.
$dsTriDir = "$($clieDir)\$($featDir)\$($operDir)"
「 明日辞めてしまうかもしれない お父んの特殊パターン なんか覚えてどうすんだぜ☆?」
# Duo pattern.
Clie\Feat
「 クリー と フィート をつなげたパターンは デュオ・パターン だぜ☆
フィートとオペだけくっつくパターンは少ないので、少ないことに 用語は作らない☆ 研究者ではなく、実務屋だからな☆」
「 クリー は メール担当者が名乗る何社 と1対1対応しろだぜ☆ 契約を取る、無くなる、にフォルダーを作る、消すが対応する☆
フィート は 案件 と1対1対応しろだぜ☆ 人間力学で連絡には『あの件ですが……』とドメイン的な切れ目があるから 気づけ☆
オパー は 休日に働くシステム・エンジニア に出す このファイルをクリックしろ、という指示で切り分けろだぜ☆ 最小単位☆」
「 それを加味して 少しマシにした ディレクトリーのデザインは次の通り☆」
Case 6 : More better
C:\
|
+-- client-1
|
+-- etc
| |
| +-- client.ini
| |
| +-- feature-1
| |
| +-- operation-1.ini
| |
| +-- operation-2.ini
|
+-- opt
|
+-- feature-1
|
+-- operation-1
| |
| +-- README.md
| |
| +-- source.ps1
|
+-- operation-2
|
+-- README.md
|
+-- source.ps1
「 opt
とかいう分けのわからないディレクトリが1階層 増えたわよ?」
「 逆に、オペレーターにダブルクリックさせたいファイルもあるだろ☆
それは home
ディレクトリーの下に入れておくといい☆ サンプルを示そう☆」
Case 7 : More better
C:\
|
+-- client-1
|
+-- etc
| |
| +-- client.ini
| |
| +-- feature-1
| |
| +-- operation-1.ini
| |
| +-- operation-2.ini
|
+-- home
| |
| +-- Muzudho
| |
| +-- feature-1
| |
| +-- operation-1
| | |
| | +-- i-have-a-banana.ps1
| |
| +-- operation-2
| |
| +-- i-have-a-palm.ps1
|
+-- opt
| |
| +-- feature-1
| |
| +-- operation-1
| | |
| | +-- application.ps1
| |
| +-- operation-2
| |
| +-- application.ps1
|
+-- README-feature-1-operation-1.md
|
+-- README-feature-1-operation-2.md
「 めんどくさい前準備を終わらせておくことで、現場で手抜きができる んだぜ☆
これを タネを仕込む と呼ぶ☆」
<書きかけ>
Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。
また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!
こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?
コメント