This is my first foray into Node but I wanted to do some groundwork before building some more complex packages.
One of the biggest problems with Javascript is the lack of visibility. This is particularly problematic now we have easily accessible and usable libraries and packages. The problem is that it’s impossible for package authors to prevent backwards compatibility breaks when refactoring.
For example let’s say I have a class:
class MyClass {
calculateTax(value) {
return value * this.rate;
}
getTotal() {
return this.total + this.getTax(this.total);
}
}
If I refactor this into:
class MyClass {
constructor(taxCalculator) {
this.taxCalculator = taxCalculator;
}
getTotal() {
return this.total + this.taxCalculator.calculateTax(this.total);
}
}
I cannot publish the package in the knowledge that it won’t break someone else’s code. They may have been using the MyClass.calculateTax
function somewhere in their project. My refactor will now break their code when they update my package. Probably not what I intended! By following OOP standards and making properties/methods private when you don’t want third parties to call them you can can prevent this problem: Private methods can be removed, have their arguments changed or be renamed safe in the knowledge that the only place it’s called from is the same class. If a method cannot be called externally there’s no way to break someone else’s code when refactoring as long as the public methods have the same API.
To solve this I’ve implemented private properties and strict typing in Javascript:
It can be used like this:
var StrictOOP = require('strict-oop');
//Firstly declare the class as normal
class Car {
constructor() {
this.speed = 0;
}
accellerate() {
this.speed += 5;
}
}
var car = new Car();
//Add strict OOP rules to the `car` object
var oop = new StrictOOP(car);
//set the speed property to private
oop.property('speed').is('private');
//Now, trying to set it will cause an error to be thrown
car.speed = 100;
//This will update the speed as expected because the accellerate method is inside the class
car.accellerate();
The example above can also be expressed as:
var StrictOOP = require('strict-oop');
//Firstly declare the class as normal
class Car {
constructor() {
//Add strict OOP rules to this instance
var oop = new StrictOOP(this);
oop.property('speed').is('private');
this.speed = 0;
}
accellerate() {
this.speed += 5;
}
}
//Create an instance of `Car` as normal:
var car = new Car();
//But trying to set it will cause an error to be thrown
car.speed = 100;
//This will update the speed as expected because the accellerate method is inside the class
car.accellerate();
This approach gives class authors the ability to define whether they want to enforce strict OOP in their classes.
oop.property(name)
can be used to select a property on any object (including this
and set its visibility using oop.property(name).is('private')
or force it to only allow certain types using oop.property(name).type('someType')
The package is lightweight (~100 lines) and unit tests are provided
Comments/suggestions are welcome, the next release will also have argument type checking using oop.method(methodName).arguments(['string', ' number, 'MyClass', 'any']);