mmport80

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.

First 10 of 23 Posts Switch mode

brightball

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? :slight_smile:

Crowdhailer

Crowdhailer

Creator of Raxx

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)

  1. Using callbacks eliminates the value of the process mailbox. you cannot queue messages in a GenServer because of the handle_info callback.
  2. it’s difficult to have two types of messages to be going to one server, without knowing the message structure. again if a library is not using gen call then you are back to using the handle_info callback.

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

receive do
  Gen.call_received(from, message) ->
    Gen.reply(from, "thanks")
  TCP.packet_received(socket, packet) ->
    TCP.send(socket, "Gottit")
end
yurko

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 :slight_smile:

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

Qqwy

TypeCheck Core Team

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:

  1. Architect designs a building.
  2. The building engineer tells the architect “you really need to make this column three times as wide, or otherwise the roof will collapse”.
  3. The architect says: “Aww, but it ruins my Feng-Shui”.
  4. The final building is constructed from the compromises that the architect and the building engineer agreed on.
  5. People believe that the whole building was built single-handedly by the architect.

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 :slight_smile: :

18
Post #4
mmport80

mmport80 OP

I find myself mostly relying on the “nested pipelines” pattern

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

Qqwy

TypeCheck Core Team

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

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

By packaging OTP behaviours into macros.

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

mkunikow

OTP is concurrency model (actor model). Each language has some concurrent models.

christhekeele

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:

  • Parser level: customize the tokenizer and parser with new syntax and define new semantics for them, possibly by extending the list of language operators
  • Compiler level: create inlined functions and macros that do what you want, perhaps around overriden or custom operators
  • Runtime level: just use normal functions and possibly operators like this guide demonstrates

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.

  • Behaviour, Supervisors, GenServer, and GenEvent are macro-wrappers around existing OTP tools (you don’t have to use them to define OTP-compatible modules, and could write your own if you wanted!)
  • Tasks and Agents are higher-level abstractions around existing OTP tools
  • GenStage and Registry are completely new, non-OTP concurrency tools responding to some pain points in GenEvent and gproc, respectively

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 with work–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

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.

Where Next? Top

Trending in Discussions Top

AstonJ
As the title says, please share what you’ve been up to with Elixir. Whether that’s been learning it, looking into it, making stuff with i...
2977 91561 914
New
byu
@chrismccord : I just saw the Extract AGENTS.md from Phoenix.new into phx.new generator commit to the phoenix project. My initial shotgu...
New
arcanemachine
I was working on an Ecto migration and I needed a timestamp. So, for the nth time, I looked up the different data types for timestamps, a...
New
AstonJ
Just a general thread to post chat/news/info relating to AI/ML stuff that may be relevant for Nx now or in the future. Got anything to sh...
New
type1fool
I just stumbled on a newly redesigned elixir-lang.org. :tada: It looks like @Software_Mansion did the work, and I think it is generally a...
New
juhalehtonen
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New
alexslade
Fly’s CEO posted this recently - Turn And Face The Strange · The Fly Blog It says that Fly is going all-in on sprites, which is a worry ...
New

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve. They are GUI (Emerge) and State management (S...
New
ausimian
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New
akoutmos
@hugobarauna and I (Alex Koutmos) have been hard at work on writing a book on Nerves that takes you from simply blinking LEDs to building...
New
wintermeyer
There are three potential reasons for members of this forum to have a look at https://vutuv.de You are tired or annoyed of LinkedIn. Yo...
New

We're in Beta

About us Mission Statement