Earlier quoted context omitted.
Well of course, more complex applications are going to have more complex state. Rails does a lot more than most web frameworks, so it has a lot of extra state to keep track of. This doesn't make it any less a function, it's now just a function that takes in the internal state (including the db contents) as an input. That's exactly what the article describes.
> just a function that takes in the internal state (including the db contents) as an input No Rails (or other) app has a function like this where the entire contents of the DB are passed in as a parameter. And you can't handwave complex internal state as simply another parameter to a function because that complex state can change. That makes the function no longer solely dependent on the parameters passed in. Its beh…
Application-as-a-Function Thinking
51–60 of 80 posts
Re: Application-as-a-Function Thinking
#52I like to think of it as "application-as-functional-specification". A functional specification for a stateful system is a function from a list of all inputs to an output, i.e. `fun spec(inputs: List(Input)): Output`. This kind of specification doesn't need to specify `State` at all, as we can simply refer to previous inputs. E.g. imagine a counter system with the inputs `Increment`, `Reset`, and `Get`. The functional…
Hey, thanks for the input. > This kind of specification doesn't need to specify `State` at all, as we can simply refer to previous inputs. E.g. imagine a counter system with the inputs `Increment`, `Reset`, and `Get`. The functional spec for `Get` is "find the latest reset and then count the number of `Increment`s since then". I could be misunderstanding you, but this does not sound functional to me as `spec` seems t…
In a stateful system (where outputs depend on previous inputs) you need to have access to all previous inputs in order to determine the output of some input, right? Also keep in mind that this is a specification, not an efficient implementation. If you'd implement it like this you'd have to recompute the output based on the inputs over and over again for each new input. And yeah, you can think of it as some kind of functional composition as nine_k pointed out.
> This sounds very similar to DDD (like as described as the DDD book at the end of the blog post).
Yeah, I think DDD gets this right: some lightweight methods (e.g. event storming) around inputs and outputs. But yeah, Cleanroom did this in the 80s.
> At IBM direct, or are there any particular resources you can point to which you found useful?
On this particular topic, see Harlan Mills' "Stepwise Refinement and Verification in Box-Structured Systems" (1988): https://trace.tennessee.edu/utk_harlan/16/
Re: Application-as-a-Function Thinking
#53Earlier quoted context omitted.
You're skipping the part where Rails takes that Rack simplicity and does a whole lot of magic. There's a huge amount of state contained within Rails and then even more in the DB. So yeah, we can say web servers work like functions if we cut out all the bits that don't and call them separate applications. But realistically they're not.
Well of course, more complex applications are going to have more complex state. Rails does a lot more than most web frameworks, so it has a lot of extra state to keep track of. This doesn't make it any less a function, it's now just a function that takes in the internal state (including the db contents) as an input. That's exactly what the article describes.
Sure, it is possible to model these things as functions, for example by "passing" the entire world as a "parameter". However, it is an extremely contrived modelling, basically you're hammering the square problem domain into the round function hole with the biggest hammer you can find until it "fits".
It is also possible to model these things as Turing machines, or NAND gates...
Re: Application-as-a-Function Thinking
#54Earlier quoted context omitted.
Hey, thanks for your input. I blame myself for this misunderstanding as I wrote the article. I certainly am not suggesting that an application is a function, rather an application can be represented by single function as its core . There is an important distinction here as the production applications I have utilised this architecture in certainly do not literally behave as functions to the external user in the manner…
But this is the problem with basically every functional programming article that makes it's way to HN. As a thought experiment it makes sense but it's not transferrable to the real world. Like take the log out action as an example. Mid request we are going to have to change the state from a user logged in to a user logged out. Otherwise when we render the home screen, as an example, they'll see the logged in version…
> ... as a thought experiment it makes sense but it's not transferrable to the real world.
For the record, it's certainly not a thought experiment, I have been using this in the real world for a few years.
> Like take the log out action as an example...
The problem you outline with regards to intermediate UI states around the logout flow example is one of assumed responsibilities. If an application needs to show some specific transient UI when the application has moved between two states well, that's a UI concern and does not have to be modelled as part of the core application state. For example if you have a UI for an application which is required to show some jazzy animation when a user transitions from logged-in to logged-out that in no way needs to be part of the core application logic. The UI can just inspect the incoming state and conditionally when detecting a move from LoggedIn to LoggedOut trigger some UI animation / transient dialog / whatever.
One nice thought experiment / thought pump I find of value when dividing core application (~domain) and UI responsibilities is thinking about if you were to switch the UI from say a mobile framework (say Android/Compose) to a desktop terminal, what stuff stays the same and what stuff is display specific. In the above example you most likely would not want to show a jazzy animation on the terminal and therefore is display specific and should no be modelled in the core application logic. This is a nice simple thought process for dividing these responsibilities.
> And then how do we deal with stuff that's actually state. Like a database or whatever. Are we really passing that as a function parameter so that 10 calls deep can use it?
No, a database would fall under IO and would make more sense to access behind a Command interface in this pattern, like most other side-effect interactions. This fits into the "functional core imperative shell" mindset referred to in the post.
> And what happens 6 months in when we want a caching layer? Do we go back and edit every single function to accept a Redis argument now? Realistically...
I am in no way experienced with BE caching layers, my experience is mostly client side mobile applications. However, my first approach for an in-memory DB cache would be to chuck that in front of the DB access behind the same abstraction, and also this would be behind the Command interface, again like all other side-effect interactions.
Re: Application-as-a-Function Thinking
#55This is basically introducing Elm (a.k.a the inspiration for Redux) to Android. At least for me this model doesn’t work. Application is all about transitions of state, yes, but in context . That’s why React’s model of managing multiple state points in different levels of the application tree makes so much more sense to me
Your totally right, it's pretty similar conceptually to Elm in many ways, amazingly I only discovered Elm in the last 8 weeks or so after writing applications in this way for the last few years, maybe not surprisingly as I have been a mobile developer for 13 years and Elm is not big in the mobile space!
> Application is all about transitions of state, yes, but in context.
Like the other commentor says, it would be great to hear more about what you mean exactly by "in context" here.
Re: Application-as-a-Function Thinking
#56Very cool to see this! I've actually given this some thought a few years back when attempting to create (yet another) JS framework, and came up with something very similar to this! For me the difficult part was where the side effects fit in and how they're processed, what you call "commands" and "command handler". I didn't find an elegant solution to this and abandoned the idea early on, sparing the JS community.
> For me the difficult part was where the side effects fit in and how they're processed, what you call "commands" and "command handler"
Do you mean difficult for you when designing, or difficult to understand in my post?
Re: Application-as-a-Function Thinking
#57> “Application as a Function” Forgive me if I’m oversimplifying, but isn’t this just “stateless servers” and “router-service separation” at its core? Maybe this isn’t targeted for the API crowd, but anybody who has spent even a few months learning modern client-server programming understands this, and web dev is pretty common these days…
Not targeted at the API crowd really no, more client side applications, but it seems similar principles have been applied in various places / frameworks as spoken about in other comments here.
> Maybe this isn’t targeted for the API crowd, but anybody who has spent even a few months learning modern client-server programming understands this, and web dev is pretty common these days
Yes, I'm sure your right, but there are a huge number of people who are not web devs who have not been exposed to these fundamental principles and how they may apply in other operating environments :)
Re: Application-as-a-Function Thinking
#58it seems like less sophisticated version of reactive paradigm to me, am I wrong?
In my experience the commonality found between client side mobile applications and reactive principles is essentially everything is a stream, and the UI subscribes to those streams.
The approach outlined in the post is similar in terms of the UI observes a (single) stream of data, which can just be a simple (State) -> Unit) as opposed to some reactive library stream primitive.
The approach outlines is different from all the "reactive" client side applications I have seen as there is no proliferation of stream primitives present throughout the codebase, which often seems to create complex code with very little if any user benefit.
I'm not sure what other elements you see in the post which also fall into the "reactive paradigm"?
Re: Application-as-a-Function Thinking
#59No. Applications are not functions. How many applications that you use on a daily basis work as follows: 1. You prepare some parameters 2. You start the application with those parameters. 3. The application goes away and thinks for a bit. 4. The application returns with a result and then exits. Trying to make actual applications and system fit into the function (or procedure) mold is, IMHO, one of the biggest obstacl…
Hey, thanks for your input. I blame myself for this misunderstanding as I wrote the article. I certainly am not suggesting that an application is a function, rather an application can be represented by single function as its core . There is an important distinction here as the production applications I have utilised this architecture in certainly do not literally behave as functions to the external user in the manner…
And apologies for the misunderstanding due to my terseness, which is partly due to me having written about this in great depth on a number of occasions, here are two examples:
- Why Architecture-Oriented Programming Matters[1]
- Can Programmers Escape the Gentle Tyranny of call/return?[2]
The basic point is that we are so used to programming simply being call/return (and functional is a subset of that), that it is very hard for us to conceive of programming being anything else.
And one consequence of that is that we try to map every problem onto a call/return (incl. FP) solution, no matter how inappropriate the mapping, and the mapping very often is inappropriate, leading to architectural mismatch. [3][4]
We do this partly because we really don't know better, but also partly because there are tangible benefits, primarily that once we have done that mapping, we can then express whatever we arrived at pretty directly in our languages, because our languages effectively only allow call/return based abstraction.
It's a bit of a conundrum.
[1] https://blog.metaobject.com/2019/02/why-architecture-oriente...
[2] https://2020.programming-conference.org/details/salon-2020-p...
[3] https://repository.upenn.edu/library_papers/68/
[4] https://rd.springer.com/content/pdf/10.1007/978-3-540-92698-...
Re: Application-as-a-Function Thinking
#60How well does this approach scale for systems where the state is inherently large and complex? I write code that controls industrial machinery. There's just loads of different knobs and settings and modes that I can control with code, and a single production or test run will involve several heterogeneous machines, so the total state space is the cartesian product of all of those (not to mention the state of the physi…
I am assuming when a user interacts with one control button / dial / interaction it has a cascade effect on other controls / displays etc?
I am also assuming you already need to have a data structure representing the complete state of the system no?
There are multiple interesting aspects here, like are you / do you need to utilise complex state machines here? Just the subject of imperative vs functional state-machines is interesting and a small part of the wider approach.
Another interesting area is it depends on the language and execution environment you are operating in and how expensive operations over immutable data structures are.
Lots of questions!