Hi. My name is "Adam" and I'm a JavaScript developer. I've been class-free now, for... Oh, wait. I think I'm mixing up my meetings.
My regular...
For further actions, you may consider blocking this person and/or reporting abuse
This was an excellent article, thank you. It shines a light on something I’ve been struggling with (unknowingly) for years. I’ll try to keep this short. But first, one quick thing:
Is this the Module Design Pattern? I’m trying not to argue semantics but can’t you also export classes from modules? I think what we are talking about here is:
Factory Functions vs. Classes
Right? Both create objects. Both can do all the same things (inheritance, composition, encapsulation, polymorphism, etc.) The only real difference is performance optimization due to
class
creating a prototype and factory function creating a new scope for every instance, but this is a subtle difference until your JavaScript chops are more advanced. I’m curious your thoughts.Anyway, the main point is this:
TLDR: Using factory functions instead of classes is not using FP. It’s still just OO.
Six years ago when I was learning to code, the interwebs was full of JS bros (of which I am one) screeching about how the class keyword was ruining JS. At the same time, I’m reading all kinds of articles about how OO sucks and we should all be doing FP. I thought this was the same argument. I thought we should not use
class
, but instead use functions only, and therefore we are doing FP instead of OO. Whoops.So I don’t take any time to learn OO (because classes are bad and FP is better) but I’m definitely not doing FP because I’m writing React, state is all over the place, side effects are all over the place, etc. I’m basically just doing procedural programming and building big balls of spaghetti, refusing to learn anything about OO. I didn’t know what a constructor was until my third year as a programmer, making good money. So sad.
So, someone else I’m discussing this with just pointed out to me that whether we create our objects with classes or with factory functions is irrelevant. Either way, we are doing OO. And in fact I did watch a talk by Douglas Crockford where he said that in JS he does “class-free object oriented programming.” So, what I should have done all along is say, “well, there’s debate over how I should be creating my objects, so I’ll table that decision, but either way, I need to learn OO really well so I can learn to design complex systems.” I could have also said, “OO sucks so I’m going to write all my frontend code with Elm and do true FP.” But what happened instead was a bunch of confusion where I refused to learn OO but didn’t learn FP either and just spent 5 years afraid of classes and OO and stunting my growth.
I’m curious about your thoughts. Thanks so much for reading all that!
Wow. Great feedback. I'll try to address some of these as succinctly as possible.
Umm... yes and no. It's hard to say, with absolute certainty, what is-or-is-not a "module design pattern" because any available definitions of the pattern are, from my research, incredibly vague. One example I could give you is simply the
module.exports
methodology that's commonly seen in Node. Using the pattern I've highlighted above is just a slightly updated version ofmodule.exports
. Of course, just because that package uses the terminology of "module" doesn't necessarily mean that it qualifies as the module design pattern, but as you've pointed out this all gets incredibly semantic very fast.YES. Exactly. In fact, that was one of the central themes of the second blog that I ever wrote on this site: dev.to/bytebodger/the-class-boogey...
Yes. Yes, yes, YES. In fact, this article I wrote hits the same concept: dev.to/bytebodger/javascript-s-fun...
You've pretty much hit the nail on the head. I'll summarize my thoughts (which basically mirror yours) like so:
OOP can be a PITA. FP can be a PITA. Neither one is magically "better" or "worse". They are tools in your toolbox.
That being said, very few people I've ever met actually practice FP. Hell, very few can even accurately define it.
Most of the crap people talk about FP isn't even FP. FP doesn't mean "I write my code in JavaScript." It doesn't mean "I avoid using the
class
keyword." It doesn't mean "I write all of my code insidefunction() {...}
or() => {...}
statements."Although OOP understandably (and rightfully) gets a lot of crap for creating over-engineered, overly-abstracted concepts, it's still a crucial part of software engineering. And, as you've pointed out, it's a core part of JavaScript - whether people wanna admit that or not.
Amazing response, thank you. It feels good to be heard and understood, haha. Thanks for the therapy session. :-) I'll read those other articles!
Awesome article. Indeed classes are just self-aware modules with lots of syntactic sugar. But another important distinction I think is the support for mocking member functions when testing, e.g. with Jest you can
jest.mock(Local)
and it will mock the class so as to return instance mocks with mocked out member functions (methods). To my knowledge there is no built in support in Jest for mocking the module pattern (not to be confused with their support for mocking CommonJs/ES6 modules withjest.mock()
), which is a bit of a shame. That said, it's not too hard to enumerate all own properties on the module object and set them tojest.fn()
if they're functions.There’s one thins that I’m still struggling to understand. I come from Java and C# and in those languages it’s common to have a class that extends from another and to overwrite properties and methods from the inherited class to customize functionality for each class. How do you extend in JavaScript with this approach, and how can you overwrite properties and methods that you have in the original “module”?
Well, keep in mind that most JS/TS devs have a strong bias against inheritance. That being said, the answer to your question would be like so:
Which outputs this:
Thank you, this makes sense! I'm fairly new to JavaScript and I started to do some research into the whole Module Design Pattern thing, and I am a bit lost. Do you know of any books or online resources that you would recommend to learn more about it?
Unfortuntely, no. If you google "javascript module design pattern", you'll find other references. But I wasn't working off any primary resource.
I know everyones different -> and it compiles to the same thing anyhoo, but I am actually A BIG fan of classes... Im finding this post in a mission to find out WHY people hate on classes, and if there is any actual downside, or if people are just saying phrases that they have heard other people say.
lol anyhow thanks for the detailed post it doesnt bring me to the end of my journey but it does bring me closer.
Modern javascript actually has real classes with both private, protected and public properties.
A few points I am not sure was covered:
Yes this is also possible with importing the functions ,but much less elegant.
My point is that there's a use case for everything, and you seem to be 100% focused on React (frontend), and much less other frameworks, or backend.
I thought class in js was basically syntax sugar. You can use the ‘new’ keyword without the ‘class’ keyword for similar effect.
Great article, you have a really nice writing skill! Please keep it up!
Hi Adam,
Thanks for sharing your insights. I am not so found of the Module Design Pattern.
I think no-one should be opinionated about programming styles. Programming paradigms are tools, and as tools we should use the best one for the job when we see fit.
I like reminding my coworkers that javascript is in fact a prototype based object oriented programming langage with first class functions in it. It is not a pure functional langage like haskell, nor a pure object oriented langage like java used to be.
In Javascript we simply don't have the tools to do clean functionnal programming. And if doing something clean means using classes, you should do it. And in the same way, you should not use classes everywhere, not everything is a class.
Here are things that most functionnal programming langages offer and javascript don't :
So now, what is the issue everybody have with oop ?
From my point of view, the main issue with oop it's that the oop community abused two tools and made oop an over-engineering-fest (the enterprise syndrome):
On the opposite side, when maintaining big functionnal code bases, the main issues you face is that a lot of real objects (structure) are hidden by behaviour (functions).
React does not face this issue much, because components are the main building blocks of your infrastructure. So react components exposes structure naturally. And react hooks exposes behaviour naturally. And both gives you a nice and elegant balance that emerges naturally in your project (that's why react is awesome).
But in some part of your code that does not use react, identifying what your main building blocks are can be difficult and lead to bad designed functionnal code with functions-spagetti-fest. This is a big issue for maintenance. In some cases, using a class might be a good idea to make this code maintainable.
Now about why i don't like Module Design Pattern : No matter what some oop haters think, this is oop. Indeed, if what you are doing is, have an object instanciated by passing some parameters (it's obviously a constructor) and then calling functions to control the object (it's obviously a method), you are doing object oriented programming.
If some people really prefer writing boilerplate code to address the private field and method issue Javascript have right now... i would suggest them to use a babel transpiler and use tc39 private fields proposal. it's much more clean than using MDP.
First, I wanted to thank you for taking the time to write out this thoughtful reply. And for the most part, I agree with you. But I can't really write too much more here that explains my thoughts on the matter because my responses to Maciej Sikora in this same comment section pretty much highlight why I've moved to this design pattern for the time being. Part of it, quite frankly, is just a matter of practicality on my part. (React is pretty-much already in this pattern - and I write a ton of React.) Part of it is exhaustion. (If I can write code in Style A or Style B, and I personally like both styles equally, then I might just veer toward the one that inspires less whining from the fanboys.)
But again, I agree with your points and I totally appreciate the thoughtful feedback!
Hey Adam, as always great writing. But as always I have some concern about your way of thinking :). I mean the "Module Design Pattern" is nothing more than everybody was doing before class keyword was around, and what has its origin in Scheme. What you call MDP is really an object constructor, it takes some arguments and bakes you an object which has properties and functions working with them, and because of closure has some private scope of access. And if it is stateful it is clear OOP, but OOP in the old JS way, the JS without classes.
I get your point in terms of fanboys hunting you, and because of them avoiding class keyword, but if they are not ok with a "class" but they are ok with stateful MDP, then most probably they don't understand what OOP is. Class and MDP are the same thing, using one over another is only implementation detail.
Also take a look on this answer. Cheers Adam!
Of course I totally agree with you. As a bit of further clarification/distillation, I'll summarize my recent turn toward MDP like this:
React is my main focus (for now, at least - it tends to change every few years or so). Once React started moving much stronger to functions/Hooks, I found that nearly all of my React code looks much more like this pattern anyway. Maybe, when I'm writing a bunch of non-React stuff, I'll float back toward
class
. But for right now, it's easy to keep a consistent style across all my code.As outlined in the article, I do think there's one key benefit to this pattern over
class
- mainly, that it's somewhat "cleaner" and more intuitive to create private members. IMHO, that's not inconsequential. I find that many JS devs rarely even think about design patterns with regard to private variables, because the language doesn't make it easy for them to conceptualize them (like, for example, having a handy littleprivate
keyword available). So they rarely think about things like having protected access to update a variable. I've seen far too many instances where someone spins up a variable, alongside the variable's setter, and then they pass that setter around knowing dang well that the app will BREAK if that variable gets set to the "wrong" kind of value. Of course, this pattern doesn't fix that problem. But I do think it makes it easier to avoid it.Finally, this is absolutely a bit of a white flag on my part. The syntax I've shown above is something I'm perfectly comfortable with (again, because I'm a React dev). And as you've pointed out, the syntax above is truly just another version of what we get with
class
. But to be perfectly frank with you, if I can do something in two different ways, and I'm perfectly comfortable with both of those ways, but one of those ways will spawn an endless stream of petty squabbles from ill-informed language purists??? Well...Look into TypeScript
private
and the new#
although please use TypeScriptAnd thanks for including the political meme because we definitely don't talk about politics enough in tech. Definitely high IQ thing to obsess over
You're very welcome. I'm glad to see that us high-IQ folks can recognize each other.
Hi there, thank you for the excellent article. Can you share your thoughts on whether the module design pattern is suitable when we need more than one instance of the module? And in this case what's the best way for the instance methods to be bound to the object? Consider this example:
If I understand correctly, the module design pattern equivalent would be:
Are there any issues or pitfalls with this? Are both exactly equivalent?
What about enabling
instanceof
checks for module instances?Your syntax is a little different than my examples, but yes, this is functionally equivalent. I think that this is the simple way to think about it:
In JavaScript, there is no such thing as a 'class', at least not in the way that true OO programmers think of it. In, for example, Java, when a class is defined it doesn't represent anything at runtime - unless you choose to instantiate the class. Once you instantiate the class, it create a new object based upon the model (i.e., "class") that was defined in the code.
In JavaScript, even when you use the
class
keyword, a new object is still being created at runtime (even if you never instantiate the class with thenew
keyword). Then, when you create a new instance of that class, JS uses prototypical inheritance to create a new copy of the original object.In the module design pattern, we're using a function to return an object. In JavaScript, if you instead choose to use the
class
syntax, you're still creating an object. In true OO languages, no object is created (or returned) until you instantiate the class.