POPO = plain old PHP object / POJO = plain old Java(script) object

If you're lucky, you may work on a team that actually keeps domain model constraints close to the model, instead of using an anemic data model that just contains slots (member variables, properties, call it what you like) - essentially reimplementing your language's built-in map type in a thin object wrapper.

Look around at some "OOP" codebases for a bit, and it won't be long until you see something such as this (sample in PHP, but it could be in Java or Typescript or any other language attempting to be java-like):

class UserModel { /** @var string The name of the user. */ private $ name ; /** @var int The age of the user. */ private $ age ; /** @var int The id of the user. */ private $ id ; /** @var string The language of the user. */ private $ language ; /** * Create a the user * * @return UserModel */ public function __construct () { // What are constructors for again? // Omitting getter/setter docblocks, but you'll see them too. } public function setName ( string $ name ) { $ this -> name = $ name ; } public function getName () : string { return $ this -> name ; } public function setAge ( int $ age ) { $ this -> age = $ age ; } public function getAge () : int { return $ this -> age ; } public function setId ( int $ id ) { $ this -> id = $ id ; } public function getId () { return $ this -> id ; } public function setLanguage ( string $ language ) { $ this -> language = $ language ; } public function getLanguage () { return $ this -> language ; } }

So, what's the big deal? (you may ask).

Well, first off, by not actually constructing the object all at once (immutability) at any given point in code execution, your model could be in an "invalid" or incomplete state.

What if a new property is added down the road? Very few IDEs will be able to inform you that you failed to call some later-date added setter in code portions that consume this code.

Secondly, comments (and mandatory docblocks) should always explain the "why", not the "what". Very rarely do these types of comments offer any value whatsoever.

Lastly, the getter/setter fluff offers no value, it's just wasted screen real estate.

Let's clean up the Model a bit:

class UserModel { private $ name ; private $ age ; private $ id ; private $ language ; public function __construct ( string $ name , int $ age , int $ id , string $ language ) { $ this -> name = $ name ; $ this -> age = $ age ; $ this -> id = $ id ; $ this -> language = $ language ; // Favorite prog language. } }

Ok, that's a bit better - it's still a little wordy, but if PHP was your language of choice, that's just a bed you'll have to sleep in at this point. Had it been Kotlin you could use a Data class, or in Typescript you could leverage some nice constructor bonuses:

class UserModel { constructor ( private name: string , private age: number , private id: number , private language: string ) {} }

Or, you know, had you chosen Clojure, you could just use a record to the same effect (check out clojure.spec if you are worried about types):

( defrecord UserModel [ name age id language ] )

which is effectively just the simpler to use 'map' type: