HN Theater @HNTheaterMonth

The best talks and videos of Hacker News.

Hacker News Comments on
Functional architecture - The pits of success - Mark Seemann

NDC Conferences · Youtube · 4 HN points · 8 HN comments
HN Theater has aggregated all Hacker News stories and comments that mention NDC Conferences's video "Functional architecture - The pits of success - Mark Seemann".
Youtube Summary
Object-oriented architects and developers have, over the years, learned many hard lessons about successfully designing systems with object-oriented programming. This has led to a plethora of ‘best practices’ that are painfully passed on from older to younger generations via books, lectures, consulting, blog posts, etc.
Many of these ‘best practices’ must be explicitly taught, because they don’t evolve naturally from object-oriented programming. Surprisingly, many of these hard-won ‘best practices’ fall naturally into place when applying functional programming. Instead of deliberate design, functional programming forms pits of success where you naturally fall into the same ‘best practices’ that you have to deliberately work for in object-oriented programming. In this session, you’ll learn about a handful of such ‘best practices’, and how functional programming automatically lead you there, without your explicit effort.



NDC Conferences
https://ndcsydney.com
https://ndcconferences.com
HN Theater Rankings

Hacker News Stories and Comments

All the comments and stories posted to Hacker News that reference this video.
Dec 16, 2021 · kirse on F# Good and Bad
Mark Seemann has a good talk on this called the "functional pits of success" -> https://www.youtube.com/watch?v=US8QG9I1XW0

Of all the languages I've used nothing is quite as fun as refactoring an F# app down to nothing. Expressive power is king in F# with the whole .NET ecosystem behind it.

dsizzle
Does refactoring down to nothing in F# make you a better programmer in other languages? That sounds like you just like programming in F#.
verinus
I quite like Mark's way of thinking and stumbled upon his blog several years ago while learning FP with F#. [1]

Especially the series about category theory...

Can also recommend his recently published book "Code that fits in your head".

[1] https://blog.ploeh.dk/

edit: typo

Akronymus
If you like his blog, you surely are gonna enjoy wlashins blog as well. (Making the BIG assumption you don't know it already)

It is THE blog that made me grok a lot of FP.

https://fsharpforfunandprofit.com/

verinus
Ah yes- superb content on FP/F#! He helped me a long way to understand FP- thanks for mentioning it, I can definitely recommend it to anyone who wants to get into FP / F#!
Yeah, me too. They published quite a lot of papers using it [0]. The datalog integration is pretty nice too, haven't gotten to learning Prolog yet, but seeing how concise a sudoku solver can be implemented in it was an experience.

(edit) you can import Java, Kotlin and Scala in it too, those are automatically Impure. Would enable purely functional architecture [1] and falling into the "Pit of success" [2].

[0] https://flix.dev/research/ [1] https://blog.ploeh.dk/2016/03/18/functional-architecture-is-... [2] https://www.youtube.com/watch?v=US8QG9I1XW0

His videos about functional programming are amazing (Mark Seemann). "Pit of success" is one of the best.

https://youtu.be/US8QG9I1XW0

Jan 24, 2021 · 2 points, 0 comments · submitted by scns
> So while FP is just another tool, it's also a framework for thinking that helps people make better choices

I’ve been getting more into functional programming this past year (via Clojure, though my day-job is mostly JavaScript/TypeScript) and this is the big takeaway for me.

Type theory and monads may have their place, but thinking about separating logic from side-effects is, I think, the most valuable aspect of functional programming.

That is a thought process that you can apply in pretty much any language that will give you the biggest bang for your buck.

Edit: Here’s some great examples of the benefits of functional thinking without going off the deep end.

1. Boundaries by Gary Bernhardt - https://www.destroyallsoftware.com/talks/boundaries

2. Pits of Success by Mark Seemann - https://youtu.be/US8QG9I1XW0

3. Grokking Simplicity by Eric Normand - https://grokkingsimplicity.com/

pdimitar
Yep, there also exists such a thing as "I learned language X and will not use it for my paid work but it made me a better programmer". One such example for me is Racket.
busterarm
Free Pascal.

That said, I'll use anything in my paid work if the project is interesting enough. Hence the three years I spent writing PHP.

pseudalopex
I'm curious. How did Free Pascal make you a better programmer?
busterarm
Not an answer you'll like, honestly. Turbo Pascal as the first thing I learned after BASIC as a wee youngin'. Mostly it was about connecting young hobbiest programmer me with seasoned professional me.

Basically, sometime's it's good just to kick back and have some fun with your work. Aside from that though, my impressions of the language are that it forces you to be a little bit more organized about everything than C-derived languages. In Pascal, the things that you do to satisfy the compiler are things you can do for anyone reading your code in other languages (not that you would in those languages conventions though...). And other languages do this even better... I wouldn't recommend anyone go learn it unless they had a real business need to.

pseudalopex
Thanks!
tcbasche
For me that's been Elixir. It's made me appreciate some of the more functional aspects in Python, like generators, map, filter and the functools library in general.
pdimitar
Ironically Elixir has become a personal favourite and I find it amazing for backend web work, especially API gateways -- although it does very well with server-side rendering web projects as well. It's my main work tool (very close second is Rust).

But I fully get what you mean. Working with it and learning it has been a very strong eye-opening experience.

tcbasche
I really enjoy the tooling as well. I feel like these days tooling can be just as important as the more “tangible” benefits of a language. The Phoenix code (and test!) generation in particular is just magnificent, not to mention docs. Pythons most lauded doc generation tool Sphinx on the other hand is just complicated and confusing.
alisonatwork
I agree that separating logic from side-effects is an excellent lesson that easily translates to less functional programming languages.

Another thing I tend to do now is order function arguments as if the programming language had partial function application. You can see this in JavaScript by comparing lodash to lodash/fp. I think once this practice is established on a team, it can help bring a more uniform feel to the code.

Kwantuum
In javascript it's pretty easy to write a function for partial application in either order, you can curry functions forward or backward.

    const map = (arr, mapper) => arr.map(mapper); // Non "traditional" order for arguments
    const curry = f => (...first) => (...second) => f(...first, ...second); // Classic currying: partially apply arguments to the start
    const reverseCurry = f => (...second) => (...first) => f(...first, ...second); // You might want to reverse() first and second depending on the desired syntax
    const arrayMapper = curry(map)(array); // Usually not that useful, more common to map over many arrays with the same function than to map over the same array with many functions
    const funcMapper = reverseCurry(map)(func); // Same benefits as having the classic argument order in the first place
If you're working in a code base that doesn't already implement "most specific argument last", or does so inconsistently, it's very easy to write partial application functions for both cases. If your functions aren't variadic you can even get over the clunky double call syntax by checking the total number of arguments passed thus far, and if it's greater than or equal to the function's "length" (the number of named arguments that it takes) call it, otherwise return the partially applied function, something that is sometimes known as "autocurry".
good default behavior and how it nudges programmers to favor predictable and composable solutions

Agree. Mark Seeman calls these the "Functional pits of success"

https://www.youtube.com/watch?v=US8QG9I1XW0

I think the toughest thing about F# is that it doesn't offer as many Google-able easy solutions, so I'm stuck using it for utility and client libs at work. Trying to get a whole team onboard is a non-starter. It takes a good 6-12 months to adjust the mindset and most people are just looking to come into work, find their tough questions on StackOverflow and head out for the day.

thelazydogsback
Reactoring and reuse is a bit of a pain compared to functors or typical OO code in C#, etc., esp. moving from idiomatic F# to to more performant code, when this is needed.

For example, I may use a List at first, as it's natural to start with and offers niceties with [H|T] pattern matching or List.filter() somewhere, then if I decide to use a .Net List (ResizeArray) or Array or Set instead, I'm screwed. The pattern matching needs to either change syntax or go away, and all the List.Foo() calls need to change to Array.Foo's or whatever -- or I have to use Seq.Foo() everywhere to get extensibility even I don't want to pay for lazy evaluation. Long time F# fan here! -- but still some sore points.

I spend a lot of time thinking about these sorts of topics (actually, I just taught a 4 hour session yesterday that used most of the terms in this article), working with newer, less experienced developers, and trying to figure how to distill the essence of "architecture" down to something simple that everyone can start with.

This is what I’ve started telling people:

Use mostly functions, try to make most of them pure.

I think that can get people (even new devs) 80% of the benefits (testability, composability, loose coupling, and the ability to reason about code) of more complicated, prescriptive architectures (Hexagonal, Onion, Ports & Adapters, Clean, etc) with a minimal amount of ramp up.

Of course, this isn't the solution to every problem (it obviously depends on the domain you are working in, for me its webDev and backends), but I think maybe its a good way for people to start.

Edit: Here is a great talk demonstrating that by following a simple functional approach, your code can naturally fall into a “pit of success”: https://youtu.be/US8QG9I1XW0

lmilcin
I am sort of in a similar situation meaning, I try to transfer to the team what I have learned over decades of development and now it is intuitive for me.

I think the most important principle is to "keep it simple". I mean, even if you have absolutely no idea how to put things together, just trying to limit LoC and trying to not do anything fancy is probably going to get you into better spot than any other principle alone.

"Keep it simple" has the advantage that it in itself is quite simple. Even if you are just starting you can pretty much tell simple from complicated code. You might not yet be able to make your code simple but if you honestly try you are also equipped to judge your results in an intuitive way which is essential to improve. The only way to improve is to be dissatisfied with your product and the only way to do that is to be able to judge it at least in some way. Usually the way you are dissatisfied is going to shape the direction in which you are likely to improve.

That is not the case with other principles, which oftentimes are easy to state and sometimes easy to show on a small scale of a very simple example, but give not much guidance on how to use and combine with other principles on a large scale.

For example, principle of using patterns to structure your code (we are talking GoF, PoEAA, etc.) which is frequently taught to people is right in itself (ie. whenever possible we may want to use established ideas on how to solve particular problems) but is frequently misrepresented by adepts who try to overload the application with constructs which even if correctly implemented, might have been replaced by a simpler construct. It frequently requires a lot of experience and good judgment to tell which pattern could be used in particular situation and it absolutely gives you no hint of how much is enough giving impression to novice developers that the more patterns you cram the better developer you are.

I also think that if you put "keep it simple" as your main principle, in your search on how to "keep things simple" you are probably going to discover other principles and also understand why, in the process.

I have many times seen codebase that has been thoroughly obfuscated by "pattern wannabees". I have also seen codebases made by teams that had very little knowledge of programming (like barely being able to program their way out of paper bag). Of the two, I very much prefer code written by people who don't try to be too fancy.

It takes twice as intelligent person to read the code so if some intelligent people try to be smart with their code but are misguided, it freqeuntly results in a codebase that is very hard to untangle.

With a code that is naively written, the problems tend to be simpler both to understand and to resolve.

Couple of months ago I had a discussion with a dev who was supposed to implement circuit breaker on one of the services (dunno why on one service only) and the resulting was a dozen pages of Java code that was chock full of callbacks, suppliers, optionals and what not. But something did not sit right with me because I could not for the life of me see what the code actually is doing and given the problem it was supposed to do I did not expect so much code.

So I sat down and over two hours I have simplified entire dozen pages to a single try / catch with an if in it.

Fire-Dragon-DoL
Interesting. It aligns with my line of thinking. With OOP, the most interesting objects are always stateless and the only "state" present is used for dependency injection.

It seems like in the industry the cost of having state has always been overlooked.

Funny enough, in frontend software this pain surfaced a lot, but in the backend it keeps being unnoticed, at least in the world I live in (Ruby, Javascript).

jhardy54
> Use mostly functions, try to make most of them pure.

This reminds me of:

> Eat food, not too much, mostly plants > > -- Michael Pollan

My new mantra: Write software, not too much, mostly functions.

wadkar
In a similar vein, I look forward to adding less lines and removing more in my git commits.
AnimalMuppet
"Not too much" is interesting. If I understand you correctly, you can write "too much software". I can think of at least three ways - bad architecture, too little abstraction forcing repetition, and just bad writing.

Did you have something else in mind here?

adamkl
I believe “Not too much” is a simple reminder that more code equals more bugs. So, try to write less code whenever possible.
rsanheim
I think "Too much software" comes from product and engineers not being willing to say 'no' to feature requests and product bloat, rather than any sort of strictly technical thing.

If your product or tool lacks a clear focus and goal, then the code base will reflect that, and will grow and sprawl endlessly.

bluGill
I have been net negative lines of code for the month more than once, while productively adding more features and fixing bugs. There is a lot of code out there that need not exist at all.
asimpletune
I think more likely is to actually have too much abstraction.
AnimalMuppet
Either can be a problem. Too much abstraction and you're writing FooFactoryFactoryFactory. Too little, and you're repeating yourself. Somewhere between the extremes is a sweet spot.

The problem is that, as the project continues over time, the sweet spot moves...

RangerScience
Nah. It's always about 4 layers. Hardware/services/data stores/etc, wrappers/models/components, business logic / application, ops/deploy.

If you nest your models/components deep enough that they're forming new abstraction layers, you're nesting them too deep. Backup and use mixin-style stuff instead.

If your business logic or application are nesting pretty much at all, then you haven't succeeded at making good choices in your models/components.

asimpletune
Agreed, and I’d add that code duplication is hardly a big problem. It’s kind of like if I legitimately see a lot of code duplication, then I have enough data points to do the right thing. On the other hand, abstracting early to avoid code duplication is worse.
RangerScience
Hmm... I think you might be right. Or, at least, that the problem that is and the problems that go with code duplication are easier to resolve than those that show up with shit abstraction.

Maybe... Duplication is a code smell, but shit abstraction is a code problem...?

RangerScience
I would definitely add "too many features". You can do a really good job building something way too large and you've built too much.
klenwell
NIH or Resume-Driven Development might be another way.

From personal experience, I worked with a team years ago where product owners wanted a datetime picker or parser for an app we had built. Senior dev on team decided it would be cool if it included some lite NLP. When product owners heard from him how easy it would be to add, they were on board.

He started with a popular existing Python library. But there was a bug with one corner case that was causing problems. So he took the initiative to spend a few extra days on the story to write his own simple NLP date parser.

A couple months later, early on Jan 1st, the new feature wished our ops team Happy New Year by taking down our application.

I happened to open an issue for the library's bug on Github after learning about it from the other dev. The owner there promptly responded to share a simple workaround for the issue. But by that time we already had too much software on our hands.

Jul 31, 2020 · 2 points, 0 comments · submitted by adamkl
> I don’t have that talent, focus and skill.

Same. I'm perfectly happy to fall into the pit of success[1].

1. https://www.youtube.com/watch?v=US8QG9I1XW0

The goal is that everything in the core is pure data types and functions. Now, depending on your problem domain, your core can be small or huge compared to the shell. Your question was all about IO/effects. They are impure and belong to the shell. If what you work on does mostly IO then you will have a lot of impure code lying around by definition. Still, the idea is that you should keep the amount of time spent in impure land minimal, ie. drop into pure structures/computation as soon as possible during program execution and only dip out of on occasions when you have to do IO.

Here is a good talk about these ideas: https://www.youtube.com/watch?v=US8QG9I1XW0

lackbeard
I guess what I'm getting at is that in any non-trivial program with many external dependencies and cross-cutting concerns, almost all of your code is the "shell", so either I'm missing something, or this is stating the obvious (write pure functions where you can) in a very roundabout way. I've never seen a program written explicitly in this style that wasn't a trivial example.
pwm
The system I've been working on in the past 6 months is non-trivial and written in this style. Roughly 2/3 of the code is in core and 1/3 is in shell.
yen223
I think it's more that a lot of programs aren't actually doing anything terribly complex, logic-wise.

A lot of apps out there do nothing more than fetching data from one service, and dumping it out to another.

ramchip
The functional core can return a symbolic description of actions to take, which the shell executes, a bit like a simple interpreter.

This is a good example:

https://www.theerlangelist.com/article/spawn_or_not

(Note the context is Elixir, so it’s talking about lightweight processes, not OS processes. It explains how to keep that stateful / effectful code very simple, and have all the real logic be pure functional code.)

HN Theater is an independent project and is not operated by Y Combinator or any of the video hosting platforms linked to on this site.
~ yaj@
;laksdfhjdhksalkfj more things
yahnd.com ~ Privacy Policy ~
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.