I've been writing test (in JavaScript) for the last two months. And, I have the habit of checking if module has some properties.
For example:
// test/foo.js
const Foo = require('../lib/foo');
const Expect = require('chai').expect;
describe('Foo API', () => {
it('should have #do and #dont properties', () => {
Expect(foo).to.have.property('do')
.and.to.be.a('function');
Expect(foo).to.have.property('dont')
.and.to.be.a('function');
});
});
});
And, I've been wondering if I am doing the right things. Just wanna know a few things:
Is this pattern "right"?
Is it widely used?
Are there other ways to do it?
If its not "right"?
Why?
Does it even makes sense?
I mean, it is unnecesary or redundant?
Don't test for types. Do test that specific property values conform to expected values.
So instead of "is foo a function", write a test that calls foo and expects a specific result.
If foo is not a function, you'll generate an error and the test will fail (which is good). If foo is a function, you'll have a proper test of that function's behavior.
There's a paradigm called duck typing that says (from Wikipedia):
In duck typing, a programmer is only concerned with ensuring that
objects behave as demanded of them in a given context, rather than
ensuring that they are of a specific class. For example, in a
non-duck-typed language, one would create a function that requires
that the object passed into it be of type Duck, or descended from type
Duck, in order to ensure that that function can then use the object's
walk and quack methods. In a duck-typed language, the function would
take an object of any type and simply call its walk and quack methods,
producing a run-time error if they are not defined. Instead of
specifying types formally, duck typing practices rely on
documentation, clear code, and testing to ensure correct use.
I would focus on the following part of above text:
In a duck-typed language, the function would take an object of any
type and simply call its walk and quack methods, producing a run-time
error if they are not defined
And...
[...] duck typing practices rely on documentation, clear code, and testing
to ensure correct use.
That is, since JavaScript is a dynamically-typed language fits very well with duck typing.
In other words, you should avoid these tests. If a module has a missing property or it exists with an undesired type, you'll get a runtime error, which is enough to note that the caller doesn't fulfills the implicit contract to work fine with a given module.
The whole contract defined by the behavior of your code during run-time can be enforced by good documentation pages.
If you write a test it is because you want to be sure that further changes of the code will not change the behavior that you're testing.
So it is useful if your module expose those property as an interface and other code on your app or other apps depends on it.
But if the property, is just something "internals", I mean it is just dependent on the module implementation, than it is dangerous and a waste of time, as you should always be able to change implementation.
That's not true for interfaces.
On your tests, instead to test if a property is a function, you should test if the function do what should do when is called.
If there is a documentation that this function is an interface of the module.
Related
I am having trouble using TypeScript's type system to model a generic interface to call from Lua into TypeScript. For this to work, the developer must define a TypeScript interface defining the TypeScript methods that Lua can call into. The details don't matter much here, as the simple example below illustrates my confusion.
As you can see from the code above, I have "ApiInterface", which defines arbitrary methods that a developer may want to invoke from Lua. All such methods take a first argument that is an object (akin to 'this'), and the remaining arguments can be whatever the developer needs to pass from Lua into the TypeScript method. In practice, the only types supported for these remaining arguments are primitives like number, string, boolean, null. In the example code above, I defined 3 such API methods, but the developer may define whatever methods they want. The whole point of this Lua-to-TypeScript module is to be generic, and not be tied to any particular definition of "ApiInterface".
The runtime eventually packages up the Lua-to-TypeScript method call into an object of type ApiCall, which you can see is defined with fields for the method name, the JavaScript object to use for "this", and the remaining arbitrary arguments.
To illustrate my confusion, I have shown a KeyofDemo to illustrate the TypeScript error I am getting. There is a "run" method in the KeyofDemo class that wants to take the ApiCall object and invoke the corresponding TypeScript/JavaScript function.
You can see the red-squiggly under the actual invocation of the method in the two cases. One case is where there are no additional arguments (beyond the required "this" argument), and the other case for when ApiCall.args is actually populated with an array of arguments to pass from Lua to TypeScript.
The error message from the first red-squiggly case is: A spread argument must either have a tuple type or be passed to a rest parameter.
The error message from the second red-squiggly case is: Expected 3 arguments but got 1.
Neither of these error messages makes any sense to me. If I try to compile the above TypeScript code, the compiler reports similar errors.
How can I get TypeScript's type system to best model the behavior I have described? For now, I have worked around the problem by changing lines 23 and 25 to case "this.api" to "any", and this shuts up the TypeScript compiler. But I would like to know how to properly model this problem.
The first error is because Javascript/Typescript does not support using spread operators in parameters, unless your function is configured to do so.
You have to configure the function to accept variadic parameters.
interface ApiInterface {
apiMethod0(thisObj: Object, ...args: any[]): void
apiMethod1(thisObj: Object, ...args: [string]): void
apiMethod2(thisObj: Object, ...args: [number, boolean]): void
}
See this code in playground
The second error is because the methods need to be all of the same "shape", or have the same # of parameters. In this case we kill both birds with the same stone.
Consider a hypothetical function called isEcmaGlobal that returns true for string names of ECMA-262 globals.
$ node
> isEcmaGlobal('Array')
true
> isEcmaGlobal('process')
false
How would one design this function?
Lets be careful here. We need to ask another question before this answer will make sense: Are we categorizing globals by what ECMA-262 ("the standard") says now, or by the standard governing our program's runtime?
Put another way: Should multiple machines see the same answers?
Going by the Current Standard
Let's say we want isEcmaGlobal to return true in terms of what the standard says right now. I won't show any code here because if you care about this kind of problem, then you probably already thought to download or scrape standard global names.
Going by the Current Runtime
Now let's assume we want isEcmaGlobal to return true in terms of offline information available in the current runtime. It's not as easy as iterating over the "own" property names of the global object and checking them against a hard-coded array like ['Array', 'Object', ...]. If we did that, then we'd have to verify our array is correct. We can't verify hard-coded data because it assumes isEcmaGlobal is already written for that exact runtime! We cannot paste in global names from ECMA-262, because we don't know if the version of that document is in parity with the runtime. We also can't check the Internet because we assumed an offline solution.
So we can't hard code, but we can try something else. I'll use Node.js v14.16.0 and its built-in vm module. This program exploits vm's need to provide standard globals in a new evaluator. We tell vm to evaluate code using an empty global object, but that global object simply won't be empty.
const vm = require('vm');
function isEcmaGlobal(identifier) {
try {
// Lol, what security?
vm.runInContext(identifier, vm.createContext({}))
return true;
} catch (e) {
return false;
}
}
Couple of things here.
First, a warning: This example uses unsanitized code execution for illustration and brevity. Do not put it on your clipboard with intent to take a shortcut.
Second, you can see our goal is to create a fresh evaluator with only standard globals defined, and no visibility into what's going on outside of the evaluator (eval does not do either of these things). If we get that evaluator, then you can just toss Object.getOwnPropertyNames(new Function('return this')()) into it and we all go home.
But we're making a predicate, so assuming the "lean" global object is correct, evaluation will throw a ReferenceError for non-standard identifiers.
Unfortunately, somehting isn't right.
> isEcmaGlobal('Array')
true
> isEcmaGlobal('process')
false // yes!
> isEcmaGlobal('global')
false // yes!!
> isEcmaGlobal('console')
true // no!!!
Darn, we still have a Node global for some reason. So at this point you could say I'm making this all too complicated because Node.js doesn't add that many globals, or that I missed a configuration option or existing predicate. You'd be right on all counts, but that's missing the point of the question. The question started with "Can a JavaScript program know...?", and my use of Node is meant to illustrate a way to approach the problem without hard-coding standard global names and creating a contradiction. Even if Node.js added only one non-standard global, the problem remains if we can't get a clean evaluator.
Recap
To implement isEcmaGlobal in some JavaScript runtime, that runtime needs to give you a way to run a bare-bones JS evaluator, free of all host-specific extensions. eval doesn't count. Make it such that that you only accept identifiers, and then evaluate those identifiers. Interpret an exception as reason to return false.
Note: I now believe this question was based on assumptions about the javascript specification which are actually implementation specific.
I am attempting to build a runtime debugging hook system for a complex dynamic javascript application. A series of choices have let me to choose to use javascript Proxy and Reflect metaprogramming constructs to interpose function calls in the application I am debugging, wrapping all incoming functions arguments in Proxy/Reflect constructs.
The approach involves replacing high level application functions with Proxies and using traps and handlers to provide debugging functionality, ultimately passing arguments through to the application in a transparent way. All property get/set and function executions act as normal. However, by wrapping all objects and functions in Proxies allows tracing of the runtime.
I am installing this hook system into Chrome.
(Note: Please do NOT provide an answer suggesting a different methodology for debugging hooks - options have been evaluated extensively.)
The issue is that some javascript methods in the application invoke closures and pass "this" parameters. When "this" parameters are wrapped in a Proxy, the runtime fails to execute a closure, instead throwing an "Illegal Invocation" Exception.
I have tried reengineering the debugging hook system to not wrap arguments for some methods, or selectively wrap arguments. I have not been able to find a way to tell if an argument is intended to be used as a context, making code that tries this approach hardcoded to many possible methods and calling conventions. Ultimately this is too fragile to calling convention edge cases and requires too many case statements.
I have also removed the logic for wrapping arguments before passing them through. This removes the benefit from the debug hooking system, and so I have always reverted the logic to wrap all incoming arguments.
alert.apply(this, [1]);
p = new Proxy(this, {});
try {
alert.apply(p, [1]);
} catch (e) {
console.log(e);
}
This throws an "Illegal Invocation" Exception.
typeof this === 'object'
true
But it seems that contexts are objects just like everything else.
I expect that passing a Proxy() through to context should succeed in an invocation. Barring this, I would expect the type of a context to be specific enough to determine whether it should be wrapped in a Proxy() or not.
I have two questions.
(1) What are the semantics of context binding closures in javascript that would cause binding to a Proxy(context) to fail with an illegal invocation?
(2) What type of object are contexts, and how can a javascript method tell one apart from other javascript objects by inspecting its properties at runtime?
What type of object are contexts, and how can a javascript method tell one apart from other javascript objects by inspecting its properties at runtime?
There is no special type. Every object can become a context by calling a method upon it. Most objects that will become a context of a method call do have that very method as an (inherited) property, but there's no guarantee.
You cannot tell them apart.
What are the semantics of context binding in javascript that would cause binding to a Proxy(context) to fail with an illegal invocation?
When the method is a native one. In user code functions, the this context being a proxy doesn't make a difference, when you access it then it will just behave as a proxy.
The problem is native methods that expect their this argument to be a native object of the respective type. Sure, those objects are still javascript objects, but they may contain private data on internal properties as well. A proxy's target and handler references are implemented through such internal properties as well, for example - you can sometimes inspect them in the debugger. The native methods don't know to unwrap a proxy and use its target instead, they just look at the object and notice that it doesn't have the required internal properties for the method to do its job. You could've passed a plain {} as well.
Examples for such methods can be found as builtins of the ECMAScript runtime:
Map.prototype.has/get/set/…
Set.prototype.has/get/set/…
TypeArrayPrototype.slice/copyWithin/map/forEach/…
Number/String/Boolean prototype methods
But also (and even more of them) as host objects supplied by the environment:
window.alert/prompt
EventTarget.prototype.addEventListener/removeEventListener
document.createElement
Element.prototype.appendChild/remove/…
really just anything that's browser-specific
but also in other environments, like the nodejs os module
I have tried unwrapping Proxies in the right places by coding in edge cases and by blanket/heuristic policies.
I think the only reasonable approach would be to check whether the called function is a native one, and unwrap all arguments (including the this argument) for them.
Only a few native functions could be whitelisted, such as most of those on the Array.prototype which are explicitly specified in the language standard to work on arbitrary objects.
With TypeScript or Facebook's Flow(type) I can statically type variables like
function add (x: integer, y: integer) { ... }
Both TypeScript and Flow catch any illegal invocation such as add('1',0) at compile time.
However, when the library is compiled and exported, the types are gone. That means, the library consumer using that function gets no errors, that may potentially lead to hard-to-debug problems.
Is there any way to auto-generate additional code that would throw exactly the same errors at run time?
I can surely manually place guards every time a typecheck is expected but that feels boring and repetitive.
https://github.com/codemix/babel-plugin-typecheck does what you want.
There is also https://gcanti.github.io/flowcheck/ but it looks a bit abandoned.
I haven't personally used any of those libraries. It seems that they might cover less than 100% of Flow syntax.
You won't get that from javascript alone regardless of which you choose as javascript doesn't have the notion of types in this sense.
I've never worked with fb flow so I can't reply on that, but typescript-wise here are the options I think you have: (in order of complexity and how much it doesn't make sense)
Modify the typescript compiler to automatically add runtime parameters validation
You can use the compiler API and inject a piece of code that validate the params for the functions. The compiler will tell you what the param names and types are, if they are optional and so on.
I'm just including this as an option but it's a pretty messed up solution in my opinion.
Start every function with validation
Pretty much like the previous one, just that you'll include the code yourself in each function instead of modifying the compiler to do so.
You can have a global function that take as arguments the meta data of the declared params and the actual arguments that are passed.
This will make things pretty ugly code-wise, and won't be fun to maintain.
In case of classes you can use decorators
The decorators feature is pretty new, but typescript lets you use it, and if you want to do this validation thing on classes then this is the best solution for your problem so far.
Generate a definition file for you library
This is the best of options if you ask me.
You don't need to contaminate your code with checks in each function. More than that, you can never control who's using your lib or how they use it so it's lost cause to even try.
For this your lib consumers will need to write in typescript themselves.
You can also try babel-plugin-runtyper that performs type checking in runtime and does not require manual annotations.
For your example, if function looks like:
function add(x, y) {
return x + y;
}
And you call it as
add('1', 0);
you will get warning in console:
Plus operation with different types: "1" (string) + 0 (number)
We have been debating how best to handle objects in our JS app, studying Stoyan Stefanov's book, reading endless SO posts on 'new', 'this', 'prototype', closures etc. (The fact that there are so many, and they have so many competing theories, suggests there is no completely obvious answer).
So let's assume the we don't care about private data. We are content to trust users and developers not to mess around in objects outside the ways we define.
Given this, what (other than it seeming to defy decades of OO style and history) would be wrong with this technique?
// namespace to isolate all PERSON's logic
var PERSON = {};
// return an object which should only ever contain data.
// The Catch: it's 100% public
PERSON.constructor = function (name) {
return {
name: name
}
}
// methods that operate on a Person
// the thing we're operating on gets passed in
PERSON.sayHello = function (person) {
alert (person.name);
}
var p = PERSON.constructor ("Fred");
var q = PERSON.constructor ("Me");
// normally this coded like 'p.sayHello()'
PERSON.sayHello(p);
PERSON.sayHello(q);
Obviously:
There would be nothing to stop someone from mutating 'p' in unholy
ways, or simply the logic of PERSON ending up spread all over the place. (That is true with the canonical 'new' technique as well).
It would be a minor hassle to pass 'p' in to every function that you
wanted to use it.
This is a weird approach.
But are those good enough reasons to dismiss it? On the positive side:
It is efficient, as (arguably) opposed to closures with repetitive function declaration.
It seems very simple and understandable, as opposed to fiddling with
'this' everywhere.
The key point is the foregoing of privacy. I know I will get slammed for this, but, looking for any feedback. Cheers.
There's nothing inherently wrong with it. But it does forgo many advantages inherent in using Javascript's prototype system.
Your object does not know anything about itself other than that it is an object literal. So instanceof will not help you to identify its origin. You'll be stuck using only duck typing.
Your methods are essentially namespaced static functions, where you have to repeat yourself by passing in the object as the first argument. By having a prototyped object, you can take advantage of dynamic dispatch, so that p.sayHello() can do different things for PERSON or ANIMAL depending on the type Javascript knows about. This is a form of polymorphism. Your approach requires you to name (and possibly make a mistake about) the type each time you call a method.
You don't actually need a constructor function, since functions are already objects. Your PERSON variable may as well be the constructor function.
What you've done here is create a module pattern (like a namespace).
Here is another pattern that keeps what you have but supplies the above advantages:
function Person(name)
{
var p = Object.create(Person.prototype);
p.name = name; // or other means of initialization, use of overloaded arguments, etc.
return p;
}
Person.prototype.sayHello = function () { alert (this.name); }
var p = Person("Fred"); // you can omit "new"
var q = Person("Me");
p.sayHello();
q.sayHello();
console.log(p instanceof Person); // true
var people = ["Bob", "Will", "Mary", "Alandra"].map(Person);
// people contains array of Person objects
Yeah, I'm not really understanding why you're trying to dodge the constructor approach or why they even felt a need to layer syntactical sugar over function constructors (Object.create and soon classes) when constructors by themselves are an elegant, flexible, and perfectly reasonable approach to OOP no matter how many lame reasons are given by people like Crockford for not liking them (because people forget to use the new keyword - seriously?). JS is heavily function-driven and its OOP mechanics are no different. It's better to embrace this than hide from it, IMO.
First of all, your points listed under "Obviously"
Hardly even worth mentioning in JavaScript. High degrees of mutability is by-design. We're not afraid of ourselves or other developers in JavaScript. The private vs. public paradigm isn't useful because it protects us from stupidity but rather because it makes it easier to understand the intention behind the other dev's code.
The effort in invoking isn't the problem. The hassle comes later when it's unclear why you've done what you've done there. I don't really see what you're trying to achieve that the core language approaches don't do better for you.
This is JavaScript. It's been weird to all but JS devs for years now. Don't sweat that if you find a better way to do something that works better at solving a problem in a given domain than a more typical solution might. Just make sure you understand the point of the more typical approach before trying to replace it as so many have when coming to JS from other language paradigms. It's easy to do trivial stuff with JS but once you're at the point where you want to get more OOP-driven learn everything you can about how the core language stuff works so you can apply a bit more skepticism to popular opinions out there spread by people who make a side-living making JavaScript out to be scarier and more riddled with deadly booby traps than it really is.
Now your points under "positive side,"
First of all, repetitive function definition was really only something to worry about in heavy looping scenario. If you were regularly producing objects in large enough quantity fast enough for the non-prototyped public method definitions to be a perf problem, you'd probably be running into memory usage issues with non-trivial objects in short order regardless. I speak in the past tense, however, because it's no longer really a relevant issue either way. In modern browsers, functions defined inside other functions are actually typically performance enhancing due to the way modern JIT compilers work. Regardless of what browsers you support, a few funcs defined per object is a non-issue unless you're expecting tens of thousands of objects.
On the question of simple and understandable, it's not to me because I don't see what win you've garnered here. Now instead of having one object to use, I have to use both the object and it's pseudo-constructor together which if I weren't looking at the definition would imply to me the function that you use with a 'new' keyword to build objects. If I were new to your codebase I'd be wasting a lot of time trying to figure out why you did it this way to avoid breaking some other concern I didn't understand.
My questions would be:
Why not just add all the methods in the object literal in the constructor in the first place? There's no performance issue there and there never really has been so the only other possible win is that you want to be able to add new methods to person after you've created new objects with it, but that's what we use prototype for on proper constructors (prototype methods btw are great for memory in older browsers because they are only defined once).
And if you have to keep passing the object in for the methods to know what the properties are, why do you even want objects? Why not just functions that expect simple data structure-type objects with certain properties? It's not really OOP anymore.
But my main point of criticism
You're missing the main point of OOP which is something JavaScript does a better job of not hiding from people than most languages. Consider the following:
function Person(name){
//var name = name; //<--this might be more clear but it would be redundant
this.identifySelf = function(){ alert(name); }
}
var bob = new Person();
bob.identifySelf();
Now, change the name bob identifies with, without overwriting the object or the method, which are both things you'd only do if it were clear you didn't want to work with the object as originally designed and constructed. You of course can't. That makes it crystal clear to anybody who sees this definition that the name is effectively a constant in this case. In a more complex constructor it would establish that the only thing allowed to alter or modify name is the instance itself unless the user added a non-validating setter method which would be silly because that would basically (looking at you Java Enterprise Beans) MURDER THE CENTRAL PURPOSE OF OOP.
Clear Division of Responsibility is the Key
Forget the key words they put in every book for a second and think about what the whole point is. Before OOP, everything was just a pile of functions and data structures all those functions acted on. With OOP you mostly have a set of methods bundled with a set of data that only the object itself actually ever changes.
So let's say something's gone wrong with output:
In our strictly procedural pile of functions there's no real limit to the number of hands that could have messed up that data. We might have good error-handling but one function could branch in such a way that the original culprit is hard to track down.
In a proper OOP design where data is typically behind an object gatekeeper I know that only one object can actually make the changes responsible.
Objects exposing all of their data most of the time is really only marginally better than the old procedural approach. All that really does is give you a name to categorize loosely related methods with.
Much Ado About 'this'
I've never understood the undue attention assigned to the 'this' keyword being messy and confusing. It's really not that big of a deal. 'this' identifies the instance you're working with. That's it. If the method isn't called as a property it's not going to know what instance to look for so it defaults to the global object. That was dumb (undefined would have been better), but it not working properly in that scenario should be expected in a language where functions are also portable like data and can be attached to other objects very easily. Use 'this' in a function when:
It's defined and called as a property of an instance.
It's passed as an event handler (which will call it as a member of the thing being listened to).
You're using call or apply methods to call it as a property of some other object temporarily without assigning it as such.
But remember, it's the calling that really matters. Assigning a public method to some var and calling from that var will do the global thing or throw an error in strict mode. Without being referenced as object properties, functions only really care about the scope they were defined in (their closures) and what args you pass them.