3 ms·
Working with JavaScript has caused me to ask this question: "When should I create a Class, and when a Function?" This is not a trivial question because class-i
by galaxyLogic 3y ago
Working with JavaScript has caused me to ask this question: "When should I create a Class, and when a Function?"
This is not a trivial question because class-instances are basically collections of Functions, and Functions can return class-instances. So a trivial answer would be: "It does not matter, you can do everything with both or either one".
No, you shouldn't do everything with both, you should do some specific types of things with classes and other types of things with functions. But what?
I've come to this Rule-of-Thumb: Use classes only to represent and encapsulate data, use functions to process and transform class-instances.
In practice this means that in most cases classes should not have methods which take arguments. Exceptions: You can have setters. You can have a new() method which creates a new instance with data that differs from the data of the recipient. But it should be all about data-creation and extraction.
Classes are still truly useful over plain records, because a class abstracts over what data is stored, and what are the names by which it is accessed, and whether the methods return a stored field or a calculated one.
The idea that "Everything is an instance of a Class" as in Smalltalk is a bit flawed, or at least too trivial an advice. It is of course also true that (even in JavaScript) Functions are objects. And in Smalltalk you can use BlockClosures, which really are "functions".
This division of design makes it easier for me to think about the structure of the whole application. I no longer have classes for everything. Instead I have classes which represent and provide access to and creation of data, and a set of functions which do the processing of those class-instances.
Why is this good? Because classes are, and easily become complicated, since they can have many methods, they can have both static and instance-methods, and methods can be local or inherited and you can even use the 'super' to add to the confusion. So therefore if you can find a way to force your classes to be as simple as possible, do that. Don't make them do complicated things since they are complicated to start with.
Dividing the design into two parts, classes + functions, divides the complexity of the whole app into two parts, each of which contains about 1/2 of the complexity of the whole app. The complexity is now data-complexity PLUS function-complexity whereas with use-classes-for-everything the app-complexity would be more like data-complexity TIMES function complexity (I conjecture).
Keep data (= classes) and functions separate. Divide and conquer complexity.
- whstl 3y agoOh, yes. I totally agree with that philosophy. The part about classes only acting on themselves resonates heavily with me. To me it's the same with components in frontend apps: the more independent they are, the better. I'm probably never going to be copy-pasting my classes and components into other apps, but a good class/component should be copy-paste-able without needing many dependencies. This avoids the "banana gorilla jungle problem", as named by Joe Armstrong. "Free Functions" also help with keeping those classes even more self-contained and decoupled: you can use Function types for callbacks and things like that, instead of having to couple the class to some other class or interface. The only thing the class has to worry about is that the function conforms to the type. - "Keep data (= classes) and functions separate. Divide and conquer complexity." Yep, 100% agree. Amen to that.
- galaxyLogic 3y agoRight. Functions and data can not be decoupled because functions must know what properties of data they need to access. So functions by necessity depend on data. BUT data, if it is really "data" should NOT depend on functions. So we have reduced what would be bi-directional dependency problem into one directional one. In a typical OOP design there would be no clear rules as to who can depend on whom and whom not.