Mark Seemann
blog.ploeh.dk · Personal blog · on HN since 2012
Mark Seemann writes about software design, dependency injection, functional programming, F#, and category theory, mostly for .NET developers.
What HN saysCommenters recommend his category theory series and book 'Code That Fits in Your Head', and cite his argument that Service Locator is an anti-pattern.
171HN people shared it
67linked it in comments
155stories submitted
3.6Kstory points
3 months agolast shared
2012people per year2026
Most-shared posts
- 1From Design Patterns to Category Theory (2017)14 people · 774 points · first shared 2017 · 75 comments on HN
- 2From dependency injection to dependency rejection9 people · 108 points · first shared 2017 · 33 comments on HN
- 3Yes Silver Bullet (2019)7 people · 120 points · first shared 2019 · 72 comments on HN
- 4Less is more: language features6 people · 90 points · first shared 2015 · 63 comments on HN
- 5Functional architecture is Ports and Adapters (2016)6 people · 82 points · first shared 2016 · 9 comments on HN
- 6Service Locator is an Anti-Pattern (2010)6 people · 1 points · first shared 2013 · discussion on HN
- 7The Programmer as Decision Maker5 people · 9 points · first shared 2019 · discussion on HN
- 8When to use a dependency injection container (2012)5 people · 1 points · first shared 2014 · discussion on HN
- 9You'll regret using natural keys4 people · 748 points · first shared 2024 · 553 comments on HN
- 10REST lesson learned: Avoid hackable URLs4 people · 3 points · first shared 2013 · 2 comments on HN
- 11Visitor as a Sum Type (2018)4 people · 1 points · first shared 2020 · discussion on HN
- 12CompositionRoot4 people · first shared 2013
- 13The dispassionate developer3 people · 294 points · first shared 2021 · 255 comments on HN
- 14Semigroup Resonance FizzBuzz3 people · 88 points · first shared 2019 · 66 comments on HN
- 15Repeatable Execution (2020)3 people · 43 points · first shared 2020 · 4 comments on HN
What HN people wrote when they linked it
verinus · 2021-12-16
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
bunderbunder · 2016-08-03
It's a big ask to suggest reading through this, but reading http://blog.ploeh.dk starting from around about 2013 is illuminative.
Seemann basically wrote the book on dependency injection in .NET, and has been a pretty big evangelizer for clean object-oriented design. Some time during that year, though, he discovered F#, and from 2014 on his blog has been increasingly about functional rather than object-oriented design. By following the transition you get a pretty good luck at things (ML-style) functional programming does well, since it's basically a journal of a serious expert in object-oriented design learning switching over to the functional paradigm.
Joker_vD · 2023-02-09
> Copilot is amazing for reducing the tedium of typing obvious but lengthy code (and strings!)
Which it occasionally mistypes. Then you're off to chase a small piece of error in a tub of boilerplate. Great stuff! For actual example, see [0]
[0] https://blog.ploeh.dk/2022/12/05/github-copilot-preliminary-experience…
throwaway_au_1 · 2023-01-08
FWIW a fellow who has published books on the topic calls Service Locator an anti-pattern[1]. I take no position here as usage of any pattern is contextual but it's worth a read.
[1] https://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/
danielovichdk · 2022-05-20
Mark Seeman wrote a book about Writing code that fits in your head.
It's a really good read.
https://blog.ploeh.dk/2021/06/14/new-book-code-that-fits-in-your-head/
dmux · 2022-02-07
I've always found Mark Seemann's blog posts to be really pragmatic and insightful. He oftentimes puts to words things that I've always "felt" but hadn't quite found the thread to pull.
https://blog.ploeh.dk/archive/
mumblemumble · 2020-11-12
I'd go a step further and say that if calls to the IoC container are scattered all around your code, you're not actually doing DI. You're following the service locator antipattern.
(https://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/)
foxes · 2020-02-02
The inclusion/ exclusion idea can actually be useful for harder project euler questions (deriving some sort of closed form sum to compute). Worthwhile to think about.
Im also reminded about the "semigroup resonance" way to solve fizzbuzz posted recently on hn [0]. Seems like another interesting method.
[0] https://blog.ploeh.dk/2019/12/30/semigroup-resonance-fizzbuzz/
cryptos · 2019-09-04
After reading "Functional architecture is Ports and Adapters" [1] and using ORMs (Hibernate) for some time now, I'm wondering whether a functional approach wouldn't be better in many cases. With such an approach you would have the following flow:
HTTP adpater receives request -> object is loaded from database as immutable object -> business operation creates a modified copy -> DB adapter persists the new object.
The last step could be improved if the DB adapter would look what was actually changed. Since everything is immutable it is as easy and fast as comparing references (like React does btw). This works even with Domain Driven Design, what is usually used with mutable entity objects.
[1] https://blog.ploeh.dk/2016/03/18/functional-architecture-is-ports-and-…
l0w · 2019-08-12
wow nice post. I can also recommend Mark Seemanns take on monads: https://blog.ploeh.dk/2019/02/04/how-to-get-the-value-out-of-the-monad…
enz · 2019-04-21
I can suggest https://blog.ploeh.dk
Focused on OOP design and some FP design.
mlmitch · 2018-09-02
I ended up making an account for this one. Exceptions are a section in one of my favourite blog entries:
http://blog.ploeh.dk/2015/04/13/less-is-more-language-features/
Their argument is that Exceptions are GOTOs in disguise and point to the use of sum types.
I have found this to be good advice when using Java 8+. Composing Optional<?>, Either<?, Exception>, or CompletableFuture<?> has provided sufficient tooling for handling failure scenarios.
I also find that Exceptions slow down my reasoning about code, because they are side effects - see functional programming.
platz · 2015-01-22
The problem with SRP is it's hard to define what that "one reason" is exactly. http://sklivvz.com/posts/i-dont-love-the-single-responsibility-princip…
> sometimes really want is just a function
summed up nicely here: http://blog.ploeh.dk/2014/03/10/solid-the-next-step-is-functional/
chris_wot · 2013-06-27
Yeah, to startup the container and manage the object graph, sure. But not to directly instantiate the objects like you've given in your example!
The whole point behind DI is to decouple objects, any IoC container worth it's salt gets started and works it out for you. You shouldn't need to resolve the individual object.
Another poster noted this is known as composition root, a good explanation can be found here:
http://blog.ploeh.dk/2011/07/28/CompositionRoot/
Note the following:
"A DI Container should only be referenced from the Composition Root. All other modules should have no reference to the container."
Words to live by :-)
h2s · 2013-06-04
The epiphany we had was that whilst machines do access
the API, the developer is always the customer and user.
Everything we do should help the developer, and if we
have to break rules to help them... then largely we
should.
Thank you, this articulates my disagreement with the idea of hashing all URLs so that client developers are forced to follow links returned by the API instead of generating their own URLs
http://blog.ploeh.dk/2013/05/01/rest-lesson-learned-avoid-hackable-url…
aswerty · 2024-09-17
> This is such bad advice that I honestly couldn’t tell if it was a parody or not until I read the comment section—it’s not.
There is a large body of content on why concepts discussed in the article are championed. And also a large body of content on how they are misused (and I agree that can be - even to a huge degree).
So while, I think it is fine to judge that ascribed benefits are not worth the cost (or are not even realizable in a typical development team). Or argue why the benefits of an architecture like this doesn't work for Rust in particular - which may be the case since many of these patterns are oriented towards design in the enterprise applications space. But ascribing the approach as being a "parody" is not at all constructive.
The patterns of hexagonal architecture isn't in any way coupled to OOP even if some of the terminology is highly aligned with languages in the OOP space. In fact the well regarded (at least by me) Mark Seeman has an article how Ports and Adapters, another name for Hexagonal Architecture, is inherently functional [1]. And this resonates with my experience.
I have seen the pattern implemented well across: Python, Typescript, Javascript, .Net, Scala, and Go. And while the systems languages such as: C, Rust, and beyond are quite distinct from the previously discussed languages. There is certainly space for debate on the viability of the application of these patterns.
[1]…
dustinmoris · 2021-08-15
Observation from the real world:
Functional programming seems to be extremely easy if you have never learned imperative programming first. I have seen beginners grasp FP much faster than OOP and write production ready code only after a few weeks/months of learning whereas beginners need on average multiple years to learn "production ready" design pattern style OOP.
On the other hand I have observed some of the best OOP developers really struggle with FP. It's not that they find FP hard to learn, they find it really hard to unlearn OOP and the thinking that the way things are done in OOP is the holy grail of good software design.
For example, only recently there was this blog post trending on HN (Am I stuck in a local maximum - https://blog.ploeh.dk/2021/08/09/am-i-stuck-in-a-local-maximum), which was triggered by a "blue tick" OOP programmer (tastapod on Twitter - inventor of BDD) making false statements about FP because he seemingly struggled learning it and wasn't able to work out how to program without mutations. He came to the conclusion that all functional programmers actually use mutations by default and immutable data structures are not common in FP at all. It was a completely unfounded assertion and clearly one made from frustration by someone who was so hard wired into OOP programming that they couldn't adapt to the FP way of thinking. It was a prime example of an "old dog" (citing the original article) finding FP harder than the new guys.
ojnabieoot · 2019-11-08
> FP people don't use the term "design pattern" often, but that's what most monadic stuff really is.
This is exactly backwards. A monad is not a design pattern - a design pattern is an awkward manual reimplementation of a monad (or another category). In OO design patterns the structure behind what you're actually doing is buried under both the clunky type system of most OO languages and the arcane memorization of patterns and their names.
The whole reason design patterns exist is that in C++[1]/Java/Smalltalk/etc the type system is not quite good enough to enforce consistency with certain complex designs - failure management in concurrent systems being an excellent tricky example. In imperative/OO-dominant languages there is inevitably a huge amount of boilerplate around checking nulls, lots of wrapping things in try/catches, and so on. Design patterns are an useful abstraction of this boilerplate in a way that's easy to maintain (and, more importantly, are an intutive common language for many programmers). But they are no substitute for categories, which allows the compiler to make sure the design pattern is actually properly implemented.
But this stuff is quite complicated. It really does sound like a lot of navel-gazing mathy jargon. But the way you've phrased this makes me wonder - and I am aware this is condescending - if you haven't actually used categories in practice.
My thinking on this has been strongly influenced by this excellent blog series from Mark…
danidiaz · 2019-03-04
This is usually called the classical vs. mockist, or test interactions vs. test final state debate.
Instead of mocks, some people prefer to build fakes / stubs which are versions of a dependency which are "fully operative" in a sense but with a simplified internal implementation. For example a repository that keeps entities in memory. (Not the same as an in-memory database! The fake repository wouldn't use SQL at all.)
Tests would check the final state of the fakes after the interactions, or simply verify that the values returned by the tested component are correct.
The hope is that fakes, while possibly more laborious to set up, allow an style of testing that focuses less on the exact interactions between components, and therefore is less brittle.
Some links:
- Mocks aren't stubs https://martinfowler.com/articles/mocksArentStubs.html#ClassicalAndMoc…
- From interaction-based to state-based testing http://blog.ploeh.dk/2019/02/18/from-interaction-based-to-state-based-…
vfaronov · 2016-07-20
> We're talking about REST best practices here, not "let's do RPC instead".
I don't think so. Avernar above seems to argue against REST as an architectural style (RPC being the default as everybody uses it). I thought you were trying to defend REST with your example, and I wanted to point out a weakness in that example.
> There's no reason for the webcam to hard-code URIs, and that's a violation of the architectural constraints.
The webcam has to hardcode some URIs (entry points). Consider that it could be using other services: perhaps a social network to post updates on. Then it must hardcode another entry point URI. But at that point -- and since every resource is supposedly independent and only explicit relations matter -- why can't the webcam treat the "problem report service" and the "update frame service" as two entirely separate services to hardcode? Which constraint of REST does this violate?
In your example, insisting that the webcam go through the entry point doesn't even buy the server a lot of flexibility. You reduce the client's knowledge from 2 URLs to 1 URL -- a URL that you may still want to change etc.
An extra HTTP roundtrip every time can well be an unpleasant overhead. HTTP client caches are sparsely supported and notoriously complex (RFC 7234 is 41 pages long). Rolling your own cache is, well, rolling your own.
And then there is the human problem. I was blown away by a discussion [1] where people reported using cryptography to prevent in-house…
sltr · 2026-08-03
Reminds me of "Appeal to Aithority"
> The LLMs says this, so it must be right.
https://blog.ploeh.dk/2025/03/10/appeal-to-aithority/
Jach · 2026-05-09
I think the fuller version of the "'no silver bullet' is wrong" claim is at: https://blog.ploeh.dk/2019/07/01/yes-silver-bullet/
A weaker claim is that maybe there's no single silver bullet but there have been many bronze bullets that add up to more than a single silver bullet. I readily endorse at least that and think it's rather easy to justify.
magarnicle · 2026-03-09
"The problem isn't the concept of 'null', but rather that everything can be null, which makes it impossible to distinguish between the cases where null is an appropriate and expected value, from the cases where null is a defect."
https://blog.ploeh.dk/2015/04/13/less-is-more-language-features/#78744…
ptx · 2025-05-25
> James Shore calls this Parameterless Instantiation
Mark Seemann calls it the Constrained Construction anti-pattern: https://blog.ploeh.dk/2011/04/27/Providerisnotapattern/#4c7b89305e744b…
mrkeen · 2025-05-19
> Principle of Essential Denotation (PED): A relation should be identified by a natural key that reflects the entity’s essential, domain-defined identity — not by arbitrary or surrogate values.
create table citizen ( national_id national_id primary key, full_name text); Is national_id really a natural key, or is it someone else's synthetic key? If so, should the owner of that database have opted for a natural key rather than a synthetic key?
More arguments for synthetic over natural keys: https://blog.ploeh.dk/2024/06/03/youll-regret-using-natural-keys/
satvikpendem · 2024-11-27
It's not about the bugs, it's about designing the layout of the program in types first (ie, laying out all of the data structures required) such that the actual coding of the functionality is fairly trivial. This is known as type driven development: https://blog.ploeh.dk/2015/08/10/type-driven-development/
arendjr · 2024-07-18
The keyword to search for is algebraic data types, which are common in functional languages, but for instance Rust also has them.
Here is an example comparing C# with F#, where the latter also algebraic data types: https://blog.ploeh.dk/2016/11/28/easy-domain-modelling-with-types/
lmm · 2023-10-16
The IO doesn't usually involve business logic, almost by definition. A web service can usually make a pretty good sandwich if it's actually doing anything - you do a thin state fetch, a thick business computation on that state, and then a thin write / return to the user.
There are definitely cases where your business logic and your I/O are more tightly interleaved so that you can't really separate them the same way, and the post mentions that and links to https://blog.ploeh.dk/2017/07/10/pure-interactions/ as a deeper guide for those cases.
molszanski · 2023-01-09
I would prefer manual DI:
https://blog.ploeh.dk/2012/11/06/WhentouseaDIContainer/
1ris · 2022-11-18
The non-cynical answer is: Yes, we will be doing so much more.
https://blog.ploeh.dk/2019/07/01/yes-silver-bullet/