I was coding the other day and stumbled upon something atrocious.
Do you see it?
Let’s zoom in a bit more:
This line:
Please don’t do this in any language.
Don’t await
properties.
You’re destroying your code readability and ruining the whole concept of OOP.
Properties are features not actions.
They don’t do like methods. They are.
They are data holders representing states of an object.
Simple states:
class Person {
firstName = 'Tari';
lastName = 'Ibaba';
site = 'codingbeautydev.com';
}
Derived states — what getters are meant for:
class Person {
firstName = 'Tari';
lastName = 'Ibaba';
site = 'codingbeautydev.com';
get fullName() {
return `${this.firstName} ${this.lastName}`;
}
}
const person = new Person();
console.log(person.fullName); // Tari Ibaba
But the status
property was returning a Dart Future
— JavaScript’s Promise
equivalent:
❌Before:
class Permission {
get status() {
return new Promise((resolve) => {
//
resolve();
});
}
}
const notifications = new Permission();
await notifications.status;
It would have been so much better to use a method:
✅ After:
class Permission {
getStatus() {
return new Promise((resolve) => {
//
resolve();
});
}
}
const notifications = new Permission();
await notifications.getStatus();
And now async/await
can make things even more intuitive:
class Permission {
async getStatus() {
//
}
}
const notifications = new Permission();
await notifications.getStatus();
But guess what happens when you try async/await
with properties?
Exactly. It’s a property.
This rule doesn’t just apply to async
tasks, it applies to any long-running action, synchronous or not:
❌ Before:
class ActionTimer {
constructor(action) {
this.action = action;
}
// ❌ Property
get time() {
const then = Date.now();
for (let i = 0; i < 1000000; i++) {
this.action();
}
const now = Date.now();
return now - then;
}
}
const splice = () => [...Array(100)].splice(0, 10);
const actionTimer = new ActionTimer(splice);
console.log(`[email protected]: ${actionTimer.time}`);
✅ After:
Let them know that the action is expensive enough to deserve caching or variable assignment:
class ActionTimer {
constructor(action) {
this.action = action;
}
// ✅ Get method
getTime() {
const then = Date.now();
for (let i = 0; i < 1000000; i++) {
this.action();
}
const now = Date.now();
return now - then;
}
}
const splice = () => [...Array(100)].splice(0, 10);
const actionTimer = new ActionTimer(splice);
const theTime = actionTimer.getTime();
console.log(`[email protected]: ${theTime}`);
But sometimes it still doesn’t deserve to be a property with this.
Check this out — do you see the issue with the level
setter property?
class Human {
site = 'codingbeautydev.com';
status = '';
_fullness = 0;
timesFull = 0;
set fullness(value) {
this._fullness = value;
if (this._fullness <= 4) {
this.status = 'hungry';
} else if (this._fullness <= 7) {
this.status = 'okay';
} else {
this.status = 'full';
timesFull++;
}
}
}
const human = new Human();
human.fullness = 5;
console.log(`I am ${human.status}`);
It doesn’t just modify the backing _fullness
field — it changes multiple other fields. This doesn’t make sense as a property, as data.
It’s affecting so much aside from itself.
It has side-effects.
Setting this property multiple times modifies the object differently each time.
const human = new Human();
human.fullness = 8;
console.log(human.timesFull); // 1
human.fullness = 9;
console.log(human.timesFull); // 2
console.log(`I am ${human.status}`);
So even though it doesn’t do much, it still needs to be a method.
class Human {
site = 'codingbeautydev.com';
status = '';
_fullness = 0;
setLevel(value) {
this._fullness = value;
if (this._fullness <= 3) {
this.status = 'hungry';
} else if (this._fullness <= 7) {
this.status = 'okay';
} else {
this.status = 'full';
}
}
}
const human = new Human();
human.setLevel(5);
console.log(`I am ${human.status}`);
Name them right
Natural code. Coding like natural language.
So always name the properties with nouns like we’ve been doing here.
class ActionTimer {
constructor(action) {
this.action = action;
}
// ✅ Noun for property
get time() {
// ...
}
}
But you see what we did when it was time to make it a property?
We made it a verb. Cause now it’s an action that does something.
class ActionTimer {
constructor(action) {
this.action = action;
}
// ✅ verb phrase for method
getTime() {
// ...
}
}
Nouns for entities: variables, properties, classes, objects, and more.
Not this
// ❌ do-examples.ts
// ❌ Cryptic
const f = 'Coding';
const l = 'Beauty';
// ❌ Verb
const makeFullName = `${f} ${l}`;
class Book {
// ❌ Adjectival phrase
createdAt: Date;
}
But this:
// ✅ examples.ts
// ✅ Readable
const firstName = 'Coding';
const lastName = 'Beauty';
// ✅ Noun
const fullName = `${firstName} ${lastName}`;
class Book {
// ✅ Noun phrase
dateCreated: Date;
}
Verbs for actions: functions and object methods.
Key points: when to use a method vs a property?
Use a property when:
- The action modifies or returns only the backing field.
- The action is simple and inexpensive.
Use a method when:
- The action modifies multiple fields.
- The action is async or expensive.
All for clean, readable, intuitive code.