はてなキーワード: ENUMとは
ロックに条件持たせる
やりたいことはできてるように見えるが、うーんしんどい
# Entity Relation Diagram
# ```mermaid
# ---
# title: Rental Office example
# ---
# erDiagram
# OFFICE ||--|{ ROOM : x
# OFFICE {
# number office_id
# }
# ROOM {
# number office_id
# number room_id
# }
# ROOM ||--|{ SCHEDULE : x
# SCHEDULE {
# number room_id
# datetime start_at
# datetime end_at
# }
# OFFICE ||--|{ BUSINESS_HOUR : x
# BUSINESS_HOUR {
# number office_id
# enum week_of_day
# datetime start_at
# datetime end_at
# }
# ```
# Directed Acyclic Graph
#
# ```mermaid
# graph LR
# A[OFFICE] --> B[ROOM]
# B --> C[SCHEDULE]
# A[OFFICE] --> D[BUSINESS_HOUR]
# D --> C
# A --> C
# ```
# 基底クラス: EntityLock
class EntityLock
attr_accessor :entity_name, :entity_locked, :attribute_locks
def initialize(entity_name)
@entity_name = entity_name
@entity_locked = false # エンティティ全体のロック状態を保持
@attribute_locks = {} # IDに対するロックを管理するハッシュ
end
def lock_entity
@entity_locked = true
puts "Entity '#{@entity_name}' is now locked."
end
def unlock_entity
@entity_locked = false
puts "Entity '#{@entity_name}' is now unlocked."
end
def lock(attributes)
entity_id = attributes["#{@entity_name.downcase}_id"]
if entity_id && !@attribute_locks[entity_id]
@attribute_locks[entity_id] = true
puts "#{@entity_name} with ID '#{entity_id}' is now locked."
end
end
def unlock(attributes)
entity_id = attributes["#{@entity_name.downcase}_id"]
if entity_id && @attribute_locks[entity_id]
@attribute_locks.delete(entity_id)
puts "#{@entity_name} with ID '#{entity_id}' is now unlocked."
end
end
def locked?(attributes)
# まずエンティティ全体がロックされているかチェック
return true if @entity_locked
# 次に特定のIDがロックされているかチェック
entity_id = attributes["#{@entity_name.downcase}_id"]
if entity_id && @attribute_locks[entity_id]
return true
end
# ロックされていなければfalseを返す
false
end
end
# 子クラス: OfficeLock, RoomLock, ScheduleLock
class OfficeLock < EntityLock
def initialize
super("Office")
end
end
class RoomLock < EntityLock
def initialize
super("Room")
end
end
class ScheduleLock < EntityLock
def initialize
super("Schedule")
end
end
# 子クラス: BusinessHourLock
class BusinessHourLock < EntityLock
def initialize
super("BusinessHour")
@attribute_locks = [] # BusinessHour用のロックを配列で管理
end
def lock(attributes)
start_at = attributes["start_at"]
end_at = attributes["end_at"]
if start_at && end_at
@attribute_locks << [start_at, end_at]
puts "BusinessHour from '#{start_at}' to '#{end_at}' is now locked."
end
end
def unlock(attributes)
start_at = attributes["start_at"]
end_at = attributes["end_at"]
if @attribute_locks.include?([start_at, end_at])
@attribute_locks.delete([start_at, end_at])
puts "BusinessHour from '#{start_at}' to '#{end_at}' is now unlocked."
end
end
def locked?(attributes)
# まずエンティティ全体がロックされているかチェック
return true if @entity_locked
# 次に特定の時間範囲がロックされているかチェック
start_at = attributes["start_at"]
end_at = attributes["end_at"]
if start_at && end_at
@attribute_locks.each do |(locked_start, locked_end)|
if locked_start <= start_at && end_at <= locked_end
return true
end
end
end
# ロックされていなければfalseを返す
false
end
end
# TreeNodeクラス
class TreeNode
attr_accessor :name, :children, :parents, :lock
def initialize(name, lock)
@name = name
@children = []
@parents = [] # 複数の親ノードを保持する配列
@lock = lock # TreeNodeにロックを持たせる
end
def add_child(child_node)
child_node.parents << self # 子ノードにこのノードを親として追加
@children << child_node
end
def display(level = 0)
indent = " " * (level * 4)
puts "#{indent}#{@name}"
@children.each { |child| child.display(level + 1) }
end
def has_dependency
return false if @parents.empty?
@parents.each do |parent|
puts "#{@name} is dependent on #{parent.name}"
return true
end
@parents.any?(&:has_dependency)
end
def locked?(attributes = {})
# 自身がロックされているか確認
return true if @lock.locked?(attributes)
# 親ノードがロックされているか再帰的に確認
@parents.any? { |parent| parent.locked?(attributes) }
end
end
# 木構造の組み立て
# ロックオブジェクトの作成
office_lock = OfficeLock.new
room_lock = RoomLock.new
schedule_lock = ScheduleLock.new
business_hour_lock = BusinessHourLock.new
# ノードの作成
office_node = TreeNode.new("Office", office_lock)
room_node = TreeNode.new("Room", room_lock)
schedule_node = TreeNode.new("Schedule", schedule_lock)
business_hour_node = TreeNode.new("BusinessHour", business_hour_lock)
# ノード間の依存関係の設定
office_node.add_child(room_node) # Office -> Room
room_node.add_child(schedule_node) # Room -> Schedule
office_node.add_child(business_hour_node) # Office -> BusinessHour
business_hour_node.add_child(schedule_node) # BusinessHour -> Schedule
# 木構造の表示
office_node.display
# ロックの確認
puts "Case 1. Office全体がロックされた場合"
puts "Is office_node locked? #{office_node.locked?({})}" # false
puts "Is schedule_node locked? #{schedule_node.locked?({})}" # false
office_lock.lock_entity
puts "Is office_node locked? #{office_node.locked?({})}" # true
puts "Is schedule_node locked? #{schedule_node.locked?({})}" # true
office_lock.unlock_entity
puts "Case 2. Room id:1 がロックされた場合"
puts "Is schedule_node locked? #{schedule_node.locked?({ "room_id" => 1 })}" # false
puts "Is schedule_node locked? #{schedule_node.locked?({ "room_id" => 2 })}" # false
room_lock.lock({ "room_id" => 1 })
puts "Is schedule_node locked? #{schedule_node.locked?({ "room_id" => 1 })}" # true
puts "Is schedule_node locked? #{schedule_node.locked?({ "room_id" => 2 })}" # false
room_lock.unlock({ "room_id" => 1 })
puts "Case 3. BusinessHour start_at:0 end_at:5 がロックされた場合"
puts "Is schedule_node locked? #{schedule_node.locked?({ "room_id" => 1, "start_at" => 0, "end_at" => 5 })}" # false
puts "Is schedule_node locked? #{schedule_node.locked?({ "room_id" => 1, "start_at" => 5, "end_at" => 10 })}" # false
business_hour_lock.lock({ "start_at" => 0, "end_at" => 5 })
puts "Is schedule_node locked? #{schedule_node.locked?({ "room_id" => 1, "start_at" => 0, "end_at" => 5 })}" # true
puts "Is schedule_node locked? #{schedule_node.locked?({ "room_id" => 1, "start_at" => 5, "end_at" => 10 })}" # false
business_hour_lock.unlock({ "start_at" => 0, "end_at" => 5 })
拡張子については、例えば Excel の拡張子が変わったとき一括対応できる、とか?
あとは普通に".txt" で取り扱ってるファイルはどれだ、って時にその定数の参照箇所を見ればもれなく分かるとか、
取り扱うファイルの種別を段階的に変えようってときも、どのファイルは変え終わっててどのファイルはまだ、とかも同じように分かる
あとはあれだ、どのスコープにおける分類なんだって話を明確にする事も出来るだろうな。
とか。
パラメータについては、複数の選択肢から選ぶ奴は enum にしろよ、とは思うが、
文字コードも大体同じような話か。
自分には6年付き合った年上の彼女がいた。名前はPHP。学生の時からの付き合いで、自分にとっては初めての彼女だった。付き合った当初は全てが新鮮で、オブジェクト指向やSOLID原則、大事なことは全て彼女から教えてもらった。(そう思われるかもしれないが、)時間が経って彼女の魅力が感じられなくなってしまったということはなくて、彼女は歳をとっても魅力的なままだった。むしろreodonlyプロパティやEnum、null safe演算子など、新しい機能が導入されてますます綺麗になっていったように思う。最近ではジェネリクスさえ導入されたようだ。彼女は本当に努力家だ。
(褒められた話ではないが一応、彼女以外の女性を全く知らなかったわけではなく、TypeScriptという若い子と少し遊んでいたこともある。TypeScriptは昔からの知り合いのJavaScriptの妹で、大雑把な姉と違って几帳面で、少しオタク気質もある個性的な子だった。よく新しい型パズルを考案して楽しそうに話してくれたが、自分には正直よく分からなかった笑。)
そんな中でも基本的には6年間PHPとずっと一緒に過ごしてきた。前述の通り彼女に何か不満があったわけではない。ただ、彼女との将来に不安を覚えるようになってしまっていた。周囲に彼女と付き合っていることを話すと、「え、まだPHPと付き合ってたんだ?(昔は人気だったけど、最近はそうでもないよね)」みたいなことを、彼女のことをよく知らない人から言われたりもした。そこまで直接的ではなかったけれど。自分も、彼女以外の女性のことをほとんど知らずにずっと彼女と付き合っていて大丈夫なのかななんて思ってしまったりしていた。
結局自分はPHPと別れて、新しい女性と付き合う決断をした。新しい彼女の名前はGo。彼女は若いのに自分の芯がしっかりしていて、みんなの憧れの格好良い女性といった人だった。そんな彼女と付き合いだして、最初は戸惑うことも多かった。
例えばこんな感じだ。
また、今まで当たり前だと思っていたPHPの良さに気づくことも多い。PHPStanを使えば静的型付け言語と同じように型安全性を担保できていたし、彼女のWeb FWには歴史が長いだけあって痒いところまで手が届く様々な機能が完備されていた。経験豊富でこちらの要望をなんでも受け止めてくれるような包容力があったことに今更気づいた。
とはいえ、いつまでも昔の彼女を引きずっていてもしょうがない。Goにはこちらに積極的に合わせてくれるような包容力はないが、彼女なりの哲学を持っていてそれ故の美しさがあると思う。そして正直、まだ彼女の10分の1も理解できていない。彼女が得意だという並行処理や、実行速度が求められるような処理も、自分はまだ実際に実装したことはない。でもこれからしっかり向き合って、Goのことをもっと理解して、実りのある交際にしていきたいと考えている。PHPと別れてGoと付き合う決断したのは自分なのだから。
時は金なりという意味か?
public class Person { BasicInfo info; float stock; float Value; public string Name(bool isSpy){ return isSpy ? info.Name : info.Name.ToSecondName(); } public string Sex(bool isNormal){ return isNormal == info.isMan ? "Man" : "Woman"; } public float Earn(bool isExtra = false){ float sexPad = info.isMan ? 1f : 0.5f; float racePad = info.isWhite ? 1f : 0.5f; var delta = DateTime.Now - info.Birth; int age = (int)(delta.TotalDays / 365); float result = Value * sexPad * racePad * age; if(isExtra){ Value += result; } return result; } enum Race{ White, Black, Yellow }; class BasicInfo{ public string Name; public int NationalId; public bool isWhite; public bool isMan; public DateTime Birth; public BasicInfo(string Name, int NationalId, Race race, bool isMan){ this.Name = Name; this.NationalId = NationalId; this.isWhite = race == Race.White; this.isMan = isMan; Birth = DateTime.Now; } }
enumすら無いのはきつい
おう!外部キー制約を語るとは、RDB を勉強しているのだな?いい心がけだ。増田は外部キー制約があると「どんなメリットがあるか知りたい」のだな?良し、答えてやろう!外部キー制約があると「変なデータが入らない」ということが開発者が『保証』できるのだ。うん、それで?って増田は思うだろう。それで、実例を挙げるけど、sex というカラムを create で作ったときに、そこに insert into で入る値が「男」「女」「その他」というデータに限りたいときが設計者にあったとする。そうすると、「 insert するのは『チンポ』でしょ?」みたいなアホを防げるだろ?もちろん、limit みたいな副クエリで実装しても構わない場合もある。型を指定して、boolean にしたい場合もある。だが、「入るのはこれだけだと思うが、後に追加で変更できる」としたら、嬉しい場合があるのじゃ。まぁ、究極的に OOP や関数型言語、または(古い)命令形言語だと、enum みたいなものなんだよ。いや、だとしたら、enum でよくね?って思うのなら、リプライくれ。答えるから。
言語によると思う
javaなら普通にオブジェクトでEnumを継承したインスタンスになるからその分メモリ使うし、enum内部で結局String持ってる(コンパイラがStringをEnumの子クラスのコンストラクタに渡す)からStringの方がリソースは無駄にならない
三つ持ってるならintでもboolでもなくenumにする
ねぇXちゃんさぁ。なんでこんな動的なオブジェクトをstaticにしてんの?
これさぁ、そこそこ重いけどさ、セッションごとに生成される一時的なインスタンスで持ってるだけでも十分パフォーマンス的に問題ないよね?
なんでプロセス間でわざわざ共有してんの?
ネットワークリソースつったって利用者はたかだか数百人でしょ?
その中でリソースを同時利用するってゆってもたかだか十数人でしょ?
プロセス内でこのオブジェクトを全共有することでリソースの削減なんてたかが知れてるよね?
それをわざわざプロセス内でこのオブジェクトを全共有ってマジ管理できるの?シンクロナイズドとか書いてっけどさぁ?削減できるリソースの量に比べて超危険すぎねぇ?
コミットログ見たけど、ぜんぜん性能問題とかと関係のない問題の修正だったみたいだけど、なんでこんな危険なコードになったわけ?
Xちゃんさ、そもそもコードが品雑なんだけど、これエンプラJava案件なのよ
なんでCの組み込みコードみたいにif文の鬼ネストとか、引数に空のList渡して破壊的に値を設定するような、読みづらいコード書いてるわけ?
Listくらい普通に返り値で返しなさいよ…
状態管理もif文の鬼ネストやめて専用クラスとかEnum使ってコマンドパターンで対処しなさいよ
もしかして、Xちゃんオブジェクト指向にピンときていないのかな?
俺ちゃんはどっちかってーっとPHPパーなので、ゴリゴリのオブジェクト指向はそりゃ専門じゃないよ
それでもさ、interfaceとか使って、各処理の実装を切り分けるとか、やりようはいくらでもあるじゃん。
あと不要なnullチェックも多すぎです。コンストラクタで初期化が保証されているfinalなフィールド値がnullかどうかなんて確認しないでください
ユーザー入力、DB入力、環境リソースとか、外部の情報起源じゃない変数がnullとか、明らかなバグなんだから暗黙的なぬるぽでクラッシュさせましょう
こんなバグが出荷に乗ることなんてありえません。わざわざ専用のエラー処理で専用の例外飛ばすとか無意味です。
いちいちなんか冗長で複雑なんですよねぇ。
俺ちゃんみたいな若造が、ベテランのXちゃんにこんなこといいたくないけどさ、
Xちゃんのコード。どこか昭和の匂いがするんだよねぇ。悪い意味で。
プログラマなんだけど、なんでも揃えようとしてる人がうざい
よくあるのが、JSON とかオブジェクト系の記述するところで、 「:」とか「=>」みたいなのの位置
揃えられると一見すると見やすいが、金額みたいに揃ったみやすさが必要ないところでされると面倒
10行並んでたら1つ変えたのが原因で10行とも変えないといけなかったりする
面倒だけどツール使えば揃えること自体は楽にできるからこれはまぁいい
だが、バージョン管理ソフトでの変更行数が無駄に増えるのでパット見たときに結構大きな変更してるように見えたりするからちょっとイヤ
さらに grep かけようにも空白数が不定だから正規表現にしないといけない
んだけど、まあここまでは別にいい
この揃えるときに
aaa : { bbbb : 100 ccccc: 200 }, dddd : { e: : 300 }
みたいに(フォントによっては揃ってなく見えるかも)、ネストが違うのに全部を揃えようとするの、ホントやめろ
わかりづらい
上の例みたいなシンプルだと困らないが複雑な構造になってるとかなり見づらい
上でいう aaa と dddd の行が10行程度離れていたら、ここを揃えても全くきれいに見えないし無駄
bbbb と ccccc みたいなときだけならまあ許せる
仏の顔も三度まで、
(1) 文字数を合わせようとする
上で書いたみたいなのは文字数が違うから合わせるためにスペースを入れる必要がでる
きれいなのはわかる、だが無理やり合わせようと単語を探し始めるとかありえない
5つ項目があって、4つが6文字の単語で残りの1つが4文字だったとする
無駄な上に、本来のそれに適した単語じゃないのを無理やり使うのでわかりづらい
揃ってることはパット見綺麗でもプログラムみたいのだと、単語まで似てると気づかないミスが出て来る
beer と bear、 form と from、 fall と fail みたいな見た目が似てる単語と、見た目が全く違う単語の比較ではミスの数が明らかに変わると思う
なのに、 enum みたいな選ぶタイプのもので、数文字違うだけの似た見た目の単語を探してきて選ぶとか、ミスを誘発しようとしてるのかと言いたい
(2) 単語の語尾とか
(1)のように大半が揃ってると残りも無理やりそうしたいということで、単語を勝手に変化させたものがある
例えばだが、語尾が1つを除き全部 -ly になってたとする
そうすると残り一つに無理やり ly をつける
なんなの?イン踏みたいの?ラッパーなの??
そもそも名前みたいな固有名詞にすらそんなことしてるから意味不明にもほどがある
上の時点で英語を完全無視で英語力のなさはわかっただろうが、さらにこういうのもある
過去形には ed 、複数形には s のようなルールには単語によっては特殊な形をするものがあるのはもちろん知ってると思う
プレフィックスに is つけるみたいな単語の組み合わせ部分なら気にしないけど単語としておかしいから、自分で書くときに本来の形で書くとエラーでるからさらにイライラする
例えばこういうこと
readed, catched, taked, companys, boxs, mans, childs, fishs, classs
見てるとムズムズする
英語得意でない自分ですら違和感を感じるのに、これに何も感じないとか英語力ひどすぎると思う
まあエラーメッセージで don't have ~ とすべきところを has not ~ とか書いてたくらいだからなぁ
これが部下とか下の立場の人なら 「使う前にググってみて。おかしかったら『もしかして、~~』みたいの出るから」と言って直させるけど、上だからどうしようもない
間違ってますよー、と遠回しに言ってみたことはあるものの、直す気は全くないようだし、それどころか無邪気に揃えてやったぜみたいなこと言ってドヤ顔してるからホントどうしようもない
私はコミットログの書き方に悩む英語の苦手な人間である。実際、似たような人は世の中に結構いるようで、頻出単語を集計したりまとめたものは既にあって役に立つのだけれど、これらはあくまで単語の話であり、具体的な文を構成する過程でやっぱり困る部分がかなりあった。
要するに、どういう時にどういう文が使われているのか、ということを示した例文集が欲しいのである。ググると他にも「例文集があればいいのに」みたいな声はあるくせして、しかし誰も作ろうとしない。何なんだお前ら。それじゃ私が楽できないじゃないか。
ここで挙げているコミットログは全て実際のコミットログからの転載である。当然ながら各コミットログの著作権はそれぞれの書き手にある。いずれも各英文でググれば出てくるし、フェアユースの範囲なら許してくれるだろうと考え名前とプロジェクト名は割愛したが、ここにお詫びと感謝を述べておきたい。
抽出条件だが、参考にできそうなコミットログを多く含んでいそうなリポジトリをGitHubのSTARの多い方からざっと目で見て適当に選び、それぞれ最新コミットから5000件抽出した(あわせて前処理として、コミットログ冒頭のタグ情報は消去した)。
atomのみ5400件抽出していたため、計25400件のコミットログがベースである。このうち、以下の条件に合致するものは参考例にすべきでないとして一律排除した。
こうして残った8540件を眺めながら、適当に切り出したのがこの用例集である。個人的に「うーんこの」と思った表現も、散見される場合は載せた。
ということで、以下用例を羅列していく。
以上の用例をふまえ、今回の参考ログ8540件から先頭の単語を出現回数で並べると次のようになった。
Add | 1149 |
Fix | 1014 |
Update | 584 |
Remove | 566 |
Use | 382 |
Don't | 260 |
Make | 228 |
Move | 178 |
Change | 103 |
Rename | 85 |
Improve | 76 |
Avoid | 68 |
Allow | 65 |
Implement | 60 |
Handle | 58 |
コミットログの基本形はもちろん動詞 + 名詞である。名詞は固有名詞、複数形、不可算名詞が多いが、単数形の場合の冠詞は a が使われるか、あるいは省略される。the はまず使われない。
何かを追加した、という表現では非常に広く Add が使われる。メソッドからテスト、ドキュメントに至るまで大概これでまかなえる。
一方、何かを修正した、という表現では広く Fix が使われる。「何か」は typo や crash といった単語からメソッド名まで幅広い名詞を取るが、動名詞はあまり取らないのと、that節は取らないのでその点は注意が必要である。
Fix は「何かが正しく動くようにした」ことを示し、正しい動作内容が何かを説明しない。そこで正しい動作内容に言及したい場合は Make sure が使われる(こちらはthat節が取れる)。ただし Fix よりもニュアンス的に重い表現と思われ、Fix を使わず Make sure ばかり使うのはちょっとキモいのではないかと思う(Ensure はさらに重い表現っぽい)。
また、Fix は typo 以外でのドキュメント修正に対して使われることは稀である。対して Update はドキュメント、コメント、テストに使われ、本体のコードの修正に対しては使われない。本体コードの修正にあわせてテストも更新したなら Update が使われる。ただ、テスト機構それ自体のバグを修正したなら Fix である。
無駄な何かを単純に除去したなら Remove を使う。これまでのもの(A)から別のもの(B)に切り替えたのであれば Use B instead of A か Change A to B が使われる。新たに何かを利用するようにしたのであれば Use を、利用を取りやめた場合は Don't use を使うことが多い。
何かをしないようにしたなら Don't を、内部実装の効率化なら Make A + 比較級/形容詞 か Improve が使われる。
中身の変更を伴わない単なる名前の変更なら Rename A to B、コードや機能の論理上の場所を移動させたなら Move A to B である。
この辺はリファクタリングと呼ばれる行為と思うが、Refactor というぼんやりした動詞はあまり使われず、このように変更内容の種類に応じて動詞が使い分けられている。
コミットログにはWhyを書くべきだ、というのを何かで見かけたので because とか since を使ったログがどの程度あるかを調べたが、8540件のうち22件だった。基本的に短く、シンプルに、一目で意味が取れるログが好まれる傾向がある。例えば get rid of とか2件しか使われておらず、圧倒的に remove である。
一方で、シンプルな単語だけど開始単語としては使われないものもある。例えば次のような単語である。Expand(9)、Extend(8)、Print(5)、Optimize(5)、Publish(4)、Append(4)、Modify(3)、Manage(2)、Revise(2)、Dump(2)、Insert(2)、Migrate(2)、Enhance(1)、Edit(1) 。いずれもカッコ内は8540件に対する冒頭での登場回数である。結局、より一般的で平易な単語で表せたり、Refactor同様に抽象度が高すぎると使われないのだろう。
8000件もログを見たおかげで、迷いなくコミットメッセージが思いつくようになったのが個人的には今回書いてて最大の収穫だった。たぶんカンニングペーパーを作る行為それ自体が効率のいい学習になるという話と同じだと思う。
このまとめも100以上用例を転載してあるので、それを読むだけでも多少は効果があるんじゃないかと思う。同じようにコミットログ書きたくねぇなぁ英語わっかんねぇなぁと思っている人にとって、何か役に立つところがあれば幸いである。
ちょっとした事情からシステムディスクの移設をしたところかなり躓いたので、備忘録的にメモ。
時代に逆行して個人的な書き物をする場所を一切持ってないのでお借りします。
以下、Linuxなりの最低限の知識があり、バイトオーダーもわかり、細かいところは勝手に補間できる人向け。
オフセット32256バイトを1048576バイトに調整する。
得てして非AFTからAFTという状況と思われる。
コピー元が壊れかけの時はやらないほうが吉。