Some quick guidelines that summarize the current UMG design philosophy.
NOTE: all of this is subject to nuance!
If you disagree with something, or have a counterexample, let me know. I would love to discuss it.
This file basically seeks to clarify UMG's current ideology.
UMG High-Level Philosophy:
Follow the 80/20 rule
Less code > more code
Readibility and Elegance > efficiency (Unless it's really bad)
Simple and assumptionless > Complex and flexible
Bloat is the greatest evil
State is an evil neccessity:
- Try to keep the program state inside of components.
- If that's not possible, immutable and short-lived state is 2nd-best.
- State should ideally have a SSOT
Regular data and functions > Objects and classes
Systems and Emergence:
DO embrace chaotic, interacting systems
DONT fight existing systems to achieve something. Instead:
- Find another way to achieve a similar result
- ALTERNATIVELY; go back, and ask what the user is gaining from this feature
If something is unnatural to implement, try avoid implementing it
Mod Cohesion:
The purpose of base-mods is to provide cohesion/connections within the ecosystem;
- NOT to reuse code!
If mod-A and mod-B know nothing about each another, they should be able to exist cohesively;
- (UNLESS they are both playable-mods.)
Hackiness:
Its OK for playable/addon mods to be hacky/poorly designed.
But its NOT OKAY for base mods to be hacky/poorly designed.
Component design:
Unifying components:
Components should never have co-dependencies.
Example:
ent.uiElement = Element()
ent.uiRegion = {x,y,w,h}
--[[
When an entity has these two components,
they are rendered as a UI element on screen.
]]
But... this is dumb.
Why not just have a singular component?
ent.ui = {
element = Element(),
region = {x,y,w,h}
}
This is so much better, because:
- It tells the modder that they need BOTH
region
andelement
- It is less bloated
Splitting up components:
Ideally, components should have ONE well-defined purpose.
If we think a component is doing too much, we might want to decouple/split it up.
For example:
ent.playerControl = {
clientId = "30943434343043",
type =
}