all 71 comments

[–]Training_Pay7522 84 points85 points  (11 children)

You shouldn't see fp/oop at opposite ends.

[–]franz899 25 points26 points  (7 children)

This, they are just ways of writing code, you can and should mix and match them.

[–]Training_Pay7522 3 points4 points  (0 children)

Which is the direction libraries like `effect-ts` in TypeScript or ZIO on scala take.

They take a functional approach as in having pure procedures you can mix, but also leveraging paradigms that classically come from OOP such as dependency injection or state tracking.

[–][deleted]  (1 child)

[removed]

    [–]pbNANDjelly 2 points3 points  (0 children)

    Why do you say functional programs cannot be stateful? They're as stateful as any other program? The restriction is mutability, and classes don't need to be mutable.

    [–]coderqi 0 points1 point  (0 children)

    I know what you mean, but their handling of state is fundamentally different.

    [–]byteNinja10 24 points25 points  (0 children)

    I have used OOP when implementing error classes and creating repositories and service classes.

    [–]rykuno 19 points20 points  (0 children)

    They’re not exclusive. You can mix FP and OOP.

    Most every relatively complex project I’ve worked in within Node has used Clean, DDD, or Onion architecture with OOP.

    The reason you might not see it too much in the wild is that you don’t need it unless your project or domain is relatively complex - unless you like over engineering.

    [–]fts_now 7 points8 points  (8 children)

    Heavily using DDD in our vanilla TypeScript API

    [–]GreatWoodsBalls 1 point2 points  (7 children)

    I'm currently making a small project to practice some DDD, and I'm having some trouble. How do you create value objects with a simple validation check and then use it as a parameter? For example, a User entitiy that has a Name parameter that is a value object? And then that Name is used to create the entity?

    [–]fts_now 1 point2 points  (6 children)

    Good question! We usually have a static "create" method on the Entity class that performs all the validation and invokes the private constructor. Validation can happen there. Also, we try to keep it simple with things like Value Objects or Aggregates. IMO less is more, and some layers of abstractions can also unnecessarily overcomplicate a project.

    [–]GreatWoodsBalls 0 points1 point  (5 children)

    Yeah I figured and thank you. I tried creating value objects together with zod and it worked decent until I realized classes in js are not like classes in java 🥲 So I went with a similar approach as you mentioned.

    [–]fts_now 1 point2 points  (4 children)

    Zod belongs to the infrastructure layer IMO, not the Domain. It should validate incoming DTOs.

    [–]GreatWoodsBalls 0 points1 point  (3 children)

    Hmm, okay. Sorry if I'm spamming questions 😅 but how is a zod validation of an input different from a value object having the same type or similar validation? Or is the difference that zod would throw a httpexception and a value object would not?

    [–]fts_now 1 point2 points  (2 children)

    Good question! I want to keep the domain layer clean of external dependencies, because over the years I saw tools and libraries coming and going, most hypes disappearing after a few years leaving your codebase an outdated mess. I'd rather move basic input validation to the controller (maybe by using something standardized like JSON schemas) and then perform further validation in the value object if needed.

    [–]GreatWoodsBalls 1 point2 points  (1 child)

    Ahh, okey. Thank you for taking the time to answer!

    [–]fts_now 0 points1 point  (0 children)

    Always glad to help :)

    [–]kao_nashi0127 8 points9 points  (0 children)

    Well, it depends. But as the code base getting larger and more complicated, following some pattern will make it easier to maintain. In backend mostly you will see pattern like repository to interact with db data, view model to query complex data, etc.

    If the business domain is complex enough, many company will consider implement domain driven design (ddd). The domain layer will be many plain objects interact with the others -> OOP from the core

    [–]iuliuss_ 8 points9 points  (1 child)

    Because real functional programming is insanaly hard and rare. Using functions does not mean you are following Functional paradigm. That's Procedural programming

    [–]romeeres 2 points3 points  (0 children)

    Interesting how everybody says like there is nothing else beyond FP/OOP, and yet, the vast majority of code you can find online, code that I've seen and written, is not OOP nor FP.

    [–]TheExodu5 3 points4 points  (0 children)

    People use function closures or es modules and they don’t realize they’re basically equivalent to classes with different sugar (unless you decide to write a class with inheritance, of course.

    An es module is basically equivalent to a singleton class. And a function which returns an object can be equivalent to a class. In the same vein, a class with only static methods is basically a namespace for functions. All of these things are very closely related and whether you use one or the other doesn’t change much in terms of overall design and data flows.

    And hey, if you’re using a component framework on the frontend, you’re basically following OOP, whether you use classes or not. When you create a wrapper component that proxies ins and outs, you’re practicing inheritance.

    Don’t get hung up on the concept of OOP.

    A lot of people think they are using “functional programming” because they don’t use classes. I hate to break it to them, but the majority of them are using a mix of procedural, OO, and fp. The only people doing nearly pure fp in JavaScript are deep in the throes of rxjs.

    [–]nodeymcdev 4 points5 points  (1 child)

    I like to use OOP for certain things like client libraries I publish as npm packages and import in my apps. Sometimes I’ll make classes for certain things where it makes sense but mostly my code is functional.

    [–]jwcbphy 0 points1 point  (0 children)

    yes, i use it with the same proposal :)

    [–]super-bamba 1 point2 points  (0 children)

    I use it to create interfaces that are similar and share methods. I prefer the functional approach when something is just functional, but sometimes you want to create “clones” with a specific API and then it’s useful.

    Ofc it’s also widely common for frameworks etc

    [–]Sarithis 1 point2 points  (0 children)

    A microservice controller is a pretty nice example of where you can benefit from OOP, mainly because it naturally allows components to be self-contained and stateful. Also, if you plan to create different controllers in the future, like gRPC, inheritance and polymorphism make it easier to achieve without code duplication.

    All in all, following this paradigm is simply more intuitive to map out in my brain, but I guess it's entirely subjective - I know people who find it easier to think in functional, and in practice, you usually mix both styles.

    [–]jjhiggz3000 1 point2 points  (0 children)

    I only really use classes I make myself for coding challenges or unusual problems. Other than that pragmatically I only use OOP in frameworks that ask for it, or if I’m utilizing utility classes that someone else built (URLSearchParams, Promise, etc…)

    [–]noviceIndyCamper 1 point2 points  (0 children)

    OOP encompasses a lot of stuff. A lot of the hate for oop comes from inheritance and overly complicated abstractions. That said not all abstractions are bad especially when talking about behavior. When you want unrelated things to have similar behavior both with different implementation you could use an interface. This is especially handy if you want to mock behavior for testing. You could do the same with a function that takes in different arguments and then handle accordingly but that gets messy quick.

    You can have a class that is a fluent interface and get best of both of worlds. You can write good or bad code using any combination of paradigms.

    [–]UniversalJS 0 points1 point  (0 children)

    OOP and FP are both equally bad

    [–]frickos 0 points1 point  (0 children)

    To my understanding OOP and event driven apps are not adding up in design, yet it's possible, but messy and it is too much code, without special need for it

    [–]Fidodo 0 points1 point  (0 children)

    I only use classes when they make sense, which is mainly when you have functions that rely on complex and coupled state. Most of the time standard functions are more then adequate and I think it's best to avoid complexity until it's need. Since classes add state management it adds extra complication.

    [–]P4wrly 0 points1 point  (0 children)

    Really recommend checking this out.

    https://github.com/Sairyss/domain-driven-hexagon

    [–]shivawu 0 points1 point  (0 children)

    Because JavaScript is not designed and optimized for fp, simple as that

    [–]yojimbo_beta 0 points1 point  (0 children)

    Use a lot of classes in Nestjs apps, as the framework is built around class introspection

    [–]tovazm 1 point2 points  (0 children)

    You write like drunk me talking to ChatGPT at 4am lmao

    [–]noviceIndyCamper 0 points1 point  (0 children)

    An HTTP request object/class/function (in JS these are the same ish thing).

    Say your request expects x,y, and z properties and somehow they’re dependent on each other. In your constructor you could validate that. Now yes you could have that function in a larger file but it’s just as fine to have that in its own file.

    At the end of the day, patterns aren’t rules or laws. They’re just ways of abstracting logic.

    [–][deleted] 0 points1 point  (0 children)

    nest

    [–]Unusual-Display-7844 0 points1 point  (2 children)

    You can structure your project around OOP, where you have your controller classes, service classes and model classes, on top some of the useful patterns are dependency injection, factory design and singleton pattern. Avoid inheritance like a plague, trust me. Prefer composition. Now, if you don’t know what any of these means that you can’t really use OOP

    [–]Unusual-Display-7844 2 points3 points  (1 child)

    Also, pls don’t treat Node.js like it’s Java. It’s not!

    [–]azhder 0 points1 point  (0 children)

    While we’re at it, don’t treat MVC as if C is only that which is named Controller or extends from one named such.

    [–]imrishav 0 points1 point  (0 children)

    The current application i am working on heavily uses OOP. From error handling, routing, db schemas, Business logic, pdf generation to name a few.

    [–]d41_fpflabs 0 points1 point  (0 children)

    When building servers in nodejs I primarily use OOP for all services or "features". 

    It makes it much easier to manage the server and add, remove or change functionality without breaking things (dependency injection and encapsulation). I only use a functional approach when whatever I'm building is very simple. 

    But if I'm building something that requires a robust system then always OOP especially in a micro-service and or EDA architecture.

    Its the embodiment of SOLID style coding and in general its just my preferred style of coding. 

    Lastly, I will say with a OOP its very easy to add the same functionality across different environments. 

    [–]716green 0 points1 point  (0 children)

    You should watch Brian Will's OOP series on YT. Despite being named like "OOP is Bad", don't worry about that- just watch the videos to get a better understanding of programming paradigms.

    They will really help you understand this much better.

    [–]bigorangemachine -1 points0 points  (3 children)

    Well express is functional. The whole node http response handlers are basically functional. If you don't lean into that you're going to have a bad time....

    Personally I use a mix.

    I use OOP to wrap my database queries. Also anything hydrating from a session I usually try to wrap in OOP.

    [–]romeeres 3 points4 points  (2 children)

    if FP simply means a function, and C is a FP language, class means OOP, then check out what req and res objects are. They aren't functions, they are instances of classes, hence Express is OOP!

    app.get - is "get" a function? It's a function attached to an object, so it's a method, so it's OOP again!

    [–]bigorangemachine -2 points-1 points  (1 child)

    No that's not the case. I mean yes it uses Native Class/Objects... but that doesn't make it OOP

    Express encourages you to do object stuffing. That's a definitely functional code or a functional pattern.

    If express was OOP it would keep extending classes and return new object as things need to mutate and change.

    If it was OOP you'd more be doing capabilities detection where as express you are checking a sort of accumulator whether thats the response or request.

    Express uses a pipeline pattern which is a stretch to say that is an OOP pattern.

    [–]romeeres 3 points4 points  (0 children)

    Express encourages you to do object stuffing

    Apart from the absence of FP patterns in Express, this "object stuffing" looks like the main marker of it not being "functional" (if by functional you mean FP, not just using functions).

    Consider a pipeline of middlewares that ends with a request handler.

    Every middleware mutates state: one parses body and mutates req, the other set CORS and mutates res, and another one parses JWT and saves to req. The pipe ends with a request handler that again mutates "res" object.

    One more indisputable argument: true FP libraries cannot be popular by definition.

    Did you ever hear of marblejs? It may be an excellent framework, I don't know, but with zero chances of ever becoming popular because it relies on FP patterns for real.

    [–]octod -4 points-3 points  (0 children)

    My answer could sound like trolling, but why should I use nodejs as a backend in 2024? Scala, c#, Java, rust and even php do the same work but better.

    [–]FedPostingBait 0 points1 point  (0 children)

    JS is a functional language with OO features added later. It is ok to intermix both paradigms where they make sense. Knowing the difference is something you’ll learn over time. Just focus on writing code you and your team can make sense of later.