A lot of database tools these days prioritize instant sharing of updates over transactions and ACID properties. Example: Airtable. As soon as you update a field the update shows up on your coworkers screen who also has the same table open. The downside of this is that Airtable doesn't do transactions. And the downside of not doing transactions is potentially dangerous data inconsistencies. More about that here: https://visualdb.com/blog/concurrencycontrol/
Ever heard of Django? ASP.NET? Most UI frameworks, including ASP.NET Core, Spring Boot (Java based framework), Ruby on Rails, and Django (Python) are all based on MVC.
Those are all stateless MVC over HTTP, which is a very different architecture from stateful MVC for long-lived UI. The latter was invented for Smalltalk by Trygve Reenskaug, and is far more relevant to front-end web.
Stateful MVC uses Publisher/Subscriber (or Observer) to keep Views and Controllers up-to-date with changing Models over time, which is irrelevant for stateless MVC over HTTP. Plus, in stateful MVC the View and Controller are often "pluggable," where a given Controller+Model may use a different View for displaying the same data differently (e.g. table vs. pie chart), or a given View+Model may use a different Controller for handling events differently (e.g. mouse+keyboard vs. game controller). Whereas, in stateless MVC over HTTP, the controller is the "owner" of the process, and won't generally be replaced.
And in the world of front-end web, stateful MVC really is mostly dead. MVVM and Component-based architectures (using the Composite pattern) have replaced it. A runtime is usually responsible for wiring up events, rather than individual controllers. Controllers don't need to be swappable because events can be given semantic meaning in components, and Views don't need to be swappable because you can instead render a sub-composite to change how the data is shown.
Is the Controller not in a coupled pair with a View? We could imagine an interface where it could be completely separate (e.g. a kiosk TUI where stuff like "press 'r' for X" is displayed), but in the vast majority of UIs the View has state, and the Controller has to depend on that state (e.g. did this keypress happen with a text field focused). Sure, this is abstracted away via the UI framework and we operate on usually some form of event system.
But even then, I don't really see how we could have a non-coupled controller-view. In fact, I seem to remember that it was described in a similar way for Smalltalk even.
You can have decoupled Controllers from Views using React. That's the basis of the "original" Flux/Redux architecture used by React developers 10+ years ago when React was just beginning to get traction.
A flux/redux "Store" acts as a Model -> contains all the global state and exactly decides what gets rendered. A flux/redux "Dispatcher" acts as a Controller. And React "Components" (views) get their props from the "Store" and send "events" to "dispatcher", which in turn modifies the "Store" and forces a redraw.
Of course they aren't "entirely decoupled" because the view still has to call the controller functions, but the same controller action can be called from multiple views, and you can still design the architecture from Model, through Controller (which properties can change under what conditions) and then design the Views (where the interactions can happen).
I was asking more in the abstract. Web UI frameworks usually sit on top of considerable abstraction (in the form of the DOM, eventing system, etc), so I'm not sure your reply exactly answers my question.
Whether application state is short-lived (e.g., request/response CRUD) or long-lived (e.g., an in-memory interactive UI) is orthogonal to MVC. MVC is a structural separation of responsibilities between model, view, and control logic. The duration of state affects implementation strategy, not the applicability of the pattern itself.
MVC is a structural separation of responsibilities between model, view, and control logic.
Yes, but the “MVC” pattern used by various back-end web frameworks that borrowed the term a while back actually has very little to do with the original MVC of the Reenskaug era.
The original concept of MVC is based on a triangle of three modules with quite specific responsibilities and relationships. The closest equivalent on the back-end of a web application might be having a data model persisted via a database or similar, and then a web server providing a set of HTTP GET endpoints allowing queries of that model state (perhaps including some sort of WebSocket or Server-Sent Event provision to observe any changes) and a separate set of HTTP POST/PUT/PATCH endpoints allowing updates of the model state. Then on the back end, your “view” code handles any query requests, including monitoring the model state for changes and notifying any observers via WS/SSE, while your “controller” code handles any mutation requests. And then on the front end, you render your page content based on the back-end view endpoints, subscribe for notifications of changes that cause you to update your rendering, and any user interactions get sent to the back-end controller endpoints.
In practice, I don’t recall ever seeing an “MVC” back-end framework used anything like that. Instead, they typically have a “controller” in front of the “model” and have it manage all incoming HTTP requests, with “view” referring to the front-end code. This is fundamentally a tiered, linear relationship and it allocates responsibilities quite differently to the original, triangular MVC.
- Being under the public eye—all the time—is one of the top reasons to not be famous. Famous people must constantly self-monitor what they say and do because casual mistakes can trigger disproportionate backlash or headlines.
- You lose the ability to have genuine, equal interactions—people treat you differently, with deference or expectation, rather than as a peer.
- Privacy disappears as curious strangers can easily discover where you live, details about your family, and how much wealth you have—information you'd normally share only with people you trust.
- Strangers form opinions about you before ever meeting you, based on whatever fragments of your public persona they've encountered.
- A public persona can become a cage, limiting your freedom to change, experiment, or reinvent yourself.
Elon Musk's strategy is to control the government operations through controlling its IT department.
The smart people of 18f stands in the way. By removing it and hiring his loyalists to run the government IT he gets to control the government's operations.
I enjoy the technical side, but I'm struggling to commercialise it so don't hesitate to give me your feedback here or on https://www.myowndb.com/contact.html which is of course powered by a myowndb public form :-)
heh, I'll throw my formial (https://github.com/nathanstitt/formial) project onto this thread. I probably need to update it a bit but it's been working well in production for 2+ years now.
Where were all these alternatives when I was looking for a WYSIWYG form builder?
Good question. We've taken a somewhat unique approach of integrating tightly with PostgreSQL in order to leverage its strengths. In the short term, we plan to continue with this focus on PostgreSQL, but we are considering supporting other DBs in the long term. Thanks for your comment though! Knowing that you have an interest in using Mathesar with MySQL is a useful data point for us!
> write generic functions that take functions as arguments and re-throw the errors thrown by these functions
There is a philosophy that applies here: simple things should be simple, complex things should be possible. The scenario you're mentioning is not common enough that the language design should be centered around it.
It's a very common pattern, almost every modern language has a "map" function. The map function can throw a superset of the exceptions that its argument can throw. If checked exceptions can't deal with this, they'll be of limited use.
> The map function can throw a superset of the exceptions that its argument can throw.
Wait. Why should a map care about what exceptions it's arguments can throw?
A map is storing a thingit. A thingit should exist independently before it gets placed into a map. Placing a thingit into a map should not invoke anything on the thingit. The only exceptions coming back from attempting to place a thingit into a map should be exceptions caused by the map.
What am I missing?
Obviously, there are maps that conflate themselves and do things like take ownership when an object is placed into the map. But that's not the general case and presumably you wrote the map specifically with that in mind.
You're thinking of a finite map, also called a hash table or a dictionary.
The map function takes a function and a list and applies the function to every element of the list:
map(double,[1,2,3]) = [2,4,6]
Grandparent could've used the for loop rather than the map function to make his point:
for i in [1,2,3]:
print i * 2
-- because in general instead of the i * 2 we might have a call to a function that might raise an exception.
ADDED. That is wrong: the for loop would not a good example at all because it is not customary to declare the type of a for loop or to need to declare which exceptions a `for` loop might throw.
In the case of map function hopefully you're using it with methods that don't fail in serious ways, and don't need strong error recovery. If so Java has RuntimeException to handle that case. If serious errors are possible and strong error recovery is needed, then you need to avoid the conveniences offered by functional style programming.
The problem is that if some code you call throws a checked exception (InterruptedException being an extremely common culprit) then you must wrap... and suddently nobody calling YOUR code can catch that InterruptedException reliably because it's now a SomeException (doesn't even have to be RuntimeException specifically) with an added "suppressed" exception that you now have to check for.
... so the basic "catch" syntax starts to fall apart because now you have to catch everything and resort to stuff like Guava's Throwables helpers.
It's madness.
The problem ultimately is variance: Methods are covariant, but throws clauses must be contravariant.
There are ways to solve this but "checked exceptions" (as in Java) are not the right way. Ask anyone who's worked in Scala on the JVM which they prefer and you'll have your answer.
It's possible to use a type parameter in a throws clause in Java, last I checked (as I also mentioned in more detail above). But it doesn't seem to be common practice, so interop is still a disaster.
Sorry. This is nonsense. map() is the bread and butter of any program. Besides, you cannot ever decide whether an exception is important or not -- it's always in the purview of the user.
Re-throwing a non-checked exception is what I described as the usual / typical coping mechanism in languages with checked exceptions. Which is obviously a way to negate the whole feature.
Sorry, disagree. map() didn't even exist in Java until recently. It is convenience at the cost of some safety. If you're writing a non-critical or throw away code you may not care about strong guarantees. Personally I prefer strong guarantees over convenience. I would only use map() for things that can't throw checked exceptions. A for loop isn't that hard to write.
Do you mean Turbo Pascal? He didn't design it, Niklaus Wirth did. Or do you mean C#? James Gosling designed most of that (C# got its start by copying 90% of Java). Do you mean TypeScript? That's mostly JavaScript.
reply