A lot of these types of books and posts only deal with the low hanging fruits of software design difficulty, such as the provided discount service example.
The trouble is that kind of thing's pretty much software development common sense - only the inexperienced don't know it.
The true difficulties of software development are often must gnarlier in my experience.
For instance, making architectural choices for large and dynamic software systems, such as say a cutting edge game engine - that can be really hard to get right, and there's not always a lot of sage advice out there for how to navigate it - and not just for game engines but for any equally or more complex software.
I guess my point being - I'd love to see more effort into addressing the hard design stuff, and less repetition of what's already been established.
I come from an FP background, and this book was interesting to me as the author very clearly has a very different (imperative, systems) background. In some cases we have very different opinions, in some cases I'm completely agreed (e.g. "define errors out of existence" is extremely common in FP, usually under the term "make illegal states unrepresentable"), and in other cases I feel they were half-way to FP but couldn't quite get all the way there (e.g. the editor example is a classic interpreter, but they didn't make the connection IIRC.) I only skimmed the book and would like to go back for a more detailed review. Curious if anyone else with an FP background had the same or different experience.
"Define errors out of existence" might sound like "make illegal states unrepresentable," it's actually not. Instead it's a pastiche of ideas rather foreign to most FP readers, such as broadening the space of valid inputs of a function. One of his examples is changing the substr function to accept out of bounds ranges.
You might be interested in my review. I'm a Haskeller at heart, although the review draws more from my formal methods background. Spoiler: his main example of a deep module is actually shallow.
Does Ousterhout actually say modules must always have a longer implementation than their spec, or just that this is a generally desirable feature?
If he did, I agree with you, he was wrong about that. I also agree that the unix file API is probably not a good example.
But whether or not he did, I think the dissection of edge cases would be better off emphasizing that he's got something importantly right that goes against the typical "small modules" dogma. All else being equal, deeper modules are good--making too many overly small modules creates excessive integration points and reduces the advantages of modularity.
P.S. While I'm here, this is not really in response to the parent post, but the example in the article really does not do justice to Ousterhout's idea. While he does advocate sometimes just inlining code and criticizes the pervasive idea that you should shorten any method of more than n lines, the idea of deep modules involves more than just inlinining code.
> Does Ousterhout actually say modules must always have a longer implementation than their spec, or just that this is a generally desirable feature?
I mean the spec is a lower bound on the size of the solution, right? Because if the solution were shorter than the spec, you could just use the solution as the new shorter spec.
Not necessarily. The implementation is very often more defined than the specific. If the implementation is the spec, then it means that even the smallest change in behavior may break callers.
Your review is great! But I think the idea that it’s in opposition to PoSD is not right, I think it’s a further development and elaboration in the same direction of PoSD
I read most of the book a couple years ago, and I thought it was very good. I wonder if you (or anyone else) can recommend an alternative book that does a better job of describing your perspective?
I thought the book was stupid. Rehashed a bunch of obvious ideas. It’s a bit harsh, I know, but that’s my honest opinion and I respect other people who like his book.
I too have a fp background and I felt the author is unqualified to talk about complexity without knowing fp. Elimination of procedures and mutations is a formal and concrete reduction of complexity while the authors definition of complexity is hand wavy. Someone should know about what fp is before writing a book like this.
Why? Because fp is a basically like a formal structure for software design and the author tried to talk about philosophy without knowing some hard formal rules that are well known in the industry. Not saying these rules are absolute but you can’t talk about design without talking about this.
The book talks about modularity and things of that nature too and totally skips out on understanding the separation between statefulness and logic. The author completely misses this design concept of how how IO and mutation should be separated from declarative operations. Imperative shell/functional core is a central design philosophy that he doesn’t touch upon. The book is woefully incomplete without talking about this. Whether the authors philosophy aligns with it is open for debate but you can’t talk about what he talks about without mentioning this in a big way.
> Someone should know about what fp is before writing a book like this.
1. Are you quite sure John Ousterhout (who invented Tcl[1], comparing it to Lisp in section 7 of the original paper) doesn't "know about what fp is" as you say?
2. Do you think that the main reason functional programming hasn't taken off in systems programming is that practitioners are ignorant, or do you think there might be issues with fp systems that prevent its adoption?
Sure, fp in Lisp might not always be true (scotsman) fp. ;-)
But omitting fp in the book is not evidence that Ousterhout is ignorant of fp, and there is certainly evidence to the contrary.
The likely explanation, given that he's developed a number of systems from Sprite to Tcl/Tk to RAMCloud to HOMA, is that he is addressing the current practice of systems programming, which remains primarily imperative.
FP weenies gone wild 2024. You design web apps with monads. Ousterhout has made systems of actual consequence where mutation is a reality not a fantasy you try to pretend doesn’t exist.
The book plainly states that it is a philosophy for software design. Philosophy in this context is closely related to strategy, which is the art of reducing reality to heuristics, so that we might easier figure out how to reach our goals in a complex environment.
If the book had been titled "Formal methods for software design" the lack of algorithms for reducing complexity would have been surprising. As it is about philosophy it should not be surprising that it focuses on heuristics.
Applying formal methods derived from functional programming is a design heuristic.
It’s a core heuristic and philosophy that is foundational in my opinion. The author failing to mention this makes the book missing a fundamental issue central to software design.
Well put. This comment makes your criticism of the book much more clear to me at least.
I agree with you that the separation of Church and state is a foundational idea of software design and even computing generally. I find it quite beautiful how it manifests in hardware as the two categories of digital logic - combinatorial and sequential. And if we zoom in on the logical expression of memory we see it again - a latch is simply two feedback loops and some combinational logic.
For what it's worth I thought the book was brilliant. Its ideas weren't all obvious to me before I read it. It also inspired me to read Parnas, Wirth, Hoare, and study the Go runtime and compiler.
What should be obvious is this: the fact that the ideas were obvious to you doesn't mean they are obvious to everyone.
Secondly, complexity has many meanings. Managing complexity is incredibly important in the realm of security. I've been dabbling in security for 25 years, but I would certainly not claim to have a deep understanding of functional programming. Nevertheless I understand complexity quite well. I think that's what bothered me the most about your original comment - the idea that people without a background in FP are unqualified to talk about complexity.
I too write FP code but I found this book very valuable in how he treats complexity and his concept of "deep modules".
I acknowledge that he does not cover purity and mutations as a source of complexity (and they are big sources of complexity) but I don't think that merits dismissing the entire book on those grounds.
If this is so stupid and obvious, why does apparently 99.99% of software designed by professional engineers seem to be designed by people completely oblivious to these ideas and considerations?
Following these philosophical principles themselves- it seems like a simpler and more accessible treatment of these ideas would be vastly more effective then a more rigorous and complete one- because the ideas are indeed simple.
> If this is so stupid and obvious, why does apparently 99.99% of software designed by professional engineers seem to be designed by people completely oblivious to these ideas and considerations?
It’s similar to why a big portion of the world believes in Christianity and another portion believes in Buddhism. Basically only one or none of these religions is correct rendering at least one population of people believing in a completely made up fantasy concept.
Much of what is preached in software is religion and what is preached by the majority can be completely ludicrous. The majority believing or not knowing something doesn’t mean anything.
> It’s similar to why a big portion of the world believes in Christianity and another portion believes in Buddhism. Basically only one or none of these religions is correct rendering at least one population of people believing in a completely made up fantasy concept.
You have picked religions with as little as possible in common. It would be rather different if you had picked any two monotheistic religions for example: one could be entirely right, and that would mean the other was partially or mostly right.. Despite your choice, there are many things in common: a path to redemption, monasticism, wealth being a barrier to redemption, meditation and mysticism... its quite possible those common elements might be right.
The same with software. Some things that are widely believed may be true and other false.
Religious “truths” are not factual truths- they are better thought of as psychological technology or techniques, and are “true” if they work for the intended purpose. Many conflicting religious “truths” are all “true.” Even calling them truths is only done to make the religions accessible to people that can’t mentally process nuance, and the techniques only work for them if labeled as truth. Intelligent religious scholars understand this well- for example Mahayana and Vajrayana Buddhism both teach nearly opposite and factually incompatible perspectives on almost everything, yet are often both used by the same religious teachers for different pupils as appropriate.
The same is true for software design- an approach is not literally true or false, but either works for its intended purpose or does not. Conflicting philosophies can both be “true” just with different underlying goals or values.
To circle back here, my point is that this information is presented in a simple way that will let people reading it design better software. Saying they have no right to present it without a much less accessible and more complex framework that would likely make it less useful to the intended audience does not make sense to me.
FWIW, I am also a functional programmer, but would love to see people that are not follow some of these ideas.
1 Corinthians 15:13-19 (NIV) : “ If there is no resurrection of the dead, then not even Christ has been raised. And if Christ has not been raised, our preaching is useless and so is your faith. More than that, we are then found to be false witnesses about God, for we have testified about God that he raised Christ from the dead. But he did not raise him if in fact the dead are not raised. For if the dead are not raised, then Christ has not been raised either. And if Christ has not been raised, your faith is futile; you are still in your sins. Then those also who have fallen asleep in Christ are lost. If only for this life we have hope in Christ, we are of all people most to be pitied.”
——
There is only one kind of truth. “All truths are God’s truths.”
If Christianity is not true, then it is false. If Christianity and Buddhism strictly contradict each-other, then at most one of them is true.
Christianity is not meant to be a, what, psychological trick? It makes claims, and these claims should be believed if true and disbelieved if false.
It's no trick, it's a spiritual path that can't be understood without following and practicing it- the path very much leads to something real that cannot be experienced or explained any other way. Everything Christianity teaches is true in the sense that I mean here. You are not understanding what I am saying and I do not personally know how to explain it more clearly[1], which, as I explained above, is why religions pragmatically also offer this view you hold as the official explanation to lay people, despite being obvious nonsense as an objective truth to anyone that thinks very hard about it.
I posit almost all intelligent monastics and religious people are smart enough to tell the difference between objective truth and religious truth- but it is taboo to explain this to lay people as they will be confused and think it means the religion is "fake" or a "trick", however I don't feel the need to respect said taboo. Perhaps I will learn to respect it by trying to explain it to people unsuccessfully.
> I posit almost all intelligent monastics and religious people are smart enough to tell the difference between objective truth and religious truth- but it is taboo to explain this to lay people as they will be confused and think it means the religion is "fake" or a "trick", however I don't feel the need to respect said taboo.
That is positing a conspiracy theory level of deception.
At least as far as Christianity goes, the "intelligent monastics and religious people" write down their beliefs, and have done so for millennia, and they read each others writings. What you suggest might be possible with an oral tradition, but not with a written one. Christianity is very much concerned with objective truth, and one of the distinguishing characters of it (and some other religions too) is a belief that there is an objective truth.
It's no great conspiracy for a religion to have tiers of understanding and nuance reserved for people more intelligent and dedicated in practice- that is one key purpose of having a distinction between lay people and monastics. The mystique of this is openly part of the draw for people to sign up for it.
There's no deception- it's something that (as this discussion shows) is very subtle and dangerous to the religions when misunderstood- but not dangerous when understood correctly. It is written down repeatedly in religious texts, in a subtle way with plausible deniability, but clear to those that can read between the lines. Writing in that way was the essential basic art of any intellectual until very recently, it is only now (sort of) safe to plainly state nuanced philosophical and religious concepts without facing persecution. Nietzsche argued you still should not do so even if you can.
It's also both quite obvious and relatively unimportant on its own to people that would be capable of understanding nuance, and could be quite harmful to the faith and the stability of the religion of those not able to understand.
I'm not a scholar of Christian literature (or a Christian), and I don't speak Latin, so it would hardly be appropriate for me to pull out a specific quote and insist "this is what they really meant." In truth, my original source for this was my own understanding being raised in a Christian church- and voicing this perspective out loud in church as a young kid didn't go over well, as you might imagine. To me as a young kid, it was immediately obvious that there were deeper ethical principles being explained in these stories, and one had to be an idiot to be worried about if they were objective factual details or not, when the point was clearly to understand and embody the message- to practice and live it. One was called to have faith that living these principles wholeheartedly was the right thing to do and would lead to real spiritual growth, not to have faith that some particular guy built a particular boat- such things are irrelevant.
However St. Augustine is someone that I am particularly certain had a clear understanding of this, and I can see it in how he frames most of his ideas.
Another example, would be that ancient religious texts are not careful at all to avoid making numerous objectively factual contradictions- as the anti-christian crowd loves to point out over and over while also completely missing the point. If the people writing them thought that was important, they would have avoided doing so- contrary to modern opinion, ancient theologians and philosophers like St. Augustine were not idiots.
William Blake is a more modern person that, while just about the furthest thing from a monastic, clearly had a deep understanding of what I am talking about. Carl Jung also extensively understood and discussed a lot of esoteric things in Christianity including this, and wrote about them in a relatively clear modern way.
Good explanation, really. Imperative systems programmers reject one or more of the fp commandments (perhaps finding them impractical), and are probably heretics in the eyes of the fp cult.
Can’t because fp is in itself basically a design philosophy that can be explained in 3 axioms.
Segregate mutation from logic
Segregate IO from logic
Eliminate procedures from logic.
The third axiom is sort of for free as it falls out automatically when someone enforces the first two. That’s basically imperative shell/functional core design philosophy which is basically identical to the rules of pure functional programming.
With fp you can think of these rules enforced as a language. Outside of fp we call it functional core / imperative shell and these rules can be enforced in an imperative language as a core design philosophy.
I also found this useful. I'm not a software developer, but use programming for problem solving and prototyping. Still, things that "look like software" sometimes leak out of my lab. FP always set off my BS alarm, because in my simplistic view, the whole world has state. But even for my crude work, a sort of "separation of powers" helps clean up my programs a lot, and code that doesn't need to have side effects can be a lot cleaner if it's not mixed with code that does.
FP does not deny state, it merely segregate it between the before and the after, and everything that is in between is transient. Then you combine all the individual functions, piping them into each other and the whole reflect the same structure. Then, it becomes easier to reason about your logic as you only have two worry about 2 states: the input and the result. No need to care about individual transformations and ordering like you do in imperative.
Thank you. I found this comment illuminating. I too am very interested to hear any book recommendations you have on the topic.
What are your favorite books on software design, functional programming, and/or computing generally? What are your favorite papers on the topic of complexity (as FP defines it)?
"Domain Modeling Made Functional" is a great read and sits next to a lot of these topics. Very easy to follow and learn from even if you don't know (and never intend to use) the language.
I would like to echo the user kfreds sibling comment. I don't have a FP background either and hence would very much like to hear your recommendations on books/videos/articles to understand FP and design the "FP way".
Something bugs me about that first example. We started with two classes that had trivial constructors, and changed them into classes that require an instance of DiscountService be supplied to a constructor. That doesn't feel like less complexity to me.
I'd probably just make applyDiscount a static utility method that the two classes import and invoke on their own, at least until it becomes obvious that something more involved is needed.
Yes, and also it’s weird to get a negative shipping cost (-5) for US and code SUMMER2024. Typically you would only apply the discount code once and not both to shipping and the total order value.
It’s a great book. I feel like a lot of the midlevel engineers I’ve worked with over the years who read clean code and stopped there would benefit greatly from it.
Sadly article's author doesn't touch the main idea of the book: component's public API should be narrow as possible. John makes a great deal of that with concrete examples.
> make a lot of small tiny methods which are one liners or two liners.
I'm presuming you mean public tiny methods? Having private ones like that can be good if makes sense to do so (encapsulates logic, increases readability, etc)
“The idea behind exception aggregation is to handle many exceptions with a single piece of code; rather than writing distinct handlers for many individual exceptions, handle them all in one place with a single handler.”
This seems similar to how events are handled in a web-browser. Each element can handle its own event-handlers. But equally well there can be a single event-handler for each event-type in a containing element, perhaps at the top-level only.
If you define event-handlers of a given type for all DOM-elements of the page in a single location it becomes much more flexible to modify how and which events are handled and for which DOM-elements.
So we could say that "error" is just one of the event-types, errors can be or could be handled by the same mechanism as events in general are. Right? Or is there clear categorical difference between error-events and other types of events?
I read this book recently, one chapter at a time, and after each, reviewed the code for my current project, applying the principles to it in a re-write --- it helped a lot.
While I heartily agree with limiting complexity as a ground rule, the example given is not a great one.
First, it’s more about repetition/poor design than complexity. Second, creating a separate service class for applying a discount is adding unnecessary complexity. You’ll end up with a pile of DiscountService, TaxService, ShippingCostsService, and so on, and they will be sewn together like patchwork. It seems to be a common pattern in Java but surely there are better ways?
I disagree with the examples in the second idea. The "bad" example is easier to understand and maintain at a glance in my opinion. Looking at the RegisterUser method, I can immediately see the steps it takes to register a user, whereas the "good" example I have to think about it a bit more. Of course, this is a simple example so not much thinking needs to be done, but in a more realistic application I think this would hold much more truth. In projects I've worked on I've seen methods get incredibly bloated due to this. I certainly do agree that "splitting things up for the sake of splitting them up" can be bad practice, I'm just not sure this is the best example to demonstrate that.
I agree. The main function of a component should describe what it does, similar to describing the algorithm in natural language. I have been following this pattern with success. It is much easier to understand things at a glance.
The trouble is that kind of thing's pretty much software development common sense - only the inexperienced don't know it.
The true difficulties of software development are often must gnarlier in my experience.
For instance, making architectural choices for large and dynamic software systems, such as say a cutting edge game engine - that can be really hard to get right, and there's not always a lot of sage advice out there for how to navigate it - and not just for game engines but for any equally or more complex software.
I guess my point being - I'd love to see more effort into addressing the hard design stuff, and less repetition of what's already been established.
You might be interested in my review. I'm a Haskeller at heart, although the review draws more from my formal methods background. Spoiler: his main example of a deep module is actually shallow.
https://www.pathsensitive.com/2018/10/book-review-philosophy...
If he did, I agree with you, he was wrong about that. I also agree that the unix file API is probably not a good example.
But whether or not he did, I think the dissection of edge cases would be better off emphasizing that he's got something importantly right that goes against the typical "small modules" dogma. All else being equal, deeper modules are good--making too many overly small modules creates excessive integration points and reduces the advantages of modularity.
P.S. While I'm here, this is not really in response to the parent post, but the example in the article really does not do justice to Ousterhout's idea. While he does advocate sometimes just inlining code and criticizes the pervasive idea that you should shorten any method of more than n lines, the idea of deep modules involves more than just inlinining code.
I agree that blindly making lots of tiny things is bad, but his criteria for how to chunk modules is flawed.
I mean the spec is a lower bound on the size of the solution, right? Because if the solution were shorter than the spec, you could just use the solution as the new shorter spec.
Defining errors out of existence should be mandatory for all golang programs.
I too have a fp background and I felt the author is unqualified to talk about complexity without knowing fp. Elimination of procedures and mutations is a formal and concrete reduction of complexity while the authors definition of complexity is hand wavy. Someone should know about what fp is before writing a book like this.
Why? Because fp is a basically like a formal structure for software design and the author tried to talk about philosophy without knowing some hard formal rules that are well known in the industry. Not saying these rules are absolute but you can’t talk about design without talking about this.
The book talks about modularity and things of that nature too and totally skips out on understanding the separation between statefulness and logic. The author completely misses this design concept of how how IO and mutation should be separated from declarative operations. Imperative shell/functional core is a central design philosophy that he doesn’t touch upon. The book is woefully incomplete without talking about this. Whether the authors philosophy aligns with it is open for debate but you can’t talk about what he talks about without mentioning this in a big way.
1. Are you quite sure John Ousterhout (who invented Tcl[1], comparing it to Lisp in section 7 of the original paper) doesn't "know about what fp is" as you say?
2. Do you think that the main reason functional programming hasn't taken off in systems programming is that practitioners are ignorant, or do you think there might be issues with fp systems that prevent its adoption?
[1] https://web.stanford.edu/~ouster/cgi-bin/papers/tcl-usenix.p...
Fp with lisp is only a fraction of fp. I of course am talking more along the lines of pure fp which lisp is not.
But omitting fp in the book is not evidence that Ousterhout is ignorant of fp, and there is certainly evidence to the contrary.
The likely explanation, given that he's developed a number of systems from Sprite to Tcl/Tk to RAMCloud to HOMA, is that he is addressing the current practice of systems programming, which remains primarily imperative.
If the book had been titled "Formal methods for software design" the lack of algorithms for reducing complexity would have been surprising. As it is about philosophy it should not be surprising that it focuses on heuristics.
It’s a core heuristic and philosophy that is foundational in my opinion. The author failing to mention this makes the book missing a fundamental issue central to software design.
I agree with you that the separation of Church and state is a foundational idea of software design and even computing generally. I find it quite beautiful how it manifests in hardware as the two categories of digital logic - combinatorial and sequential. And if we zoom in on the logical expression of memory we see it again - a latch is simply two feedback loops and some combinational logic.
For what it's worth I thought the book was brilliant. Its ideas weren't all obvious to me before I read it. It also inspired me to read Parnas, Wirth, Hoare, and study the Go runtime and compiler.
What should be obvious is this: the fact that the ideas were obvious to you doesn't mean they are obvious to everyone.
Secondly, complexity has many meanings. Managing complexity is incredibly important in the realm of security. I've been dabbling in security for 25 years, but I would certainly not claim to have a deep understanding of functional programming. Nevertheless I understand complexity quite well. I think that's what bothered me the most about your original comment - the idea that people without a background in FP are unqualified to talk about complexity.
I acknowledge that he does not cover purity and mutations as a source of complexity (and they are big sources of complexity) but I don't think that merits dismissing the entire book on those grounds.
Because it misses these concepts the book isn’t good in my opinion.
Following these philosophical principles themselves- it seems like a simpler and more accessible treatment of these ideas would be vastly more effective then a more rigorous and complete one- because the ideas are indeed simple.
It’s similar to why a big portion of the world believes in Christianity and another portion believes in Buddhism. Basically only one or none of these religions is correct rendering at least one population of people believing in a completely made up fantasy concept.
Much of what is preached in software is religion and what is preached by the majority can be completely ludicrous. The majority believing or not knowing something doesn’t mean anything.
You have picked religions with as little as possible in common. It would be rather different if you had picked any two monotheistic religions for example: one could be entirely right, and that would mean the other was partially or mostly right.. Despite your choice, there are many things in common: a path to redemption, monasticism, wealth being a barrier to redemption, meditation and mysticism... its quite possible those common elements might be right.
The same with software. Some things that are widely believed may be true and other false.
The same is true for software design- an approach is not literally true or false, but either works for its intended purpose or does not. Conflicting philosophies can both be “true” just with different underlying goals or values.
To circle back here, my point is that this information is presented in a simple way that will let people reading it design better software. Saying they have no right to present it without a much less accessible and more complex framework that would likely make it less useful to the intended audience does not make sense to me.
FWIW, I am also a functional programmer, but would love to see people that are not follow some of these ideas.
——
There is only one kind of truth. “All truths are God’s truths.”
If Christianity is not true, then it is false. If Christianity and Buddhism strictly contradict each-other, then at most one of them is true.
Christianity is not meant to be a, what, psychological trick? It makes claims, and these claims should be believed if true and disbelieved if false.
I posit almost all intelligent monastics and religious people are smart enough to tell the difference between objective truth and religious truth- but it is taboo to explain this to lay people as they will be confused and think it means the religion is "fake" or a "trick", however I don't feel the need to respect said taboo. Perhaps I will learn to respect it by trying to explain it to people unsuccessfully.
[1] David Chapman may be able to: https://vividness.live/visionary-and-objective-truths
That is positing a conspiracy theory level of deception.
At least as far as Christianity goes, the "intelligent monastics and religious people" write down their beliefs, and have done so for millennia, and they read each others writings. What you suggest might be possible with an oral tradition, but not with a written one. Christianity is very much concerned with objective truth, and one of the distinguishing characters of it (and some other religions too) is a belief that there is an objective truth.
There's no deception- it's something that (as this discussion shows) is very subtle and dangerous to the religions when misunderstood- but not dangerous when understood correctly. It is written down repeatedly in religious texts, in a subtle way with plausible deniability, but clear to those that can read between the lines. Writing in that way was the essential basic art of any intellectual until very recently, it is only now (sort of) safe to plainly state nuanced philosophical and religious concepts without facing persecution. Nietzsche argued you still should not do so even if you can.
It's also both quite obvious and relatively unimportant on its own to people that would be capable of understanding nuance, and could be quite harmful to the faith and the stability of the religion of those not able to understand.
Can you give me an example of what you mean? From Christianity, as its the religion I know most about.
However St. Augustine is someone that I am particularly certain had a clear understanding of this, and I can see it in how he frames most of his ideas.
Another example, would be that ancient religious texts are not careful at all to avoid making numerous objectively factual contradictions- as the anti-christian crowd loves to point out over and over while also completely missing the point. If the people writing them thought that was important, they would have avoided doing so- contrary to modern opinion, ancient theologians and philosophers like St. Augustine were not idiots.
William Blake is a more modern person that, while just about the furthest thing from a monastic, clearly had a deep understanding of what I am talking about. Carl Jung also extensively understood and discussed a lot of esoteric things in Christianity including this, and wrote about them in a relatively clear modern way.
Segregate mutation from logic
Segregate IO from logic
Eliminate procedures from logic.
The third axiom is sort of for free as it falls out automatically when someone enforces the first two. That’s basically imperative shell/functional core design philosophy which is basically identical to the rules of pure functional programming.
https://medium.com/ssense-tech/a-look-at-the-functional-core...
With fp you can think of these rules enforced as a language. Outside of fp we call it functional core / imperative shell and these rules can be enforced in an imperative language as a core design philosophy.
What are your favorite books on software design, functional programming, and/or computing generally? What are your favorite papers on the topic of complexity (as FP defines it)?
I'd probably just make applyDiscount a static utility method that the two classes import and invoke on their own, at least until it becomes obvious that something more involved is needed.
For example in Ruby land it is very common to make a class and then make a lot of small tiny methods which are one liners or two liners.
I had asked him directly about this and his answer was to avoid doing it.
Since then my Ruby and Common Lisp code has become much better.
I have since moved to rust, but the point still applies.
I'm presuming you mean public tiny methods? Having private ones like that can be good if makes sense to do so (encapsulates logic, increases readability, etc)
It is after all an API for you!
Basically the idea that you shouldn't have long methods is something I don't believe in anymore. Even Carmack made a similar point: http://number-none.com/blow/blog/programming/2014/09/26/carm...
This seems similar to how events are handled in a web-browser. Each element can handle its own event-handlers. But equally well there can be a single event-handler for each event-type in a containing element, perhaps at the top-level only.
If you define event-handlers of a given type for all DOM-elements of the page in a single location it becomes much more flexible to modify how and which events are handled and for which DOM-elements.
So we could say that "error" is just one of the event-types, errors can be or could be handled by the same mechanism as events in general are. Right? Or is there clear categorical difference between error-events and other types of events?
I read this book recently, one chapter at a time, and after each, reviewed the code for my current project, applying the principles to it in a re-write --- it helped a lot.
Highly recommended.
First, it’s more about repetition/poor design than complexity. Second, creating a separate service class for applying a discount is adding unnecessary complexity. You’ll end up with a pile of DiscountService, TaxService, ShippingCostsService, and so on, and they will be sewn together like patchwork. It seems to be a common pattern in Java but surely there are better ways?
This book, as well as the data oriented design approach, is what made things right for me.
My screen recording: https://streamable.com/gvz68h