はてなキーワード: 木構造とは
ロックに条件持たせる
やりたいことはできてるように見えるが、うーんしんどい
# 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 })
で・・・できたけど木の組み立てがしんどすぎるー
class TreeNode:
def __init__(self, name, attributes=None):
self.name = name
self.attributes = attributes or {}
self.children = []
def add_child(self, child_node):
self.children.append(child_node)
def display(self, level=0):
indent = " " * level
print(f"{indent}{self.name} {self.attributes}")
for child in self.children:
child.display(level + 1)
def has_dependency(self):
# ルートノードや属性を持たないノードは依存関係を判定しない
if not self.children:
return False
for child in self.children:
# 子ノードがBusinessHourかScheduleかをチェック
if "start_at" in child.attributes and "end_at" in child.attributes:
child_start = child.attributes["start_at"]
child_end = child.attributes["end_at"]
# 現在のノードがBusinessHourで、子がScheduleの場合
if "start_at" in self.attributes and "end_at" in self.attributes:
self_start = self.attributes["start_at"]
self_end = self.attributes["end_at"]
if self_start <= child_start and self_end >= child_end:
print(f"{child.name} (start_at: {child_start}, end_at: {child_end}, room_id: {child.attributes['room_id']}) is dependent on {self.name} (start_at: {self_start}, end_at: {self_end})")
else:
print(f"{child.name} (start_at: {child_start}, end_at: {child_end}, room_id: {child.attributes['room_id']}) is NOT dependent on {self.name} (start_at: {self_start}, end_at: {self_end})")
# 現在のノードがRoomで、子がScheduleの場合
elif self.name.startswith("Room"):
print(f"{child.name} (start_at: {child_start}, end_at: {child_end}, room_id: {child.attributes['room_id']}) is dependent on Room {self.name[-1]}")
else:
child.has_dependency()
# 子ノードが属性を持たない場合、再帰的に依存関係をチェック
else:
child.has_dependency()
# ノードの作成
root = TreeNode("Root")
office_node = TreeNode("Office")
# Roomノードの作成
room1_node = TreeNode("Room1")
room2_node = TreeNode("Room2")
# BusinessHourノードの作成
business_hour1_node = TreeNode("BusinessHour1", {"start_at": 9, "end_at": 12})
business_hour2_node = TreeNode("BusinessHour2", {"start_at": 13, "end_at": 17})
# Scheduleノードの作成
schedule1_node = TreeNode("Schedule1", {"start_at": 10, "end_at": 11, "room_id": 1})
schedule2_node = TreeNode("Schedule2", {"start_at": 14, "end_at": 15, "room_id": 1})
schedule3_node = TreeNode("Schedule3", {"start_at": 10, "end_at": 11, "room_id": 2})
schedule4_node = TreeNode("Schedule4", {"start_at": 14, "end_at": 15, "room_id": 2})
# 木構造の構築
root.add_child(office_node)
office_node.add_child(room1_node)
office_node.add_child(room2_node)
office_node.add_child(business_hour1_node)
office_node.add_child(business_hour2_node)
# Room1にSchedule1, Schedule2を追加
room1_node.add_child(schedule1_node)
room1_node.add_child(schedule2_node)
# Room2にSchedule3, Schedule4を追加
room2_node.add_child(schedule3_node)
room2_node.add_child(schedule4_node)
# BusinessHour1にSchedule1, Schedule3を追加
business_hour1_node.add_child(schedule1_node)
business_hour1_node.add_child(schedule3_node)
# BusinessHour2にSchedule2, Schedule4を追加
business_hour2_node.add_child(schedule2_node)
business_hour2_node.add_child(schedule4_node)
# 木構造の表示
root.display()
# 依存関係のチェック
office_node.has_dependency()
room1_node.has_dependency()
room2_node.has_dependency()
business_hour1_node.has_dependency()
business_hour2_node.has_dependency()
Root {}
Office {}
Room1 {}
Schedule1 {'start_at': 10, 'end_at': 11, 'room_id': 1}
Schedule2 {'start_at': 14, 'end_at': 15, 'room_id': 1}
Room2 {}
Schedule3 {'start_at': 10, 'end_at': 11, 'room_id': 2}
Schedule4 {'start_at': 14, 'end_at': 15, 'room_id': 2}
BusinessHour1 {'start_at': 9, 'end_at': 12}
Schedule1 {'start_at': 10, 'end_at': 11, 'room_id': 1}
Schedule3 {'start_at': 10, 'end_at': 11, 'room_id': 2}
BusinessHour2 {'start_at': 13, 'end_at': 17}
Schedule2 {'start_at': 14, 'end_at': 15, 'room_id': 1}
Schedule4 {'start_at': 14, 'end_at': 15, 'room_id': 2}
Schedule1 (start_at: 10, end_at: 11, room_id: 1) is dependent on Room 1
Schedule2 (start_at: 14, end_at: 15, room_id: 1) is dependent on Room 1
Schedule3 (start_at: 10, end_at: 11, room_id: 2) is dependent on Room 2
Schedule4 (start_at: 14, end_at: 15, room_id: 2) is dependent on Room 2
Schedule1 (start_at: 10, end_at: 11, room_id: 1) is dependent on BusinessHour1 (start_at: 9, end_at: 12)
Schedule3 (start_at: 10, end_at: 11, room_id: 2) is dependent on BusinessHour1 (start_at: 9, end_at: 12)
Schedule2 (start_at: 14, end_at: 15, room_id: 1) is dependent on BusinessHour2 (start_at: 13, end_at: 17)
Schedule4 (start_at: 14, end_at: 15, room_id: 2) is dependent on BusinessHour2 (start_at: 13, end_at: 17)
Schedule1 (start_at: 10, end_at: 11, room_id: 1) is dependent on Room 1
Schedule2 (start_at: 14, end_at: 15, room_id: 1) is dependent on Room 1
Schedule3 (start_at: 10, end_at: 11, room_id: 2) is dependent on Room 2
Schedule4 (start_at: 14, end_at: 15, room_id: 2) is dependent on Room 2
Schedule1 (start_at: 10, end_at: 11, room_id: 1) is dependent on BusinessHour1 (start_at: 9, end_at: 12)
Schedule3 (start_at: 10, end_at: 11, room_id: 2) is dependent on BusinessHour1 (start_at: 9, end_at: 12)
Schedule2 (start_at: 14, end_at: 15, room_id: 1) is dependent on BusinessHour2 (start_at: 13, end_at: 17)
Schedule4 (start_at: 14, end_at: 15, room_id: 2) is dependent on BusinessHour2 (start_at: 13, end_at: 17)
class TreeNode:
def __init__(self, name, attributes=None):
self.name = name
self.attributes = attributes or {}
self.children = []
def add_child(self, child_node):
self.children.append(child_node)
def display(self, level=0):
indent = " " * level
print(f"{indent}{self.name} {self.attributes}")
for child in self.children:
child.display(level + 1)
def has_dependency(self):
# ルートノードや属性を持たないノードは依存関係を判定しない
if not self.children or "start" not in self.attributes or "end" not in self.attributes:
return False
# Aノードのstartとendを取得
start = self.attributes["start"]
end = self.attributes["end"]
# すべての子ノード(Bノード)に対して依存関係をチェック
for child in self.children:
if "position" in child.attributes:
position = child.attributes["position"]
if start <= position <= end:
print(f"{child.name} (position: {position}) is dependent on {self.name} (start: {start}, end: {end})")
return True
else:
print(f"{child.name} (position: {position}) is NOT dependent on {self.name} (start: {start}, end: {end})")
return False
# ノードの作成
root = TreeNode("Root")
a_node = TreeNode("A", {"start": 10, "end": 20})
b1_node = TreeNode("B1", {"position": 15})
b2_node = TreeNode("B2", {"position": 25})
# 木構造の構築
root.add_child(a_node)
a_node.add_child(b1_node)
a_node.add_child(b2_node)
# 木構造の表示
root.display()
# 依存関係のチェック
a_node.has_dependency()
こうかー
いまさらすぎるけどいまさらいまさらなスープストックの雑記事が上がってきたのでなんか考えたこととか書き残そうかと思う。
絵描きの世間ではパトロンサイトからAI作品が排除されて大勝利を唱和しているかと思う。
増田は、うーむ、(デジタル)手書き絵描きの溜飲は下がったけど勝てていない、遅滞成功ぐらいかなと予想する。
今回、(デジタル)手書き絵描き側に阿ったような内容になったのは、ひとえに(デジタル)手書き絵描きがお気持ち駆動する厄介な人間であることと、既存顧客であったから。
絵描きがお気持ち駆動することは今更言うまでもないが、トレパクや、絵はグレーセーフでグッズはぶったたくとかガイドラインや二次創作のありかた、検索避け、学級会などなど、感情と(日本の法律で有罪無罪問わず)私刑が先行する人類全体が持つ宿痾をとくに煮詰めたような人種が横行する界隈だ。
そんな(デジタル)手書き絵描きが自分の感情を害するAIを敵視するのは当然で、もちろんお気持ちクレームを多発する。した。
ハッキリ言って商売相手的にはクズの部類に入るが、それでも掴んだ、囲んだ顧客というのは大事だ。未だにみんなTwitterをしていることからもそれはわかるだろう。
だからギャーギャーうるさいものの大事な金ヅルな猿たち側に寄り添ったものの、本音はAI作品を取り扱いたかったと思う。
プラットフォーマーから見て(デジタル)手書き絵描きの反応はある意味予想通りだったが、それでも絵描きたちが容認する可能性もあっただろう。なぜならいわゆるAI絵師は絵描きの進化ツリー(木構造でもないし相互移行できるけど)に(今しばらくは)連なるものだからだ。AIは部分的にも全体的にも絵描きのツールになりえる可能性があるのは明白だろうし、AI絵の今後の発展は確実で不可逆であることもただの一般人でも感じるところだ。絵描きはいつかは向き合わなければならない問題。だからプラットフォーマーは即座に禁止せずしばらく様子見した。しかし結果、総体としての絵描きの感情、お気持ちだけの反対に落胆し、禁止に舵を切った形だ。もちろん審査の負荷や創作性などの表向き(かつ多少なりの事実)の理由もお出ししながら。
プラットフォームを分散させるのは管理が面倒だし人の分散もよくない。が、こうなったからにはpixivやエイシスは今後、AI作品を扱える別のサービスを開始するだろう。AIによる創作は確実に伸びていく分野だからだ。できれば既存サービスに組み込みたかったが、それこそ先行者の悲しみ・デメリット。顧客の属性が厄介に固まったばかりにそれはあきらめるしかなかった。
そして、そんなやっかいな既存顧客が居ない今後のfanboxやskebのような後発の類似サービスはほとんどがAI作品を許容する形でスタートするだろうし、AI禁止を謳う類似の後発サービスが現れたとしてもfanboxやskebなみには成長できないだろう。
AI禁止+AI専門 VS AI許可 のどちらが中期的に勝つかまではわからないが…。
あくまで今回の足並みをそろえたような方針は旧世代の、乗り換えや手札にできず取り残された、しかし金ヅルの老人たち。そんな(デジタル)手書き絵描きの無聊を晴らすためのものだった。日本で老人のための政策を打った場合の若年層の反応を想像してもらいたい。…その政策は勝利なのだろうか。勝利なのだろう。老人には。
改めて書くが、今回の(デジタル)手書き絵描きの大勝利は彼らに理があったからではなく、ただただあらゆるサービスは顧客を定着させることが大儀であり、かつデジタル空間では物理空間よりは比較的サービスの分割がしやすいからだった。
理ではなく金銭的な損得をもって鳴き声がうるさいが金を生むガチョウと今後プラチナを生む可能性があるアヒルの子を同じ柵に入れることをやめただけ。
経営者や業態、進化ツリーの進み具合・将来性などを勘案すれば、うるさい声を無視して進むべきと予測した道に突き進む場合もある。スープストックの場合はその例だったのだろう。お気持ちでギャオンと騒ぐ先細っていく独身女性の声に揺るがず、データと検証から出た客のライフスタイルの変化や世代をまたいだブランドイメージ、立地・戦略的に別サービスに分離できない(切り捨てるなら独身女性側だろうが)飲食という理由などなどをもって離乳食無料を決定したのだろうし、その反応にたいしての声明リリースをおこなったのだろう。
そして結局(デジタル)手書き絵描きも独身女性も哀れな人間であることは変わらない。
(デジタル)手書き絵描きが今、良い気分ならばそれでもいいだろう。将来結構な数の(デジタル)手書き絵描きがAIに流れるのも笑わない。(デジタル)手書き絵描きでなくてもAI絵師でも気質は別に変わらないしね。AI絵師が優れてるとも思わず絵描き全体がやっかいな人種だと思っているので。次の技術で同じお気持ちの絶叫が響くのも確実さね。
そう、増田は今回の騒動で絵描きがどういう人種であるかということを再確認させてもらった。程度しか得るものがなかった。
あるいは広がりゆくAIという腐海にあらがい風の谷という猫の額で生きる旧人類(新人類)の悲劇を観賞している気分にもなれるかもしれない。どっちかっつーと手作り宗教の土鬼か。
MLMユーザー諭そうとしたら何かよく分かんない単語並べられて逆に論破されたそこのアナタ!今から言う報酬プランを覚えるだけでギッタギタのボッコボコに出来るので覚えましょう!
まずその前に基本情報。日本の人口は1.2億人。15歳以上は1億人。
要は差益が報酬になるプランです。MLMは大体ランクが定められておりランク毎に商品価格が違ったりします。低ランクほど高価格で高ランクほど低価格。で自分の下に居る会員が商品を買ったときに自分のランクの価格と買った会員の価格の差額がそのまま報酬になるパターンです。計算しやすい反面自分が絶えず売り込まない限りは報酬が途絶える歩合制の営業みたいなもんなのでガツガツ売り込みにくるMLMの人はこの報酬プランかもしれません。店舗で買ってアマゾンのマケプレに高額で出品している転売屋みたいなものだと思ってください。
いつまでも営業なんてしてられない!って人にはこのプラン。このプランでやるべきはたった二人を自分の下に付けるだけ!あとはその二人の尻を叩くだけ。このプランは下二人の売上の内、低い方の売上を基に報酬を計算されるぞ。ちなみに二人の売上にはその下の会員の分も含まれる。バイナリーって単語でプログラマとかはピンとくるかもしれないが二分木構造のツリーが出来上がるのだ。片方だけ深くなっても報酬は増えないので上の会員は下の2名両方に頑張れ言う必要があるぞ。でもある程度育ったら何もしなくても金入ってくる夢のプランだ(実際は受取り条件とかあるが)
営業したくない。下の二人に絶えず叱咤激励もしたくない!って人にはユニレベル。これは何かと言うと毎月自分の下の会員が買った売上の数%が報酬になるプラン。ランクが低いと自分の下の会員しか対象にならないけど、ランクが上がれば自分の下の会員が紹介した会員も対象になり、もっとランクがあがれば更に下の会員も対象になる。バイナリープランみたいに全体の成長を考える必要ないのでとにかく自分の下に人を勧誘してしまえば良い。あとはその人達が頑張れば勝手にお金が入ってきます。極端なツリー構造になっても余り影響がなく会員が抜けても大して問題は無いですが継続的な購入は不可欠なので買え買えうるさい人が多いです(他のプランでもうるさいけど)
以上3つのプランを覚えておけばMLM通ぶれるぞ。なんだって?バイナリープランだと27段で日本人口超える?ユニレベルだともっと早くに限界くる?そんなのMLMがマルチまがいとかねずみ講って言われてた頃から知っとるわ。だからMLM企業は複数の報酬プランを用意してその辺のツッコミを躱すし禁止言うても実際は大多数の会員はMLMの複数掛け持ちをしているよ。だから日本人口とか意味ない。1人がMLM10個に属すれば人口10倍!死んだ爺ちゃんも飼ってるペットも今日から会員。在庫は全部家の納屋。MLMは先行逃げ切りが鉄則。今更老舗に参加したってなんも残ってないし出来るのは上の会員に媚び使って引退時に引き継がせてもらうとかだけよ。あと海外でも出来るとか移民が増えて1億じゃなく80億もありますとか言うMLM企業もあるけど言葉通じない相手に上記プランの営業活動出来る?別に世界のどこでも盛んでも無いからなMLM。
割りとマジだよねと思う出来事をふと思い出したので書いてみる。
といっても後輩が俺の思ってもいないところでつまづいて、それに俺がカルチャーショックを受けたというだけの話。
問題の話なんだけど、とある有名サービスのJSON APIを叩いて呼び出し結果を手元のオブジェクトにマッピングするというただそれだけのコードを書くというもの。
普通に考えて一日もしないで出来ると思うような代物だけど、三日以上悩んで彼はそれでも出来なかった。
{ ..., "count": 10000000000000000000000000000000000000, ...}
という感じで多倍長整数がリテラルとして書かれているのを前提として受け取る仕様だった。
JavaScriptの通常の整数と違って、JSONの整数リテラルは仕様上大きさの制限の記載がないので、上のようなのも合法。
で、彼の使ってたプログラミング言語のオブジェクト から JSONの変換ライブラリが、多倍長整数を文字列("")としてシリアライズするような仕様なことがわかって、彼は行き詰まった。
そこで何をやり始めたかというと、JSONの整数がそのまま1000000000000000みたいにシリアライズされるライブラリ探し始めたんだけど、それは見つからないまま。
というわけで「増田さん、詰まってるんですけど……」と言われて助け舟出すことになったはいいものの、彼のコード見るとJSONの抽象構文木クラスがそのまま使えるようだった。
なので、
String serialiaze(Ast.JsValue value) { return switch(value) { case Ast.JsNull nullValue-> "null"; case Ast.JsInt bigIntValue -> bigIntValue.toString(); case Ast.JsArray arrayValue -> arrayValue.stream().map(v -> serialize(v)).collect(Collectors.joining(", ", "[", "]")); // 他のJSONの木についても同様に処理 default -> throw new RuntimeException("cannot reach") }; }
1時間しない内にこんな感じのコード(言語はJavaじゃなかったけど、だいたいこういう感じ)を書いて無事問題解決。細かいタイポとかあるかもだけど、日記では確認してないのでそれはおいといて)。
結局、JSONの形が期待と違って、しかも既存のAPIじゃいいのがなかったのに延々API探すことしか出来なかったのが問題解決できなかった原因だけど、このくらいのは割りとちょこちょこある。
きっと、それから一週間放置しても問題解決できなかっただろうし、どうも同じチームの同僚も問題を解決できなかったようだった。
最近、APIは叩けるけど、そこでトラブルとどうにもならなくエンジニアにちょくちょく遭遇するんだけど、やっぱりもうちょっと基礎出来てないと駄目だなと思った出来事だった。
取り上げた技術は、本格的な開発でも役に立つもので、最も学習コストが低いものを選んだ。
重要度が低いものは載せていない。たとえばHTMLとCSSなんてググりながら書けば全く問題ない。Bootstrapなどのフレームワークも全くやる必要はなく、仮に就職先で使っていたら覚えればいい。
逆に言えば以下に挙げる技術は、そもそも概念自体がプログラミングにとって普遍的なものであり、(基礎的な部分を)調べながら使うようではエンジニア失格ということ。
基本的に現在では、バックエンド・フロントエンド・運用保守全てができないエンジニアに価値は無い。
以下に挙げた技術(①⑤⑥は他の言語やフレームワークで代替可能)が身に付いていなければまともな企業に就職することは難しい(もちろん、下らない業務システムを下請けで作ってる底辺企業には入れるだろうが)。
経験者でも、これらができない/わからないのは、相当恥ずかしいことだと思った方がいい。
特定の言語やフレームワークの書き方を知っていること自体に意味は無い。
重要なのは、他の言語やフレームワークにも共通する基礎を理解すること・保守性やセキュリティなどの品質を高める使い方ができること。
この2つは習得が容易だし、今覚えておけば向こう10年腐ることはないだろう。
基本的な構文や、よく使う標準ライブラリは勿論、高階関数・クラス・非同期処理等の発展的な機能も知り尽くしていなければならない。
言語のみではなく、パッケージ管理、単体テスト、タスクランナー等の周辺ツールの使い方も熟知している必要がある。
また、「リーダブルコード」や「コードコンプリート」に書いてあるような良い作法も身に付ける必要がある。
Gitを使えないのはプログラマーとして論外。細かい機能は調べればよいが、
多くの場合、本番環境やテスト環境はLinuxサーバーであるから、以下のような基本的な概念と使い方を知っておく必要がある。
環境構築、CI、デプロイなどは、現在コンテナを使って行うことが当たり前になっている。
これも細かいことをすべて覚える必要はないが、Dockerfileの書き方や、docker-composeの使い方などは知っておかなければいけない。
Flaskは、数あるWebフレームワークの中で最も簡単。本当に呆れるほど簡単で、Pythonさえ書ければすぐにアプリを作れる。
フレームワークを覚えること自体が重要なのではなく、Web開発の基本を習得することが重要。HTTP、ルーティング、データベース、SQL、認証、セッション管理などは当然すべて覚える。
データベースは、就職したらMySQLやPostgreSQLなどを使うことが多いかも知れないが、今はPythonの標準ライブラリにあるSQLite3を使えば十分。
作ったアプリを公開したければ、「Heroku」などにデプロイするのが良いだろう。
ブコメで指摘をいただきました。HerokuではSQLite3は使用できないようです。公式のドキュメントに従ってPostgreSQLを使用して下さい。
SQLite3はファイルにデータを持てる簡易DBなんだけど、Herokuにデプロイしてもストレージ的な使い方はできないから、結局PostgreSQLを使う必要あるから注意してね。(DAOを丸ごと書き換える羽目になる)
参考: https://devcenter.heroku.com/ja/articles/sqlite3
今の時代、フロントエンドをフレームワークなしで作るのはただのバカ。
2021年現在、実用的なフロントエンドのフレームワークはReactとVueしかない。Vueの方が少し簡単なのでこちらを選んだが、JavaScriptをしっかり理解しているなら大差は無い。
フロントエンドには膨大なパッケージ群があって全部覚えるのは大変だが、とりあえずまずはVueを完璧に使えればいい。Webpackの設定などは既存のものを流用すればいい。
アルゴリズムは全てのコンピュータ技術の基礎であり、絶対に知っていなければならない。
高速フーリエ変換のような高度な数学は必要ないが、クイックソートや木構造のような基本的なアルゴリズムは当然、その性質を知っていなければならない。
それらは言語の組み込み関数や標準ライブラリでも使われており、理解していなければ、それらの機能を正しく使うことができない。
また、プログラムを読み書きする際には、そのコードの計算量を見積もれなければならない。
セキュリティは言うまでもなく学ばなければならない。
有名な脆弱性や攻撃手法(XSS・SQLインジェクション・CSRFなど)が何だか理解していて、その対策を実装できなければならない。
各種暗号化技術や署名などについても、実装の詳細は知らなくていいが、共通鍵暗号や公開鍵暗号などの特性は理解する必要がある。
プログラミングで食っていくためには、他の職業と同様に様々なスキルが必要になる。単に技術的な面だけに絞っても、以下のようなことが出来なければ話にならない。
プログラミングスクールなどを卒業したゴミには、(1)〜(2)もしくは(1)だけを以て「自分はプログラミングが出来る」と勘違いしている奴が多い印象がある。
本当に嫌になる。
見よう見まねでコード書いてるだけのゴミはプログラマ名乗らないでくれ。
他にもいろいろ書きたいこと(ネットワーク、データベース、セキュリティ、OS、ハードウェア等)はあるが、ソースコードが書けるという点だけにフォーカスすれば、この程度は最低限できないと困る。
上に書いたようなことが完璧にできると断言できない奴が、プログラマを名乗るのがいかに非常識で恥ずかしいことなのか、よく理解して欲しい。
第一章『関係を記述する方法としての「基準」とその基準からの「指定」』
このベーシックイングリッシュの分析においては、「基準」とその基準からの「指定」という概念が、フローチャートの他に重要なものとして出てくる。なぜか。
それは自然言語においては下の図のような統語法則が使われるからで、そのままでは単語AとBの関係を記述する際に、図の通りで、集合論的にどちらかがどちらかを直接的あるいは間接的に含むという風にしか記述できない。(木構造は、ただ何が何を含んでいるかを表しているという意味で、集合論を線で表したものでしか無い)
https://ja.wikipedia.org/wiki/%E4%B8%BB%E8%A6%81%E9%83%A8#/media/File:Kafka_English_tree.jpg
※この英語の図では動詞が主語を含んでいて、また「monstrous verminous bug」が「a」を含んでいると解釈されているが、事実として『主語が動詞を含んでいて、またaがbugを含んでいる』と解釈するのも意味的には可能な文で、私は後者を採用している。「monstrous verminous bug」は一語として認識されていると考えている。
https://ja.wikipedia.org/wiki/%E4%B8%BB%E8%A6%81%E9%83%A8#/media/File:Kafkaj.jpg
※wikipedia「主要部」から引用。 https://ja.wikipedia.org/wiki/%E4%B8%BB%E8%A6%81%E9%83%A8#%E4%B8%BB%E8%A6%81%E9%83%A8%E5%85%88%E5%B0%8E%E5%9E%8B%E8%A8%80%E8%AA%9E%E3%81%A8%E4%B8%BB%E8%A6%81%E9%83%A8%E7%B5%82%E7%AB%AF%E5%9E%8B%E8%A8%80%E8%AA%9E
そこで必要になるのが「基準」とその基準からの「指定」で、ある単語を基準に他の単語を指定するということによって、二つの単語の関係が様々に記述できるようになる。
例えばAとBが隣り合っていることを記述したいとする。記述する方法を自由に設定できるならば、「A B」と記述すれば良い。これなら「右」という単語も「左」という単語も必要無い。
ただ自然言語においては、これではAがBを含んでいるということになってしまう(あるいはBがAを含んでいるということになってしまう)。そこで、Aを基準にすればBが右にあり、Bを基準にすればAが左にある、というような記述方法が必要になる。
(ちなみに「right」や「left」には、前後の他に上下も必要になる。前後と上下が定まって、右や左が生まれる。上下は重力によって生まれていて、重力は自然現象なので、この分析では「right」と「left」は考察の対象外とし、付録の『本文に掲載されていない単語一覧』に掲載している。)
朝日新聞の記事を鵜呑みにして検証が表立ってほとんどなされず、毎日新聞他の記事は黙殺されたままに見える。挙げ句は大元が「改ざん認める」と言う。決済された文書を、何をどう書き換えたのかを明示して欲しい。
というか、枝葉のところばかり見ていないで、全体の整合性を意識して欲しい。万が一、決裁者全員が結託して書き換えたのだとしても、大きな組織の中の末端が起こしたトラブルなぞ最上位の人が知るわけないじゃない。毎回末端まで把握する必要があるのなら、アホほどコストを払う必要があるし、木構造の組織にする意味もない、実に非現実的な世界が待っている。
全体の舵取りが実におかしい。
ともかく、国運営が自国のみならず周辺国交えて微妙な立場(北朝鮮だけでなく、中国の圧力や、暴れ米国の手綱、国際的イベントである自国オリンピック開催を控えて(韓●は自分のところのが概ね終わったら反日をモリモリ出してきているし)、また国内の生活水準の底上げが始まったばかり)なのに、足を引っ張っている人たちは何をしたいのか。
軍という単語にアレルギーを持つのは仕方ないにしても、平時の備えがいざというときに役に立つのは天災に対してだけでは無いことを認識して欲しい。
国際的イベントで恥をさらすということは、それだけ国力の低下を海外にさらすことにもなる。
景気(「気」だけあって心持ち次第)回復についても、稼いだ人たちを引きずり落とすつもり満々な発言をしている人たちがいる。どう考えてもアベノミクスを打ち出した当時は、金を持っている人たちを太らせて引っ張ってもらうトリクルダウン方式が効果的だっただろうに。行き渡りにくいという問題については改善の余地が大ありだろうけど、皆で貧乏になる案よりははるかにマシだったろう。
「国民は納得していない」という無敵ワード(前に進まないし、そもそもここでの「国民」って具体的にだれ?)だけで足を引っ張り続ける野党さん左翼さんはどう責任を取ってくれるのだろう。こちらこそ納得してないわい。
一行目と国運営についてだけをどこかで言いたくて勢いのまま書いてしまった。反省はしていないけど、自分の生きる世の中の動きが本当に心配だ。
2014/1/1 全文が正しく表示されていないことに気づいたため修正した。遅ればせながら指摘に感謝したい。
才能のあるワナビは己の思うがまま書き連ねればそれで問題ない。一次落ちなど経験することも無く、一発で新人賞を取ったり、取れなくても編集者が連絡してきたりして遅かれ早かれデビューに至り、そしてワナビに向けたラノベ創作論を書いたりする。私はこうやってプロとして本を書いてます、どうぞ参考にしてください。
これが意味するところは、才能のあるワナビは他人の書いた創作技術本を読んで必死にトレースしたりなどしなかった、という非情な現実である。ノウハウ本を欲するのはいつだって才能のないワナビで、そして才能の無いワナビは今日も選考落ちの通知を見て顔を覆うのである。○○先生の本に書いてある通りにやったのにどうしてダメなんだろうか。何がダメなんだろうか。
スティーブン・キングがプロットなど不要だと言う一方でディーン・クーンツはプロットの無い作品など糞だと断じる。大塚がまずキャラから作れと言う一方で冲方は世界から作らないようでは話にならないと言う。
ラノベに限らず小説創作技術本はそれぞれの主張がまるでバラバラであり、まとまりがない。もっともこの手の本は意識の高いサラリーマンがこよなく愛する成功体験本と同じカテゴリである。ゆえに真面目に考える必要は無いとするのも一理あるだろう。
実のところ彼らは単に表現が違うだけで、最終的に同じことを述べてるのではないだろうか。
手順が違うだけで、結局同じことをしているのではないだろうか。
もしそうだとすれば重要なのは手順ではなく最終的にどういう状態であるかにあり、その状態がいずれの作家も共通しているのであれば、それこそが欠かすべきではない要素ではないのか。
大沢は「技術は教えられるが、才能は教えられない」という。だがヒックスは「モノを書くことでの才能の問題は、相当に過大評価されて」いるとして、「それはやっていくことで獲得」できるものだと言う。
Hard work beats talent when talent doesn't work hard.
Tim Notke
本稿は個別の手順というより、最終的にどういった状態を目指しているのか、という観点でラノベ創作技術本の各説を整理し、俯瞰する。筆者はワナビではなく、単なる興味本位でこの整理を行ったに過ぎない。しかし才能が無いことを自覚し、それでもなお努力によってこれを覆そうというワナビにとって、本稿がより効率的な努力を実現する上での一助となれば幸いである。
本稿ではラノベを「ラノベの主要レーベルの新人賞に向けてワナビが執筆する、新人賞を取りうる内容の小説」と定義し、本質的なラノベの定義へは踏み込まない。このことからカテゴリエラーをめぐる問題はこのラノベの本質的定義の限界を探ることと同義であり、本稿では割愛する。
本稿執筆にあたり参考とした文献を下記に記載する。
まだ参照すべき文献は多くあるが、ひとまず本稿執筆にあたっては上記で一区切りとした。
ラノベ作家は商業主義であらねばならない、と五代/榊は明言し、飯田はキャッシュフローを生む作品こそが素晴らしい作品なのだという。実際、ラノベ新人賞は商業的に売れるラノベの発掘を目的としているのであって、ワナビの承認欲求を満たすためにあるわけではない。
新城はラノベの読者の多くは男子中高生であり、すなわち「毎月のお小遣いが限られている学生」であるとする。飯田はさらにラノベの読者はアニメや漫画、ニコニコ動画を好むオタクであるとする。そしてラノベは彼らの限られた小遣いの使い道として選択される商品でなければならない。榎本も西谷も水島も、いずれも同様に読者が誰かを意識しろと主張する。
ところでワナビが書いた新人賞用のラノベの読者は、中高生ではない。
新人賞の下読みの多くは大学生のバイトであり(あるいは主婦や新人編集者)、選考するのはプロの作家であり、プロの編集者である。いずれにせよ選考過程に中高生は存在しない。
読者が誰かを考えるべき、という指摘はもっともだが、プロの作家とワナビでは立場が違う。ワナビはラノベレーベルで勤めるサラリーマン編集者が想像する『中高生』にウケるラノベを書かなければならない。榎本は現実の中高生とふれあい彼らの考え方を理解しろと言うが、本当にそんなことをすれば事案待ったなしのワナビは少なからずいるだろうし、現実の中高生には圧倒的にウケるが20代30代の編集者には全く理解できないものがあったとすれば、それは間違いなく一次落ちである。
行頭は一段空けましょう、といった小説執筆上のお作法ができていなかったからといって間違いなく多くの中高生は気にしない。しかしプロは気にする。そうした基礎的作法の欠如は中高生云々の前にまず彼らに不快感を生じさせる、という点を理解しておく必要があるだろう(応募に際してはあらすじを付すようにという指示に対して小説の煽り文や序文を付けるといった無理解なども根は同じだろう)。
最終的なラノベに至るまでの執筆上の段階や要素は論者の数だけ存在する。例えばキングによるアイディア、原稿の2段階、クーンツを始めとするアイディア、プロット、原稿の3段階、冲方による能書き、種書き、骨書き、筋書き、肉書き、皮書きの6段階などがある。
本稿では「アイディア」「プロット」「原稿」の3段階を用いて各説を俯瞰する。この各段階は「アイディア」が最初であるという点を除けば、随時行き来することがいずれの説においても許容される。一度「プロット」に移行したら「アイディア」へ戻ってはならないなどと主張されることはないし、「原稿」の完成に至ってから再度「アイディア」の段階に戻る作家も存在する。
一方で、これらの「段階」はそれぞれ独立しているわけではないことに注意する必要がある。いずれもその前段階の上に構築されている。つまり、あるワナビが「プロット」に問題があると認識したとしても、その前段階に問題がある可能性は否定できない。これは感想や選評においても言えることであり、問題点の指摘がまったく的外れでなかったとしても、その問題を引き起こしているそもそもの原因は何なのか、という点を突き詰めなければ、根本的な問題はいつまでたっても解消されないままだと言えよう。
以下、それぞれの段階についての各論に入る。
「アイディア」とは筒井がいうところの「妄想」であり、単語、キーワード、フレーズ、断片的な会話や場面など様々なものであり、その創作で用いるかもしれないし、用いないかもしれないネタである。
冲方は「アイディア」を3段階に分けており、まず主題を考え(これを能書きと称する)、次にそこから様々な雑多なアイディアを連想し(種書き)、今回はこのあたりのアイディアを使おう、と決めて整理する(骨書き)という。
しかし実際には冲方自身、これらを行きつ戻りつして執筆を進めていくとしており、「骨書き」の段階からは後戻りしないと固定しているわけでもないことから、本稿では参考として紹介するに留める。
この「アイディア」の種類についてもいくつかの主張があり、例えば冲方は主題、世界、人物、物語、文体の5種であるとするし、榎本はキャラクター、世界設定、ストーリーの3種としている。分類それ自体が意味を持つものではないが、それぞれが独自の用語を用いて自説を主張している状態では整理のしようもないため、本稿では「主題」「世界」「登場人物」の3種に分けて整理する。
本稿では主題とテーマは同一の概念とみなすが、主題とは、そのラノベ創作において根幹となるアイディアのことである。冲方や大塚はこの主題を根として木構造状に各アイディアが繋がっていることを主張する。
主題を確定するタイミングについて冲方は真っ先に考えるとするし、大塚は作成した主人公像の要素を深化させそこから主題を抽出するとしている。榎本はプロット作成の段階で必須としていることからそれ以前に考えておかねばならない。西谷は執筆段階で突如として「物語の核」を意識する、と述べるが、この「物語の核」が主題とみなせるのであれば、プロット後に主題を決めてもいいということになるだろう。
このように主題をいつ考えるかは説によって大きな差があるが、結果としてラノベ創作において「主題」が必要不可欠だと多くの作家が述べていることに変わりはない。
繰り返しになるが、全てのアイディアの共通の祖先として「主題」は位置付けられる。従って本稿の分類で言うならば「世界」や「登場人物」は必ずこの主題と関係する要素を持たねばならない。言い方を変えれば、「主題」はアイディアとアイディアの共通要素として機能するため、ワナビ本人は主題として位置づけたが、それが「世界」や「登場人物」に関係していないのであればそれは「主題」ではない。
この「主題」があることの意義について、「読者は「設定資料集」を読みたいのではなく、「物語」を求めている」という榎本の指摘、また「「細部」には主題が宿る「細部」とそうでない「細部」があります。そしてあなた方の小説がしばしば欠いているのは「主題の宿る細部」なのです」という大塚の指摘を踏まえるなら、読者が「物語」と捉えるか「設定資料集」と捉えるかは「主題」の有無次第だ、ということになるだろう。
設定資料集が好きな人が存在することは事実であるが、彼らは設定資料集ならなんでも好きなわけではなく、特定の物語を好んだことで、その物語のより詳細な背景情報を知ることを好んでいるに過ぎない。興味のない物語の設定資料集など誰も目を通してくれはしない。
このように「主題」は重要な要素であると考えるが、その表現方法に関して榎本は主題を台詞や地の文で語ると胡散臭く、説得力が無くなるとしているし、クーンツは主題で読者を説教してはならないと注意を促している。台詞や地の文での表現を避けるとなれば、多くの場合登場人物の行動、またそれによって引き起こされた出来事によって表現されることになると考えられる。
本稿では会話文の主体になりうるものを形作る上で用いられる情報(名前、性格や容姿、口調など)の総体を「登場人物」と定義する。「キャラ」「キャラクター」とこれを区別するものもあるが、特筆の無い限り本稿ではまとめて「登場人物」とみなす。
一方で、登場人物以外の全ての設定を本稿では「世界」と定義する。具体的には魔法の有無などの自然法則、身分制のような社会構造、もしくは携帯電話の無い世界といった現代社会との差分もまた「世界」である。
いずれを先に考えるかについては諸説ある。例えば冲方や水島は世界が先だとするし、大塚や西谷は登場人物からだとする。榎本のように特に順序には言及しないものもある。
しかしながら冲方と大塚の「世界」と「登場人物」が揃った状態についての言及は非常に似通っている。
冲方は「人物たちの性格や言動や行動の全般は、結局のところ、大半が、世界と時代に左右されたもの」と言い、このような世界だからこそ、そこに登場するこの人物はこのような設定になるのだ、という必然性を要求する。
大塚もまた登場人物の個性については「キャラクターが所属する「世界」の物の見方の価値観に由来するもの」があるとしており、その人物の設定は彼の存在する世界の設定から必然的に生じたこのような価値観に由来するのだ、という必然性を要求する。どちらの側から見るかの違いだけで、冲方も大塚も目指している状態は同じだと言っていいだろう。
ワナビの「世界」について「リアリティが自分の身の回り3mくらいしかない」「おまえの世界には学校とコンビニと自宅しか存在していないのか」と五代/榊は批判し、リアリティには細部の設定が必要不可欠だ、という立場をとっている。一方で「登場人物」の細部情報への批判としては「異能力の内容だけやたら細かい」にもかかわらず「話に全然関係ない」としており、両者をまとめると「主題」の宿る細部こそが必要不可欠であり、それ以外の細部の設定は不要だとする大塚説とほぼ同一と言っていいだろう。
冲方は「そのテーマが内在する世界を、しっかり構築することができるようにならなきゃ話にならない」と世界における主題を重く位置づけた上で「実際にその世界について書かなくても、少なくとも自分は知っていたいし知らないと駄目」と細部の設定の充実に言及する。
その一方で登場人物については、冲方はそれが主題に関係しないのであれば「性別や年齢をあとから決める」とする。水島も登場人物はプロット上の必要性が出てから作れと述べ、最初に長大なキャラ表を作るというワナビにありがちな行為を繰り返し否定する。ヒックスは事前定義表に基づいて穴埋めで作られた登場人物を「組み立てられた登場人物」と表し、そして「最良の脚本には、組み立てられた登場人物は存在していない」と断じる。
だがこれらは登場人物に細部の設定が必要ない、という意味にはなりえない。例えばクーンツはプロットをまず作ることを前提とした上で、リアリティを持った人物描写のためには、登場人物に関しても細部設定が必要だとして、身長、体重、体型、年齢といった肉体的特徴、声や話し方、動作や仕草など多岐に渡る項目の設定を列挙している。
「登場人物」であれ「世界」であれ、リアリティは細かな設定によって得られるものだ、という点はいずれの主張とも矛盾しない。その細部の設定が「主題」と関係する場合は最初に考えるべきとする見解はあるが、関係しない場合、それがとりわけ「登場人物」の細部設定の場合、これを最初に考えることは多くの見解で明示的に否定されている、ということになる。
これとは相反する主張として、西谷はまず人物設定から始めるべきだとする。「積極性」「肉体的な強さ(美しさ)」「いざというときのリーダーシップ」「やさしさ」「辛抱強さ」「頭の良さ」で点数をつけてチャートを作成するのが良いとして、さらには性格、趣味、髪の色からメイクの仕方、ブラジャーの形状までを設定例として挙げており、そこには「主題」との関係性への言及はない。
ところが西谷は実際の作例において仮置きの主人公を用意するに留めており、チャートについては一切触れず、細かな設定も一切用意しない。まず最初に「世界」と「主題」に取り掛かり、「企画を練り上げる段階で、主人公を変えてしまう」「主人公を引き立てる脇役は、書いている途中で思いつく」とすら述べる。
最終的なこの作例が実際の西谷の手順なのだとすればその手法はむしろ冲方寄りである。 Permalink | 記事への反応(5) | 20:41
いやいや、XP以前の木構造のほうが圧倒的に見づらい&操作しづらいだろ…
UI変更は単なる見た目の変化だけなら問題はないんだが、アーキテクチャ自体が改悪されている場合もある。
例えばWindowsのスタートメニュー周りのUIなら、かつては用途によって分類された木構造を辿るだけのシンプルなものだった。
これがWindows7あたりから履歴に基づく表示になって、毎回見る度に位置が変わるようになった。「すべてのプログラム」を表示させてもずらずらプログラムの名前が出るだけで、インストールしているプログラムが増えてくると目当てのものを探すのに時間がかかる。それでもまだフォルダを展開するという形で木構造を表すことはできた。
Windows8になってくるとメニューを見せずにタイル状のランチャになった。これは見栄えはするだろうがフラットな構造しかないのでプログラムが増えてくると探すのが大変になる。
ファイルシステムのディレクトリのような木構造にデータを格納するのは、RDBに比べたらデータ構造が人間には超分かりやすいし、検索にかかる時間も簡単に見積もれるし、そもそも高速で動くし、CPUもメモリも少なく済む。
確かにRDBのWHERE句に相当する部分はいちいちプログラムで実装しないといけないけど、必要な処理はどれもこれも定型的で、一度覚えてしまえば非常に楽できそう(テンプレのコード用意しといて、システムに応じて微修正してコピペすればいい)。
即ち、誰でも素人からプロになれるというか、プロになるまでのコストが低いので、人材育成の面でも有利。
と、これほどまでに良いことづくめなのに、なんで廃れたのか意味が分からない。
逆にRDBはデータ構造は合理的なんだろうけど、人間にはとても分かりにくいし、パフォーマンスも加味した適切なテーブル設計が出来て効率いいSQLを組めるレベルの人となると、もはや適性の問題になってくる。
要するに向いてない奴にはいくら教育しても全く身につかない。一人前になれる人間が限られると言い換えてもいい。なかなかデキる人が出てこない。