DEV Community

Discussion on: Loosely coupled code: Babylon vs Three.js

 
neovance profile image
Devon Bagley

Scene is just the root of a traversable tree of child objects, and may or may not be renderable, but have the transform, position, rotation, etc context of it's parent. The renderer calls scene.traverse, and scene.traverseVisible respectively, with a callback function to build the render buffer each frame.

The problem with inheritance that you are supplying is flawed by design. Bird is a classification that is not based on purpose, or function to begin with. Bird is a classification of animal which share certain traits, but those traits aren't related to the ability to fly or swim. This particular problem can easily be solved using well known design patterns within which inheritance can play a role. Direct inheritance is not the only tool applied to all problems.

There is no instance check. Three.js merely looks for a truthy property on the object called isObject3D, and isScene, etc for each "type" and assumes that the object implements the interface, so it should be possible to use objects from other libraries using a simple adapter to implement the interface.

In any case, looking at the files being imported doesn't really tell you the whole story of what is tightly coupled or not. Babylon is typescript, and thus all of the types used must be imported for static analysis of the type hints.

Thread Thread
 
seanmay profile image
Sean May

A Scene also needs a "translateOnAxis" and a "setRotationFromQuaternion", et al, because it is an Object3D. It doesn't just possess the information, but rather also possesses all of the methods, because of inheritance.
It also has Observer / Pub-Sub features, because Scene is also an EventDispatcher, because Object3D is an EventDispatcher.

This isn't tightly-coupled to you? How is the cohesion of all of the features of Scene, for you? Does the abstract concept of a "scene", or a scene graph, or a render batch list, or whatever abstraction you're going to use, always come with event pub-sub, and its own built in quaternion methods?
I would say that is low cohesion. If you got a list of all properties and methods on Scene, or on the superclass of Scene or on the supersuperclass of Scene... I believe that they would not all make sense to be on one object, to solve one problem.

"it should be possible"... until somewhere down the stack, if it assumes that it has a Scene, that it can add an event listener, or fire an event on it... and yes, if I were to write a new Scene from scratch, then it needs to contain everything that a regular Scene would inherit down the line, if I expect it to conform.

"In any case, looking at the files being imported doesn't really tell you the whole story of what is tightly coupled or not."
It really does. In every case, if a JS file imports another JS file, then the importer is tightly coupled to the imported...
If A imports B, then A gives B the chance to run code and change global state, just by virtue of being called. That's tightly coupled. Moreover, assuming that you have C that you want to use instead of B... if A has imported B directly, then chances are that the methods of A are going to use B directly, rather than using the C you want it to use, because it has reference to B in its code...
That is prima facie tight-coupling with A having a hard dependency on B (such that C can't be used as substitute, without also rewriting A).

"Babylon is typescript, and thus all of the types used must be imported for static analysis of the type hints."
And? Types can live in their own .ts files, or be imported separately using the import type { } statement, or the new import { type X } expression. None of that involves importing any running code. Moreover, all TypeScript types are structural types, not nominal types. That means that any and all types/interfaces in TypeScript are happily polymorphic and swappable for any interface that matches. Thus, you don't even need the class or a base class for polymorphism in TS. You don't need classes to all declare that they implement an interface. They don't even need to be class instances at all.
Loose coupling would be if Scene wasn't an Object3D, didn't have a bunch of math methods, didn't have pub-sub... didn't load/initialize a bunch of math libs, et cetera, if you load the file directly (by having it load Object, and having that load the rest)...
...and rather, I could use my own implementation of objects or scenes, separate from the whole ThreeJS or Babylon framework that they're residing in.