mmport80
Flamebait-y title, but Joe Armstrong doesn’t use OTP, so I am not in uncharted territory.
But… I have been thinking (dangerous).
I read a blog post a while ago, by a Lisp guy, who said that programming patterns are bad, because they are used to patch language weaknesses.
I imagine, in Lisp-world, patterns are packaged into nice little macros and all is good in the world because Lisp is flexible like that.
Perhaps too, this is where Elixir could really take a leap beyond Erlang.
By packaging OTP behaviours into macros.
Then again, perhaps the analogy is completely wrong, because behaviours aren’t really design patterns in the first place (although, I feel they aren’t far away).
Nevertheless, if I am making a little sense, I would love to hear some more experienced people’s views.
Trending in Discussions
Other Trending Topics
Chat & Discussions>Discussions
Latest on Elixir Forum
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #blog-post
- #phoenix_html
- #iex
- #graphql
- #genstage
- #ai
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #hex
- #performance










First 10 of 23 Posts
brightball
Distributed programming is very much a design pattern. I hate design patterns as much as the next rational person, but you can’t effectively assemble a distributed system without it. Even throwing a bunch of stuff behind ZeroMQ or load balancers is “a pattern”.
People don’t need to seek out OTP to use it “because OTP” but Elixir/Erlang’s design decisions facilitate everything needed to make OTP work so well for it’s purposes. You’re welcome to own a sports car with access to the Autobahn and not use it…but why?
Crowdhailer
I would be interested in where seeing what Joe has said about not using OTP.
I think that OTP is “bad” in a number of ways. (bad in quotes because obviously a lot has been done with it)
handle_infocallback.Elixir macros do allow some help to this because you can write macros and use them on the left side of pattern matches. e.g. the following psudo code that could be possible
yurko
I’d say any non critical belief that something is good or bad is a bad thing, that might be the evil behind some design patterns but it’s “not their fault” so to say
Without (a little bent) MVC and OTP we’d have problems maintaining our Elixir apps, YAGNI and KISS help us think about problems (or maybe they help us think less), so why are they bad? I like them!
That being said I find myself mostly relying on the “nested pipelines” pattern when writing elixir apps, that means I mostly think in terms of input, output and small functions in between, but that’s in part because these big fat patterns took care of other concerns.
Qqwy
I had a very interesting conversation with a fellow developer a while back. He has a background in building engineering, and told me the following story:
He said that what people in Computing Science call ‘design patterns’ (probably since the famous ‘design patterns’ book written by the ‘gang of four’) are actually ‘structural patterns’: “build the column this way or the roof caves in.”.
As such, they have nothing to do with beauty, but everything with practicality (which, in computing science, translates to speed/memory efficiency, ease-of-understanding, ease of refactoring).
Many programmers boast that “they solved problem A by using patterns X, Y and Z”, but that is useless. Patterns are something to recognize and use when it is useful to do so, not something to boast over or to cram as many as possible in your application of.
In the end, the main use of these named patterns is that two developers can have a conversation about a possible solution for a problem, and easily describe to each other how these work in general terms, just like two architectural engineers might converse and say: “to prevent this wall from collapsing, we could use a buttress.”
Tl;Dr: do not use patterns to solve a problem. do solve a problem by using patterns.
Patterns are good nor bad, but programming is about solving problems, not about cramming as many patterns as possible in your codebase.
As for the ‘do patterns exist in functional programming?’-debate: Yes, they do! (To be exact, structural patterns do). Some common ones include recursion, map/reduce, higher-order functions and even the illustrious monads. However, these patterns have a much lower impact on how everything around them is designed than many of the OOP-patterns are, and all of these patterns more-or-less arise naturally (i.e. even when you do not know about them, you might already have ‘reverse-engineered’ them).
The fact that many people do not recognize these as patterns might indeed mean that it is so natural to use them in your language, that indeed they can be considered language features.
As for OTP: Message-passing is a complex thing. OTP packages this in the best way Erlang could. I completely agree that this does not feel like the most idiomatic way in all circumstances.
There do exist Elixir libraries that wrap GenServer & friends using macros to make it easier to use, such as ExActor. This works fine for 95% of the cases. For the other cases (more logic in the outward-facing function before calling handle_*, or needing to keep the dependencies of your library as small as possible) simple OTP is fine.
I would say that behaviours are something completely different from structural patterns: Behaviours make different parts of your code agree in what way something can communicate. This in no way restricts what else is going on in those parts of your code.
Finally though, recognizing patterns is actually important. This amazing TED-talk explains why better than I could
:
mmport80
In some places, nested pipelines is called the ‘builder pattern’.
Both try to achieve the same thing.
One is instantly understood when you lay eyes on it, the other is found in the pages of design pattern books…
Perhaps same thing goes for OTP and the mythical language semantics which could replace it : )
Qqwy
Actually, I’d dare say that the ‘builder pattern’ is the poor man’s ‘partial function application’ (to be precise, the definition of the builder is a way to introduce ‘currying’, and the locations where the builder are used are doing ‘partial application’), while Elixir’s pipelines are a more natural way to write to function composition (which, itself, of course, is a more specialized form of function application).
benwilson512
What does this mean? We already deal with some OTP boilerplate with macros. Macros are a compile time construct, OTP is run time process patterns.
mkunikow
OTP is concurrency model (actor model). Each language has some concurrent models.
christhekeele
I do think the analogy is wrong, here. I don’t think OTP tools constitute programming patterns at all–they’re a fault-tolerant framework that builds on the BEAM VM’s concurrency primitives and other language features.
The OTP tools, in their implementation, may employ different programming patterns, and as a framework they limit the patterns you can use with them because they decide how you interface with them. OTP Behaviours are just one pattern to implement the definition of an interface, you can do this different ways (as Protocol does). You can re-implement OTP tools using those primitives, a custom interfacing mechanism, and different programming patterns if you want to get different results, if you want.
There is a “pattern” for this–it’s called syntactic sugar. The OTP framework is bundled with the language, so one could conceivably extend the language with custom syntax for hooking into OTP, or even your own custom concurrency tools. There are three ways in Elixir that you could create elegant hooks into them:
You’ll notice Elixir does do this already! In particular, only through the latter two mechanisms, without any custom operators. I think is a wise choice because it keeps parsing separate from syntax and semantics, and leaves the operator field wide open for custom use-cases, like your envisioned concurrency toolbelt.
With that background, to respond to your post point-by-point…
That’s because prefers to reinvent his own concurrency tools and behaviours from language primitives, or just use the primitives. If he packaged and published his tooling, you’d have just another OTP-like toolbelt in the ecosystem, which would be great. But the core appeal of OTP is that it’s done and battle-tested for you.
I think some tools are built to assuage language weaknesses. But some tools, like OTP, are built to make using the language’s strengths easier. I also think Lisp’s core language weakness is that it doesn’t have many standard tools built in, so its core language strength (metaprogramming) is used heavily to compensate. “programming patterns are bad” seems like a silly way to defend a core language-tradeoff that LISP made.
That would make sense if we wanted Elixir to be a LISP-world. Instead, Elixir’s made some trade-offs in it’s core library (like, for instance, having one) so that developers can be more productive out of the box, without navigating a package manager or auditing third-party code to decide how to do Enumerables, for example. Elixir inherits the OTP tools as well as adding its own.
Where it takes a leap beyond Erlang in it’s design, is that it’s hackable with macros to let you do anything you want to, within its parser and lexer limitations, if you’re willing to write the macros. This is how the pipeline operator, conditionals, and tools like
withwork–they’re totally new syntax and semantics, fitting within the lexer. You could build your own macro-powered concurrency tools that feel as native as those macros.As mentioned, Elixir has already has done this, although purely on a semantic level. However, nothing’s stopping you from a very interesting investigation into pairing your own concurrency tools, or pairing existing OTP semantics, with custom syntax. Just learn your way around macros and color in-between the lines that the lexer gives you. If you have some ideas in this front, I’d love to see your experimentation!
KallDrexx
Thank god someone said it.
Patterns being a bad thing is something that seems to be perpetuated by people who got burned because they took the idea of design patterns and “best practices” to mean “use all the time”, and then get mad when their square peg doesn’t fit in their circular hole, and they had to do frankenstein work to make it fit.
Formal design patterns are just a way to communicate different architectural approaches to solving a specific problem, not even to architect a whole application.