Thanks Mark Seamann. It brought a different perspective altogether. I come from C# background. these concepts like ports and adapters or onion architecture and domain driven design and TDD are true fantacies to hear and would like to implement for us. But as you have rightly pointed out it falls out of Equilibrium so easily and so quickly with C#. Thanks for the explanation. Excellent Perspective. Thanks NDC for putting these videos online.
Fascinating talk, I think the idea of combining functional programming with DDD can be very valuable. However, I have to say that Mark misrepresents Evans's patterns at ca. 38:00. Entities and value objects are *not* meant to be just data holders, and Evans does *not* advocate for anemic domain models - quite the opposite is true. Those objects are very much meant to have behavior. What should be removed from them are operations that require outside dependencies, such as a database or an e-mail server (because that is infrastructure code, not domain logic, and it is "impure"). However, when you have domain logic that is essentially "pure", the right place to put it is on the entities or (even more so) value objects. Indeed, separating value objects from their behavior would weaken the usefulness of that pattern significantly.
It's also worth noting that both entity and value objects could/should contain validation logic so as to not allow for an entity to be created in an invalid state.
I believe the original authors of DDD methodology are object oriented programmers. The idea that an anemic data model is an anti pattern has no basis in performance or maintainability. To me rich domain models often just look like a Json littered with helper functions that should live somewhere else.
@@Wafflepudding They are called value objects because they represent values - things that have no identity and are fully described by their intrinsic properties - as opposed to entities which do have an identity. It has nothing to do with having behavior or not. And after all, DDD came out of OOP, where all objects are supposed to have behavior.
Modern, idiomatic C++ strongly recommends marking everything `const` or even `constexp` (able to execute at compile time), and we just got `consteval` (*must* run at compile time). There is strong emphasis on and automatic tooling for side-effect isolation. You can choose other paradigms, of course, but the thing I love about the language is that it is very staunchly a multi-paradigm language-we even got lambdas back in 2011. Idiomatic C++ enables the “pit of success” by providing mechanisms that enforce safe usage, using its powerful library-writing capabilities and new features to keep these mechanisms clean and clear. You don't hear much about “90s enterprise” OOP in C++ nowadays. You aren't supposed to put “symmetrical” functions (e.g. `operator+()`) inside a class, since it doesn't belong to a single object. Lambdas are zero-overhead (they're literally objects of anonymous classes that implement the `operator()()` function), and turn the `std::` algorithm library into pure beauty.
is still possible in C++ just do casting to get rid of the const thing? I remember from college that in a project when would have to bubble the const up like 10 levels, it was easier just to cast it to mutable and be done with it :)
That is a good base. And you will find lots of other benefits in OCaml, F# and similar. The type system is on a whole other level, the abstractions are amazing and the boilerplate is extremely reduced.
Good presentation, but there is a mistake regarding DDD. It is not about anemic models. Quite the opposite. Business logic goes into entities. Services are for logic that does not naturally fit in a single entity. A key part of DDD are the domain events. In your case you will be forced to trigger the domain events from the persistence module.
This is exactly what I also thought, the anemic model is a bad practice and is by no means recommended in DDD. The entities is the place where to mainly put business logic, not the services. Otherwise, I liked the explanation of the pure / impure function and the idea of ability to strictly block side effects with a functional approach.
I independently came to the same conclusions about how to write testable OO software (ie. the anemic domain model, leading to functional principles). What I find interesting is the complete lack of mindshare of this technique. Developers continue (after ALL these years) to develop OO by mixing state and functionality - this is catastrophic from a complexity management perspective as the presenter here notes. And developers are highly resistant to changing their worldview - most will actually sneer at any alternative approach. Highly frustrating when working on these kind of codebases!
Why use OO languages then? Whole point of OOP is to merge together data and methods that perform actions on this data into objects. By using anemic model you're basically coding procedurally and there's no point in using OO language.
This is not the problem of OOP per se, it's a problem of OOP done wrong. This code (and I guess the code you're referring to) just violates SRP. User shouldn't deal with saving itself to a DB or sending an email, it's not his responsibility as the DB as a whole is not his internal data. But it's OK to have *its own* behavior (i.e. behaviours dealing only with its own internal data), and this behaviour can be incapsulated and they are still perfectly testable without any additional code.
This epiphany happened to me as well. I’d apply SOLID principles to my projects and then realized what I’d been trying to write functional programming with so much noise from an OOP language.
Hearing people call FP domain modeling "anemic" signals to me that they are simply parroting Martin Fowler's blog instead of attempting to understand a new paradigm. (Not to mention the insensitive use of a debilitating medical condition as a programming analogy.) FP is in fact _great_ at encapsulating domain logic into the data model, often to the point of becoming inextricable! It simply does so in ways that you may be unfamiliar with, because it does so without objects or classes. Here's some more recommended viewing on the subject: ruclips.net/video/Up7LcbGZFuo/видео.html
In *DDD Entity and VO* are *not* only data container it has *behaviour* as well. and services only has that behaviour which *don'*t belongs to Entity or VO. what u are saying is kind of opposite what *Aggregate* is.
What exactly is the code at 46:19 damaged by test-driven development? Because it is wordy, a lot of boilerplate code? That code is actually the object-oriented equivalent to the functional code presented thereafter: we insert behaviour (function) from outside to create new behaviour (function) and we call this behaviour by the name the object is given.
Not sure why my comment was deleted but I was sharing C# code to do something similar to the functional shown here by: 1) using record to declare the class, 2) use Func parameter to pass getReservedSeats. Also 3) there is OneOf package to do discriminated unions. That's less convenient to write than in functional languages, but in all fairness, you could go that path.
Awesome talk, already learnt so much more (and most importantly, why!) with that talk, still valid one. It really blew my mind, not only because he put the effort to talk about these things, but to explain the reasons for them in a simple way and it really clicked on me. Thank you very much!
At one point, our group was going to promote test driven development and integration testing. However, we already had a huge amount of established code and it wasn't structured the best way. Some of us wrote unit tests, but they they upgraded the test library and broke a lot of those tests. By now it was time to do a re-write,, but this was just busy work for most, where we rewrote the front end and updated to a new MVC framework; the guts of the code weren't re-written. If you're able to test your ideas as you develop, you easily see when you're creating too many internal dependencies on external objects. I've also learned that its a mistake to tell yourself, "I'll just pass the whole object.", when all your needed to do is pass in the values from the object. You think its cleaner, but not.
Good talk! But the C# code for CapacityChecker (minute 46) is actually wrong (HasCapacity returns true if the number of seats exceeds capacity :-) . Following F# code is correct )
in minute 46:30, I think that this method "HasCapacity" is wrong. It should be this.capacity *>* reservation.Quantity + reserved Not important, but worth mentioning it. Other than that, very unique presentation
You can definitely do this in C#, push impurity to the boundary of your application and stop bleeding it everywhere. It's much easier to keep it up when the compiler slaps your wrist for violating it though.
Indeed! You can definitely do this in Assembly, but nobody sane even tries. Better tools don't open up new possibilities, they make doing the right thing easier.
@@Orlandofurioso95 But what makes you think that this is "the right thing to do" in the first place? Every time somebody gives you a recipe for success they a) limit your options to find a better solution and b) hand you a recipe for disaster, if you fail to apply the assumptions that make it a potentially good solution for SOME problems.
Anybody has seen ever in his life any real production functional code? I dont say it does not exist, but nobody shows it. All examples to show the glory of functional programming involves lists wth five integers or some record with two or three fields. There is some time I´m trying to learn F#, and apply it in a real functional way and I dont find the way to implement some algorithm that would be easy in oop. Concepts are really obscure or hard and when they are applied to some real code wich needs side effects (finally you need side effects to get something done) the code is really convoluted, not so elegant as the operation on 6 integer lists convey.
I designed a system with the onion architecture, following the functional principles in Typescript... It is not written in pure FP language but the idea is similar to the video. 1 year from release several hundred thousand orders recieved
"Later is never" is the fault of the development team, not something that should be accounted for in the language. I'd argue it's more valuable to be able to push a hotfix to production momentarily disregarding good practices than to ensure best code quality at the cost of an extra day of downtime. Wanting the language to enforce it is just trying to avoid the responsibility as a PM. You forfeit the right to bend the rules when it is actually need it only to reduce your efforts towards ensuring and maintaining code quality. I believe that, while it has its benefits, it is not a universally better approach
I don't think both code exerpts at 47:34 are doing the same thing. The F# code assumes that every execution of the check capacity function will be provided a get reserved seats function. This get reserved seats could be a different function at every invocation. The C# on the other hand assumes that the get reserved seats is going to be the same one across multiple calls, since it's pointing to the same object. An equivalent example would expect an interface with a getReservedSeats method as parameter to HasCapacity, resulting in no substantial difference between the two approaches.
"This get reserved seats could be a different function at every invocation" well, this can be achieved by currying. By having `getReservedSeats` as a parameter to a function, we basically shifted from dependency injection from constructor to function parameter. Basically instead of making a dummy class and a dummy interface and testing it, we just write a function and test it with an injected `getReservedSeats` that returns a stub response. that's it
@@DenisG631 I understood that and I'm saying that's not a practice reserved to functional programming. You could, and most likely should've done the injection of that dependency in the parameter, like most domain services are passed to domain entities. As for creating a dummy class... in a larger context I'm pretty sure that method wouldn't have been alone in the class and if so, I would argue for a refactor to better represent the model. The unit in functional programming and functions while oop is objects. Its a totally different way of modeling.
Question: If function_a calls function_b, then function_b calls function_c, and function_c calls function_d. Then would I have to pass in function_d to function_a at runtime?
Not necessarily. You could pass in function d to function c (in other words dependency injection) and then pass this partially applied function to function a for use at runtime. The partially applied functions should be created on application initialisation.
I was so hyped up at the beginning, really. I thought I was going to learn how to leverage the virtues of functional programming in DDD and ports and adapters but I believe that it was an unfortunate talk. In DDD, Entities an VO are not only data. There should be, indeed, the main business logic. DTO business entities is kind of an OO antipattern. So, the main advantage is the testability and decoupling due to implicit isolation of pure functions... that's basically Dependency Inversion/Injection principle in OO. Is it OOP a bit verbose? Maybe, but I don't think the mindshift effort from OO style to functional is worth for that reason. What I think is very interesting its the use of some of the functional programming patterns like monads in multiparadigm programming languages for achieve even more decoupling in subjects like concurrency or asynchrony (Futures, Observables, etc.).
Your assumption that it was "an unfortunate talk" is based upon fundamental lack of understanding on your part. You state that in DDD entities are not only data. Well, of course they're not only data; Seeman never said they were. DDD is a philosophy which applies to object-oriented languages. What Seeman is pointing out with regard to DDD is that functional programming has all the benefits of DDD without all the baggage that comes along with object-oriented languages such as C# and Java.
When the ball is on top of the hill, make sure it rolls forward to the far side if the equilibrium is broken. That way stakeholders will enjoy new views. The moment the ball rolls back, you lose your job and gain little attention to your call for total revamp.
To summarize the entire talk: OOP is bad because hammer is bad with screws. FP is good because a saw is good at cutting wood. If getResevedSeats, for whatever reason, slows down and I have to check the seats of 500 venues/s, then I am not going to create an in memory database just to cache 20k reserved seats When I have memory access right there.
I don't like impure functions but I have no idea how to prevent them in c#. When you are 10 layers down in a business process and its logic depends upon the value of something in the db then there is no other way but to call the db. The only way I can see of preventing this is loading the entire state of your business context at the start of the business process but thats not a fix all either, what if you need to send a message in some logic buried layers down? Its a great talk but as a c# developer I still don't see the usefulness of trying to do pure functional programming. I program with modules as he explained, I call it business units, I make every business rule a function (often times one line of code) with a very descriptive name and then use semi-functional programming to make the code highly readable, except that my higher order functions still call repositories.
You don't prevent impure functions in C#. Pure versus impure is a functional programming ideology. C# is not a functional language; it is an object-oriented language.
@@gregoryshields4258 There are courses on pluralsight that talk about how to do functional programming in c#, but lets assume that the language prevents this kind of programming, doesn't this problem also occur in purely functional languages? At some point you need to hit up a db or an api, I don't see how that works in functional programming languages.
We don't need to assume. Just because there are constructs in C= which borrow elements of functional style doesn't mean it can do functional programming. Seeman answers your questions right in the talk, and gives examples.
Ideally, all the business context that you need is passed as an argument to the function that processes it. So you have an "outer" function that touches the DB once and reads all the relevant data, and that data gets passed to the (pure) functions that implement the business logic, and return a representation of what should be done. Finally, an impure function does the thing. Here is some (pseudo) F# that reads from a database the desired and actual amount of supplies and issues orders for what's missing: fun refillSupplies () = // this function is impure, and takes Unit as input (like void in C) getInfoFromDB () // here we call the impure function that reads the DB |> computeMissingSupplies // |> is the pipe operator; it works like the bash | pipe. This function is pure |> supplyListToOrder // This function is pure: it converts the list of missing supplies to an order, and returns a JSON string or whatever. // Crucially, it is easily testable, since it is pure. |> orderSupplies // this function is impure. It only sends an HTTP request or writes to a DB or whatever. // Function signatures: fun getInfoFromDB () : (Supply list, Supply list) // presumably the two lists are the desired and available supplies fun computeMissingSupplies (desired : Supply list, available : Supply list) : Supply list // Notice how the input type matches the output type of the previous function. fun supplyListToOrder (supplies : Supply list) : JSON fun orderSupplies (order : JSON) : () // This returns Unit.
i did not understand the part about Pure functions being a subset of isolated functions.. I do not see how those domains are not the same. If a functions output can be altered by anything not passed into it via arguments, is it not be definition impure+unisolated?
Isolated functions can be impure. Consider a random number generator function. It doesn't need to know anything about the program around it (the "outside world") to run, and is thus isolated (meaning that it doesn't read or mutate anything outside of its own scope). However, it is impure, because it is not idempotent - calling the function multiple times will yield multiple results. In general, when not enforced by a compiler, isolation is a consequence of how the code is written. Purity is a consequence of the algorithmic definition of that function if and only if that function is isolated. This is why pure functions are a subset of isolated functions. (You actually said this, and it's true - a function that is not isolated is automatically impure, and your example is correct.)
@@JeddAhyoung Your explanation is clear and correct, but I have a nitpick - the word idempotent does not mean what you think it means. A function is idempotent if applying it recursively to its own output has the same effect as applying it only once. For example, the function fun timesZero x = x*0 is idempotent because timesZero(timesZero(x)) = timesZero(x) for all x. This is not a requirement for purity; in fact very few functions are idempotent. The most common class of idempotent functions I can think of are type casts in C-like languages, (int) 3.14 == (int) (int) 3.14 as well as constant functions that ignore their arguments.
@@riccardoorlando2262 Right, yeah, good point. That's the definition, but the implications are the same with computer science (although simplified for nonpure functions). With something like a random number generator, even assuming a seed, it's not idempotent if it's called multiple times (and as the function takes no input value, it'd be the same as "random(random(random()))". I admit that random number generation may be a bad example as the same seed will produce the same sequence of values, and I guess you could argue whether the return value is each individual instance or the the entire set of random numbers produced by that seed. Idempotence gets a little weird when external state is thrown into the mix. It seems that the computer science definition is a little looser than the mathematics definition: en.wikipedia.org/wiki/Idempotence#Computer_science_meaning.
41:14 actually in functional programming there's only data and evaluation, or rather expressions which can be reduced to a normal form (data), because functions are data too. An example of a not yet reduced expression is a redex (a lambda applied to a value) like `(\x -> x+1) 3` which reduces to a data, namely `4`
I think about the struggle the people who first claimed that the earth was round had to go through before the majority accepted it as a fact. Much like functional programmers do to day
I have my doubts. First, I haven't seen a reasonable example, in the speech, where there's more than the naked statement (i.e. not supported by any kind of reasoning or data) that OOP falls apart, i.e. that it's an unstable equilibrium. Second, I expect a programmer able to write bad OO code will be even more capable of writing crappy functional code. Third, no engineering profession today is simple. If you want to design cars, or ships, or power plants, or roads, or bridges, the engineering discipline you need to practice is a lot more rigorous and the systematic knowledge you need to acquire is more complex than what many software engineers do/know. Could _this_ be the reason we have a lot more failed projects to show than any other engineering discipline? Fourth, I remember a statement appearing at the end of Martin Fowler's blog post about the LMAX architecture, in a footnote: "An interesting side-note. While the LMAX team shares much of the current interest in functional programming, they believe that the OO approach provides a better approach for this kind of problem. They've noticed that as they work to write faster code, they move away from a functional style towards OO style. Partly this because of the copying of data that functional styles require to maintain immutability. But it's also because objects provide a better model of a complex domain with a richer choice of data structures." This is no negligible concern, in code written for production, even when your system is smaller than what the LMAX developers did. For one, because latency, regardless of the scale of a system, is always a pain. Therefore, I wouldn't voluntarily rely on a paradigm which takes away most control from me, as a programmer, in large parts of a system - I'd see this as a risk too huge to take. Fifth, I personally feel that a functional style is a lot less readable as documentation, especially as you start using higher order functions. With typical OO, code can be read much like a paper document. Indexing is easy, therefore you can easily use tools to navigate it. The way it executes maps pretty precisely to its static structure. Once you start using higher order functions in FP (without which, IMO, FP looses much of its appeal, becoming age-old structured programming from the times of plain C), this structure melts away. The consequence is that coming back to a codebase you haven't worked on in months is hard, getting someone up to speed with a functional codebase he has never seen before is even harder. In a professional setting, I think this is a significant drawback of FP. I do use functional idioms myself, but only at the leafs, as an implementation detail, of my object-oriented code. Whenever I write code, I try to describe it to people who will work on it after me, instead of just making it work. I think I could do this equally well with a more, or even fully functional, idiom, regarding _what_ the code does, but I would not be able to give fellow programmers an as easy to use map through the code as I can do with an OO style. Maybe I still have to learn a lot about FP, and my view on FP is skewed by not knowing enough about it. But at least for the time being, while I do see its merit in some regards, I don't think FP is a paradigm to embrace for fully coding large and complex projects. It's not that it's impossible, I just think it's less productive, in the long run, if you factor human aspects into the equation. To me, at my current knowledge level, it's just a tool in a toolbox, to be used when it's most useful without introducing more subtle and more costly problems than the code itself.
OOP doesn't fall apart if you follow best practices such as SOLID, DDD. It's just that when you do that (follow best practices), you find yourself program in FP style but with more verbosity.
I have to disagree. I recently changed job, came to huge legacy C# project. It's pretty standard, DI everywhere etc. Once you find the first EntityFactoryFactoryDecoratorFacade you are done without the debugger. Trying to find which one of the 5 subclasses trows NullReferenceException on a field in shared base class. Haven't worked with F# in commercial setting, but I don't really think it's worse. It may be not better, but I don't think it's worse. (I know it's bad code and bad practises, but they are there) On the other hand, I fell into the reactive programming path, and C# is pretty much the best language to do that, especially with libraries like DynamicData and ReactiveUI. The ease of jumping back and fourth between Observables and tasks is great.
@@Qrzychu92 My understanding of your statement is that you blame OOP for the bad shape of the codebase, and assume that the same team(s) that developed that mess, at the same skill level, with the same history of the project, would have created a better structure using FP. How come? IMO it's much more reasonable to assume that programmers capable of creating a mess will maintain that capability regardless of the programming paradigm they use.
Isn't it the case that returning an IO monad in your function doesn't make it impure? I though impure function were ones that cause side-effects that aren't encoded in the type system: en.wikipedia.org/wiki/Pure_function#I/O_in_pure_functions
@@lepidoptera9337 It's not all about the name, but people will judge a book by its cover. The concept of the paradigm was about message passing more than objects/containers. Calling it object oriented causes people focus more on the objects rather than message passing.
I like it and agree, but there's not enough information here to make the case against OOP. I'm not saying he didn't say stuff about it, but imagine using his reasoning against an industry that's been doing OO for decades -- and they're been successful at it -- how do you teach them they should change -- only by showing real world pain-points, not "oh look, this is too much code to create a class".
CapacityChecker, what a weird class Just implement hasCapacity(int) in Reserveration class and get rid of feature envy code smell and also have testable code
That's the point of the talk, Reservation it's a DTO, a object that only contains data, the CapacityChecker is a class/module with a specific function (a business logic) which also implements error handling (returning Success and Error objects), if you move the capacity handling code in the Reservation class it will be less testable and isolated because you will need to instantiate the Reservation class with all the context and data it requires in a test, to only test the capacity handler function/method. It's basically changing the flow of the program of: Reservation (a bloated class, with data and methods, business logic and calls data directly from DB) to: A module/function called CapacityChecker which receives two things: a Reservation (DTO) and a Service(for access of Database), then it deals with the logic and then returns the Success Object or Error of Reservation. You are naturally doing dependency Inversion here making things decoupled.
And yep, you could add dependency inversion on the Reservation class but you are bloating the constructor and basically also doing DDD wrong because you are mixing a entity object with business rules (it's the same as the User with email sending function for example).
His explainations about DDD are just wrong. He sais, that Entites and Value-Objects cannot contain businesslogic and is put into those "services". But DDD is about the complete opposite. Acutally the "Part2"-Part of the Book only about the topic to tie data and behaviour together. I have the feeling that he did not read the book. Entites consist of Value-Objects. Also Entities are composed to Aggregates. An Aggregate has a global identity and is responsible for its consistency and owns its business logic. All businesslogic that fits to an Aggregate/Entity/ValueObject should go into this respective class. If an requirement does not fit into one of those entites/aggregates/value-objects or has a technical aspect to it (like repositories, who speak to DBs), the idea is to create a so called "domain-service", wich then implements this logic. But the goal is to reduce the amount of "services" and tie data and logic together, to hide and protect the data, since DDD is about processes and behaviour. This is probably not functional, since Entites and Aggregates can change over time, but keeping the functional ideas in mind by lowering the sideeffects to a minimum helped me a lot personally.
Great talk. A key concept is how side effects are approached differently: Hexagonal Architecture: Allow your class to call side effects from your business logic when needed but use interfaces to inject different implementations. Functional Programming (F#): Allow your business logic to run either purely (testing )or impurely (prod) passing functions that may or may not be impure. Languages that support lambda expressions (Java, Kotlin, C#, etc) can use the same principle that F# FP is using. But it isn't as natural of course. Although, in my opinion, this would create far too many testing surfaces, more than needed. A great talk on how to write Hexagonal Architecture (and how BDD is a perfect complement): ruclips.net/video/sOaS83Ir8Ck/видео.html
This got me interested: Hexagonal Architecture: Allow your class to call side effects from your business logic when needed but use interfaces to inject different implementations. By Hexagonal Architecture you mean OOP languages? And is this sentence your idea how it should be done in OOP - or is it some well known paradigm to use Interfaces for impure jobs? I am just asking for little bit more context - I am not so experienced developer.
I've listened to good functional programming talks, this was not one of them. I'm pretty sure functional code can be done badly as well, so bringing up examples written by 8 year olds as something you can solve in functional is kinda dumb.
There are too many deliberate lies in this speech. 33:20 Let's define things correctly. Encapsulation: "put data and methods in a bounded context". Information hiding: "protect invariants" the domain must always be valid. 34:35 Now let's open "Patterns of Enterprise Application Architecture" about Active Record: If your business logic is complex, you'll soon want to use your object's direct relationships, collections, inheritance, and so forth. These don't map easily onto Active Record, and adding them piecemeal gets very messy. Another argument against Active Record is the fact that it couples the object design to the database design. This makes it more difficult to refactor either design as a project goes forward. As the speech said, these books have too many pages. But this is not a reason to stop at the table of contents. Terribly bad, no matter how much I like Mark's articles on FP, every word about OOP in this speech is simply an ode to incompetence.
26:33 * tells how cool is to draw an owl in haskell * next slide * owl is drawn cut in half with guts falling out mixed with cybernetic implants * speaker doesn't give a f
Seriously, `hoistEither`, `runEitherT` (why not `runExceptT`?), `liftIO` and a `>>=` (plumbing operator) is not what the audience wants to see to get inspired to go functional right away.
IO is *not* impure. That's an imperative-programming perspective which is fundamentally unhelpful for the act of *designing* software systems (which is the thing we programmers are, theoretically *actually paid* to do).
IO as a concept is impure, because it has state. Sure, you can pass around an IO effect, which doesn't make the function impure, but whenever you try to materialise the IO you get stateful behaviour.
IO is a conversation consisting of continuously novel and unknown data; therefore, it is impure. Your second statement I couldn't make any sense of, but I would suggest that you just need to study up more on the-very simple-philosophy of what functional programming is.
It is pure as long as you don't run it. You can think of IO values as imperative recipes (or code) which you can pass around as value, but at the end of the day you will compile your code and run an IO recipe, which is of course impure
So the speaker critizise a class in OOP for being writen in a complicated way to be testable and at the same time he says that we must forget 20 years of OOP just to write functions thar are more testable? My God.
@@DaniloSouzaMoraes Hi, the point I was trying to make is that if I apply SOLID principle to my OOP code, I'd find myself writing FP code, but with more boilerplate code. blog.ploeh.dk/2014/03/10/solid-the-next-step-is-functional/
@@DaniloSouzaMoraes in Haskell you can not write inpure functions for instance. idk how one can achieve that in Ocaml/F#/Clojure, but at least FP programmers are aware of side-effects and them being bad. Java/C# programmers write inpure functions all the time
@@linhe6729 You find yourself writing FP code that follows the SOLID principles, yes. You still need those principles when writing FP, though. To break the S just imagine all your pure functions written as a single function, without composition. To break the D, just imagine yourself modeling a system starting from the database access functions. Those are inpure. Then you add functions that compose those and so on. Youll endup with a totally inpure system. The FP paradigm doesn't grant code quality on its own. Also, just like Single Responsability Principle leads to a functional style of design, Opaque Types in FP lead to OOP style of design. That duality is everywhere.
The truest software development quote of all time: "Later is Never"
One of the best-delivered technical talks I have ever seen.
Mark is a great speaker. Check out his One Kata, Three Languages talk as well.
@@CripplingDuality Thanks for the video recommendation, it's a good one. ^^
Thanks Mark Seamann. It brought a different perspective altogether. I come from C# background. these concepts like ports and adapters or onion architecture and domain driven design and TDD are true fantacies to hear and would like to implement for us. But as you have rightly pointed out it falls out of Equilibrium so easily and so quickly with C#. Thanks for the explanation. Excellent Perspective. Thanks NDC for putting these videos online.
Fascinating talk, I think the idea of combining functional programming with DDD can be very valuable. However, I have to say that Mark misrepresents Evans's patterns at ca. 38:00. Entities and value objects are *not* meant to be just data holders, and Evans does *not* advocate for anemic domain models - quite the opposite is true. Those objects are very much meant to have behavior. What should be removed from them are operations that require outside dependencies, such as a database or an e-mail server (because that is infrastructure code, not domain logic, and it is "impure"). However, when you have domain logic that is essentially "pure", the right place to put it is on the entities or (even more so) value objects. Indeed, separating value objects from their behavior would weaken the usefulness of that pattern significantly.
It's also worth noting that both entity and value objects could/should contain validation logic so as to not allow for an entity to be created in an invalid state.
I believe the original authors of DDD methodology are object oriented programmers. The idea that an anemic data model is an anti pattern has no basis in performance or maintainability.
To me rich domain models often just look like a Json littered with helper functions that should live somewhere else.
Hot take: Value objects should just hold data, I think that is why we call them "value objects"
@@Wafflepudding They are called value objects because they represent values - things that have no identity and are fully described by their intrinsic properties - as opposed to entities which do have an identity. It has nothing to do with having behavior or not. And after all, DDD came out of OOP, where all objects are supposed to have behavior.
Excellent explanation of pure/impure. That was a long time blockage in my head regarding Haskell. Thank you Mr. Mark Seeman!
Modern, idiomatic C++ strongly recommends marking everything `const` or even `constexp` (able to execute at compile time), and we just got `consteval` (*must* run at compile time). There is strong emphasis on and automatic tooling for side-effect isolation. You can choose other paradigms, of course, but the thing I love about the language is that it is very staunchly a multi-paradigm language-we even got lambdas back in 2011. Idiomatic C++ enables the “pit of success” by providing mechanisms that enforce safe usage, using its powerful library-writing capabilities and new features to keep these mechanisms clean and clear.
You don't hear much about “90s enterprise” OOP in C++ nowadays. You aren't supposed to put “symmetrical” functions (e.g. `operator+()`) inside a class, since it doesn't belong to a single object. Lambdas are zero-overhead (they're literally objects of anonymous classes that implement the `operator()()` function), and turn the `std::` algorithm library into pure beauty.
is still possible in C++ just do casting to get rid of the const thing? I remember from college that in a project when would have to bubble the const up like 10 levels, it was easier just to cast it to mutable and be done with it :)
That is a good base.
And you will find lots of other benefits in OCaml, F# and similar.
The type system is on a whole other level, the abstractions are amazing and the boilerplate is extremely reduced.
Good presentation, but there is a mistake regarding DDD. It is not about anemic models. Quite the opposite. Business logic goes into entities. Services are for logic that does not naturally fit in a single entity. A key part of DDD are the domain events. In your case you will be forced to trigger the domain events from the persistence module.
This is exactly what I also thought, the anemic model is a bad practice and is by no means recommended in DDD. The entities is the place where to mainly put business logic, not the services. Otherwise, I liked the explanation of the pure / impure function and the idea of ability to strictly block side effects with a functional approach.
I independently came to the same conclusions about how to write testable OO software (ie. the anemic domain model, leading to functional principles). What I find interesting is the complete lack of mindshare of this technique. Developers continue (after ALL these years) to develop OO by mixing state and functionality - this is catastrophic from a complexity management perspective as the presenter here notes. And developers are highly resistant to changing their worldview - most will actually sneer at any alternative approach. Highly frustrating when working on these kind of codebases!
Why use OO languages then? Whole point of OOP is to merge together data and methods that perform actions on this data into objects. By using anemic model you're basically coding procedurally and there's no point in using OO language.
There is no point in using an OOP.
We've been waiting for people to finally realize this.
The ONLY legit argument for OOP today is legacy code.
This is not the problem of OOP per se, it's a problem of OOP done wrong. This code (and I guess the code you're referring to) just violates SRP. User shouldn't deal with saving itself to a DB or sending an email, it's not his responsibility as the DB as a whole is not his internal data. But it's OK to have *its own* behavior (i.e. behaviours dealing only with its own internal data), and this behaviour can be incapsulated and they are still perfectly testable without any additional code.
This epiphany happened to me as well. I’d apply SOLID principles to my projects and then realized what I’d been trying to write functional programming with so much noise from an OOP language.
Hearing people call FP domain modeling "anemic" signals to me that they are simply parroting Martin Fowler's blog instead of attempting to understand a new paradigm. (Not to mention the insensitive use of a debilitating medical condition as a programming analogy.)
FP is in fact _great_ at encapsulating domain logic into the data model, often to the point of becoming inextricable! It simply does so in ways that you may be unfamiliar with, because it does so without objects or classes. Here's some more recommended viewing on the subject:
ruclips.net/video/Up7LcbGZFuo/видео.html
In *DDD Entity and VO* are *not* only data container it has *behaviour* as well.
and services only has that behaviour which *don'*t belongs to Entity or VO.
what u are saying is kind of opposite what *Aggregate* is.
What exactly is the code at 46:19 damaged by test-driven development? Because it is wordy, a lot of boilerplate code? That code is actually the object-oriented equivalent to the functional code presented thereafter: we insert behaviour (function) from outside to create new behaviour (function) and we call this behaviour by the name the object is given.
Impressive articulation on why Functional Programming contributes to stability...
Not sure why my comment was deleted but I was sharing C# code to do something similar to the functional shown here by: 1) using record to declare the class, 2) use Func parameter to pass getReservedSeats. Also 3) there is OneOf package to do discriminated unions. That's less convenient to write than in functional languages, but in all fairness, you could go that path.
Thoroughly enjoyed every second of this talk. Thank you! 🙏🏻
Awesome talk, already learnt so much more (and most importantly, why!) with that talk, still valid one. It really blew my mind, not only because he put the effort to talk about these things, but to explain the reasons for them in a simple way and it really clicked on me. Thank you very much!
I'm sold on functional programming!
I'm not using any functional language yet, but still, they're are so many good advices in this video equally applicable in OO languages.
At one point, our group was going to promote test driven development and integration testing. However, we already had a huge amount of established code and it wasn't structured the best way. Some of us wrote unit tests, but they they upgraded the test library and broke a lot of those tests. By now it was time to do a re-write,, but this was just busy work for most, where we rewrote the front end and updated to a new MVC framework; the guts of the code weren't re-written. If you're able to test your ideas as you develop, you easily see when you're creating too many internal dependencies on external objects. I've also learned that its a mistake to tell yourself, "I'll just pass the whole object.", when all your needed to do is pass in the values from the object. You think its cleaner, but not.
Good talk! But the C# code for CapacityChecker (minute 46) is actually wrong (HasCapacity returns true if the number of seats exceeds capacity :-) . Following F# code is correct )
in minute 46:30, I think that this method "HasCapacity" is wrong. It should be this.capacity *>* reservation.Quantity + reserved
Not important, but worth mentioning it.
Other than that, very unique presentation
You can definitely do this in C#, push impurity to the boundary of your application and stop bleeding it everywhere. It's much easier to keep it up when the compiler slaps your wrist for violating it though.
Indeed! You can definitely do this in Assembly, but nobody sane even tries. Better tools don't open up new possibilities, they make doing the right thing easier.
@@Orlandofurioso95 But what makes you think that this is "the right thing to do" in the first place? Every time somebody gives you a recipe for success they a) limit your options to find a better solution and b) hand you a recipe for disaster, if you fail to apply the assumptions that make it a potentially good solution for SOME problems.
Amazing talk, absolutely fucking amazing. We experience the same "pit of success" with our monolith fully FP frontend.
Million thanks for sharing this video
Anybody has seen ever in his life any real production functional code? I dont say it does not exist, but nobody shows it. All examples to show the glory of functional programming involves lists wth five integers or some record with two or three fields. There is some time I´m trying to learn F#, and apply it in a real functional way and I dont find the way to implement some algorithm that would be easy in oop. Concepts are really obscure or hard and when they are applied to some real code wich needs side effects (finally you need side effects to get something done) the code is really convoluted, not so elegant as the operation on 6 integer lists convey.
What problems would be easy in oop? Could you give a few examples, I am trying to learn F# too.
I designed a system with the onion architecture, following the functional principles in Typescript... It is not written in pure FP language but the idea is similar to the video. 1 year from release several hundred thousand orders recieved
"Later is never" is the fault of the development team, not something that should be accounted for in the language. I'd argue it's more valuable to be able to push a hotfix to production momentarily disregarding good practices than to ensure best code quality at the cost of an extra day of downtime. Wanting the language to enforce it is just trying to avoid the responsibility as a PM. You forfeit the right to bend the rules when it is actually need it only to reduce your efforts towards ensuring and maintaining code quality. I believe that, while it has its benefits, it is not a universally better approach
I don't think both code exerpts at 47:34 are doing the same thing. The F# code assumes that every execution of the check capacity function will be provided a get reserved seats function. This get reserved seats could be a different function at every invocation. The C# on the other hand assumes that the get reserved seats is going to be the same one across multiple calls, since it's pointing to the same object. An equivalent example would expect an interface with a getReservedSeats method as parameter to HasCapacity, resulting in no substantial difference between the two approaches.
"This get reserved seats could be a different function at every invocation"
well, this can be achieved by currying.
By having `getReservedSeats` as a parameter to a function, we basically shifted from dependency injection from constructor to function parameter.
Basically instead of making a dummy class and a dummy interface and testing it, we just write a function and test it with an injected `getReservedSeats` that returns a stub response. that's it
@@DenisG631 I understood that and I'm saying that's not a practice reserved to functional programming. You could, and most likely should've done the injection of that dependency in the parameter, like most domain services are passed to domain entities.
As for creating a dummy class... in a larger context I'm pretty sure that method wouldn't have been alone in the class and if so, I would argue for a refactor to better represent the model.
The unit in functional programming and functions while oop is objects. Its a totally different way of modeling.
Question: If function_a calls function_b, then function_b calls function_c, and function_c calls function_d. Then would I have to pass in function_d to function_a at runtime?
Not necessarily. You could pass in function d to function c (in other words dependency injection) and then pass this partially applied function to function a for use at runtime. The partially applied functions should be created on application initialisation.
I was so hyped up at the beginning, really. I thought I was going to learn how to leverage the virtues of functional programming in DDD and ports and adapters but I believe that it was an unfortunate talk. In DDD, Entities an VO are not only data. There should be, indeed, the main business logic. DTO business entities is kind of an OO antipattern.
So, the main advantage is the testability and decoupling due to implicit isolation of pure functions... that's basically Dependency Inversion/Injection principle in OO. Is it OOP a bit verbose? Maybe, but I don't think the mindshift effort from OO style to functional is worth for that reason.
What I think is very interesting its the use of some of the functional programming patterns like monads in multiparadigm programming languages for achieve even more decoupling in subjects like concurrency or asynchrony (Futures, Observables, etc.).
Your assumption that it was "an unfortunate talk" is based upon fundamental lack of understanding on your part. You state that in DDD entities are not only data. Well, of course they're not only data; Seeman never said they were. DDD is a philosophy which applies to object-oriented languages. What Seeman is pointing out with regard to DDD is that functional programming has all the benefits of DDD without all the baggage that comes along with object-oriented languages such as C# and Java.
Thanks for sharing
He is on 2x speed.
you know
Thanks. Nice examples
When the ball is on top of the hill, make sure it rolls forward to the far side if the equilibrium is broken. That way stakeholders will enjoy new views. The moment the ball rolls back, you lose your job and gain little attention to your call for total revamp.
To summarize the entire talk:
OOP is bad because hammer is bad with screws.
FP is good because a saw is good at cutting wood.
If getResevedSeats, for whatever reason, slows down and I have to check the seats of 500 venues/s, then I am not going to create an in memory database just to cache 20k reserved seats When I have memory access right there.
Excellent talk!
I don't like impure functions but I have no idea how to prevent them in c#. When you are 10 layers down in a business process and its logic depends upon the value of something in the db then there is no other way but to call the db. The only way I can see of preventing this is loading the entire state of your business context at the start of the business process but thats not a fix all either, what if you need to send a message in some logic buried layers down?
Its a great talk but as a c# developer I still don't see the usefulness of trying to do pure functional programming.
I program with modules as he explained, I call it business units, I make every business rule a function (often times one line of code) with a very descriptive name and then use semi-functional programming to make the code highly readable, except that my higher order functions still call repositories.
You don't prevent impure functions in C#. Pure versus impure is a functional programming ideology. C# is not a functional language; it is an object-oriented language.
@@gregoryshields4258 There are courses on pluralsight that talk about how to do functional programming in c#, but lets assume that the language prevents this kind of programming, doesn't this problem also occur in purely functional languages?
At some point you need to hit up a db or an api, I don't see how that works in functional programming languages.
We don't need to assume. Just because there are constructs in C= which borrow elements of functional style doesn't mean it can do functional programming. Seeman answers your questions right in the talk, and gives examples.
Ideally, all the business context that you need is passed as an argument to the function that processes it.
So you have an "outer" function that touches the DB once and reads all the relevant data, and that data gets passed to the (pure) functions that implement the business logic, and return a representation of what should be done. Finally, an impure function does the thing.
Here is some (pseudo) F# that reads from a database the desired and actual amount of supplies and issues orders for what's missing:
fun refillSupplies () = // this function is impure, and takes Unit as input (like void in C)
getInfoFromDB () // here we call the impure function that reads the DB
|> computeMissingSupplies // |> is the pipe operator; it works like the bash | pipe. This function is pure
|> supplyListToOrder // This function is pure: it converts the list of missing supplies to an order, and returns a JSON string or whatever.
// Crucially, it is easily testable, since it is pure.
|> orderSupplies // this function is impure. It only sends an HTTP request or writes to a DB or whatever.
// Function signatures:
fun getInfoFromDB () : (Supply list, Supply list) // presumably the two lists are the desired and available supplies
fun computeMissingSupplies (desired : Supply list, available : Supply list) : Supply list // Notice how the input type matches the output type of the previous function.
fun supplyListToOrder (supplies : Supply list) : JSON
fun orderSupplies (order : JSON) : () // This returns Unit.
i did not understand the part about Pure functions being a subset of isolated functions.. I do not see how those domains are not the same. If a functions output can be altered by anything not passed into it via arguments, is it not be definition impure+unisolated?
Isolated functions can be impure. Consider a random number generator function. It doesn't need to know anything about the program around it (the "outside world") to run, and is thus isolated (meaning that it doesn't read or mutate anything outside of its own scope). However, it is impure, because it is not idempotent - calling the function multiple times will yield multiple results.
In general, when not enforced by a compiler, isolation is a consequence of how the code is written. Purity is a consequence of the algorithmic definition of that function if and only if that function is isolated. This is why pure functions are a subset of isolated functions. (You actually said this, and it's true - a function that is not isolated is automatically impure, and your example is correct.)
@@JeddAhyoung Your explanation is clear and correct, but I have a nitpick - the word idempotent does not mean what you think it means.
A function is idempotent if applying it recursively to its own output has the same effect as applying it only once. For example, the function fun timesZero x = x*0 is idempotent because timesZero(timesZero(x)) = timesZero(x) for all x.
This is not a requirement for purity; in fact very few functions are idempotent. The most common class of idempotent functions I can think of are type casts in C-like languages,
(int) 3.14 == (int) (int) 3.14
as well as constant functions that ignore their arguments.
@@riccardoorlando2262 Right, yeah, good point. That's the definition, but the implications are the same with computer science (although simplified for nonpure functions). With something like a random number generator, even assuming a seed, it's not idempotent if it's called multiple times (and as the function takes no input value, it'd be the same as "random(random(random()))". I admit that random number generation may be a bad example as the same seed will produce the same sequence of values, and I guess you could argue whether the return value is each individual instance or the the entire set of random numbers produced by that seed. Idempotence gets a little weird when external state is thrown into the mix.
It seems that the computer science definition is a little looser than the mathematics definition: en.wikipedia.org/wiki/Idempotence#Computer_science_meaning.
41:14 actually in functional programming there's only data and evaluation, or rather expressions which can be reduced to a normal form (data), because functions are data too. An example of a not yet reduced expression is a redex (a lambda applied to a value) like `(\x -> x+1) 3` which reduces to a data, namely `4`
I think about the struggle the people who first claimed that the earth was round had to go through before the majority accepted it as a fact. Much like functional programmers do to day
One tiny ass box for the speaker, but oodles of logo space.
Bro, we need the short version of this here in the comments...
I have my doubts.
First, I haven't seen a reasonable example, in the speech, where there's more than the naked statement (i.e. not supported by any kind of reasoning or data) that OOP falls apart, i.e. that it's an unstable equilibrium.
Second, I expect a programmer able to write bad OO code will be even more capable of writing crappy functional code.
Third, no engineering profession today is simple. If you want to design cars, or ships, or power plants, or roads, or bridges, the engineering discipline you need to practice is a lot more rigorous and the systematic knowledge you need to acquire is more complex than what many software engineers do/know. Could _this_ be the reason we have a lot more failed projects to show than any other engineering discipline?
Fourth, I remember a statement appearing at the end of Martin Fowler's blog post about the LMAX architecture, in a footnote: "An interesting side-note. While the LMAX team shares much of the current interest in functional programming, they believe that the OO approach provides a better approach for this kind of problem. They've noticed that as they work to write faster code, they move away from a functional style towards OO style. Partly this because of the copying of data that functional styles require to maintain immutability. But it's also because objects provide a better model of a complex domain with a richer choice of data structures." This is no negligible concern, in code written for production, even when your system is smaller than what the LMAX developers did. For one, because latency, regardless of the scale of a system, is always a pain. Therefore, I wouldn't voluntarily rely on a paradigm which takes away most control from me, as a programmer, in large parts of a system - I'd see this as a risk too huge to take.
Fifth, I personally feel that a functional style is a lot less readable as documentation, especially as you start using higher order functions. With typical OO, code can be read much like a paper document. Indexing is easy, therefore you can easily use tools to navigate it. The way it executes maps pretty precisely to its static structure. Once you start using higher order functions in FP (without which, IMO, FP looses much of its appeal, becoming age-old structured programming from the times of plain C), this structure melts away. The consequence is that coming back to a codebase you haven't worked on in months is hard, getting someone up to speed with a functional codebase he has never seen before is even harder. In a professional setting, I think this is a significant drawback of FP.
I do use functional idioms myself, but only at the leafs, as an implementation detail, of my object-oriented code. Whenever I write code, I try to describe it to people who will work on it after me, instead of just making it work. I think I could do this equally well with a more, or even fully functional, idiom, regarding _what_ the code does, but I would not be able to give fellow programmers an as easy to use map through the code as I can do with an OO style.
Maybe I still have to learn a lot about FP, and my view on FP is skewed by not knowing enough about it. But at least for the time being, while I do see its merit in some regards, I don't think FP is a paradigm to embrace for fully coding large and complex projects. It's not that it's impossible, I just think it's less productive, in the long run, if you factor human aspects into the equation. To me, at my current knowledge level, it's just a tool in a toolbox, to be used when it's most useful without introducing more subtle and more costly problems than the code itself.
Florin Jurcovici well put, i agree pretty much 100%
yes, you are correct. i agree 👍
OOP doesn't fall apart if you follow best practices such as SOLID, DDD. It's just that when you do that (follow best practices), you find yourself program in FP style but with more verbosity.
I have to disagree. I recently changed job, came to huge legacy C# project. It's pretty standard, DI everywhere etc. Once you find the first EntityFactoryFactoryDecoratorFacade you are done without the debugger. Trying to find which one of the 5 subclasses trows NullReferenceException on a field in shared base class. Haven't worked with F# in commercial setting, but I don't really think it's worse. It may be not better, but I don't think it's worse. (I know it's bad code and bad practises, but they are there)
On the other hand, I fell into the reactive programming path, and C# is pretty much the best language to do that, especially with libraries like DynamicData and ReactiveUI. The ease of jumping back and fourth between Observables and tasks is great.
@@Qrzychu92 My understanding of your statement is that you blame OOP for the bad shape of the codebase, and assume that the same team(s) that developed that mess, at the same skill level, with the same history of the project, would have created a better structure using FP. How come? IMO it's much more reasonable to assume that programmers capable of creating a mess will maintain that capability regardless of the programming paradigm they use.
Hahah his joke was so good about anemic models and I couldn't hear a single laught
Isn't it the case that returning an IO monad in your function doesn't make it impure? I though impure function were ones that cause side-effects that aren't encoded in the type system: en.wikipedia.org/wiki/Pure_function#I/O_in_pure_functions
Alan Kay says that he wishes he had called it Message Oriented Programming because everybody focuses on the wrong aspects of the idea.
@@lepidoptera9337 It's not all about the name, but people will judge a book by its cover. The concept of the paradigm was about message passing more than objects/containers. Calling it object oriented causes people focus more on the objects rather than message passing.
Algorithms + Data Structures = Programs
Niklaus Wirth, 1976
I like it and agree, but there's not enough information here to make the case against OOP. I'm not saying he didn't say stuff about it, but imagine using his reasoning against an industry that's been doing OO for decades -- and they're been successful at it -- how do you teach them they should change -- only by showing real world pain-points, not "oh look, this is too much code to create a class".
The Wizard of Oz...
The explanations of the Haskell code are... not good at all.
John how much has been slurped at 27:25 the most import part.
CapacityChecker, what a weird class
Just implement hasCapacity(int) in Reserveration class and get rid of feature envy code smell and also have testable code
That's the point of the talk, Reservation it's a DTO, a object that only contains data, the CapacityChecker is a class/module with a specific function (a business logic) which also implements error handling (returning Success and Error objects), if you move the capacity handling code in the Reservation class it will be less testable and isolated because you will need to instantiate the Reservation class with all the context and data it requires in a test, to only test the capacity handler function/method.
It's basically changing the flow of the program of:
Reservation (a bloated class, with data and methods, business logic and calls data directly from DB)
to:
A module/function called CapacityChecker which receives two things: a Reservation (DTO) and a Service(for access of Database), then it deals with the logic and then returns the Success Object or Error of Reservation.
You are naturally doing dependency Inversion here making things decoupled.
And yep, you could add dependency inversion on the Reservation class but you are bloating the constructor and basically also doing DDD wrong because you are mixing a entity object with business rules (it's the same as the User with email sending function for example).
His explainations about DDD are just wrong. He sais, that Entites and Value-Objects cannot contain businesslogic and is put into those "services". But DDD is about the complete opposite. Acutally the "Part2"-Part of the Book only about the topic to tie data and behaviour together. I have the feeling that he did not read the book. Entites consist of Value-Objects. Also Entities are composed to Aggregates. An Aggregate has a global identity and is responsible for its consistency and owns its business logic. All businesslogic that fits to an Aggregate/Entity/ValueObject should go into this respective class. If an requirement does not fit into one of those entites/aggregates/value-objects or has a technical aspect to it (like repositories, who speak to DBs), the idea is to create a so called "domain-service", wich then implements this logic. But the goal is to reduce the amount of "services" and tie data and logic together, to hide and protect the data, since DDD is about processes and behaviour. This is probably not functional, since Entites and Aggregates can change over time, but keeping the functional ideas in mind by lowering the sideeffects to a minimum helped me a lot personally.
If you spent as much time studying and actually understanding what he's saying as you did criticizing, I'm sure you'd make a lot more progress.
@@gregoryshields4258 wow what a useless comment
@@gregoryshields4258 so I guess people shouldn't correct/criticise people, like, ever? Maybe you should do some study instead.
Test-driven language analysis
Great talk. A key concept is how side effects are approached differently:
Hexagonal Architecture: Allow your class to call side effects from your business logic when needed but use interfaces to inject different implementations.
Functional Programming (F#): Allow your business logic to run either purely (testing )or impurely (prod) passing functions that may or may not be impure.
Languages that support lambda expressions (Java, Kotlin, C#, etc) can use the same principle that F# FP is using. But it isn't as natural of course. Although, in my opinion, this would create far too many testing surfaces, more than needed.
A great talk on how to write Hexagonal Architecture (and how BDD is a perfect complement): ruclips.net/video/sOaS83Ir8Ck/видео.html
This got me interested: Hexagonal Architecture: Allow your class to call side effects from your business logic when needed but use interfaces to inject different implementations.
By Hexagonal Architecture you mean OOP languages?
And is this sentence your idea how it should be done in OOP - or is it some well known paradigm to use Interfaces for impure jobs?
I am just asking for little bit more context - I am not so experienced developer.
I've listened to good functional programming talks, this was not one of them. I'm pretty sure functional code can be done badly as well, so bringing up examples written by 8 year olds as something you can solve in functional is kinda dumb.
There are too many deliberate lies in this speech.
33:20 Let's define things correctly.
Encapsulation: "put data and methods in a bounded context".
Information hiding: "protect invariants" the domain must always be valid.
34:35 Now let's open "Patterns of Enterprise Application Architecture" about Active Record:
If your business logic is complex, you'll soon want to use your object's direct relationships, collections, inheritance, and so forth. These don't map easily onto Active Record, and adding them piecemeal gets very messy. Another argument against Active Record is the fact that it couples the object design to the database design. This makes it more difficult to refactor either design as a project goes forward.
As the speech said, these books have too many pages. But this is not a reason to stop at the table of contents.
Terribly bad, no matter how much I like Mark's articles on FP, every word about OOP in this speech is simply an ode to incompetence.
Uncle Bob's book is 536 p. not 700 p. 😜
And what language has a bad logo?)
Perl 6.
@@TheddunTOSS indeed :D
php?
26:33
* tells how cool is to draw an owl in haskell
* next slide
* owl is drawn cut in half with guts falling out mixed with cybernetic implants
* speaker doesn't give a f
Seriously, `hoistEither`, `runEitherT` (why not `runExceptT`?), `liftIO` and a `>>=` (plumbing operator) is not what the audience wants to see to get inspired to go functional right away.
Success mark my trading no earnig
The military sheet lamentably knock because cellar similarly obey circa a nondescript susan. rich, bashful package
My thoughts exactly
The entertaining control inspiringly dream because advice ectrodactyly excuse apropos a scarce size. overt, groovy report
Seemann Surprise!
PlZ hlp me trading
You're gonna wanna 1.25X speed this one, a bit painfully slow. Way too much blathering
I almost fell asleep watching it at 2.5x
21:40
its still pure!
sure db changes.. so wut?
It means that it is not idempotent, so it is not pure.
With the same input you will always have the same output, if not it's impure :D
IO is *not* impure.
That's an imperative-programming perspective which is fundamentally unhelpful for the act of *designing* software systems (which is the thing we programmers are, theoretically *actually paid* to do).
IO as a concept is impure, because it has state. Sure, you can pass around an IO effect, which doesn't make the function impure, but whenever you try to materialise the IO you get stateful behaviour.
IO is a conversation consisting of continuously novel and unknown data; therefore, it is impure.
Your second statement I couldn't make any sense of, but I would suggest that you just need to study up more on the-very simple-philosophy of what functional programming is.
It is pure as long as you don't run it. You can think of IO values as imperative recipes (or code) which you can pass around as value, but at the end of the day you will compile your code and run an IO recipe, which is of course impure
So the speaker critizise a class in OOP for being writen in a complicated way to be testable and at the same time he says that we must forget 20 years of OOP just to write functions thar are more testable? My God.
The talk was not just about testability. You can program in OOP using best practices (SOLID, DDD, etc) or you can just program in FP.
@@linhe6729 So I can just make all of my functions inpure that my code will be good? No need for best practices in fp?
@@DaniloSouzaMoraes Hi, the point I was trying to make is that if I apply SOLID principle to my OOP code, I'd find myself writing FP code, but with more boilerplate code.
blog.ploeh.dk/2014/03/10/solid-the-next-step-is-functional/
@@DaniloSouzaMoraes in Haskell you can not write inpure functions for instance.
idk how one can achieve that in Ocaml/F#/Clojure, but at least FP programmers are aware of side-effects and them being bad. Java/C# programmers write inpure functions all the time
@@linhe6729 You find yourself writing FP code that follows the SOLID principles, yes. You still need those principles when writing FP, though. To break the S just imagine all your pure functions written as a single function, without composition.
To break the D, just imagine yourself modeling a system starting from the database access functions. Those are inpure. Then you add functions that compose those and so on. Youll endup with a totally inpure system.
The FP paradigm doesn't grant code quality on its own.
Also, just like Single Responsability Principle leads to a functional style of design, Opaque Types in FP lead to OOP style of design. That duality is everywhere.
What that bs