Why I No Longer Use MVC Frameworks
infoq.com
infoq.com
Figure 7 (http://cdn.infoq.com/statics_s2_20160209-0057/resource/artic...) looks to me like the sort of MVC you would do with vanilla PHP or friends back in the day.
In figure 9 (http://cdn.infoq.com/statics_s2_20160209-0057/resource/artic...): he handwaves saying that you can compose things, but nothing in the article suggests that SAM provides better mechanisms to sync data between client and server. E.g. what if the view is a table, and the action is deleting an item? Does an update consist of re-downloading a whole new table worth of data? Would it also do that if I deleted that same item from some other view? Or does it require 2 http requests in series (a DELETE followed by a GET)? What would an undo action look like in terms of HTTP requests and responses? The graphs feel like they're largely meaningless. Having arrows in a diagram pointing from one word to another doesn't say anything about the complexities of the system.
I must say, I've also become disillusioned with MVC for front-end frameworks, actually after using Mithril [1]. I'm sure you've seen me lurking and asking questions in the repo since before Mithril got big. I used it on a few projects and decided the controller was not an abstraction that made much sense. I looked elsewhere and stumbled upon domchanger [2] but after trying to use it seriously and forking some changes also ran into many impasses. This is what inspired me to develop domvm [3], a simple, pure-js composable vdom view layer for plain models. I took a few of Mithril's good ideas, removed globals, made the magic as opt-in modules (so a bit more wiring is needed) and ended up with something extremely fast (at least 2.5x Mithril), composable and mixed imperative/declarative. It's been a good journey and I'm very happy where everything ended up. Thanks for some inspiration :)
I would be delighted if my projects had a positive effect on a Mithril rewrite. I originally wanted to improve Mithril but alas it was not architecturally possible without large BC breakage and alienating the existing userbase.
Actually, as a proof of concept I wrote an adapter for domvm that allows Mithril's link rotator demo to work unmodified: https://github.com/leeoniya/domvm/tree/master/demos/mithril-...
In the end everything in software is an iteration of something else.
You're the kind of programmer I aspire to be like and be surrounded with.
Humorously, this is exactly what the current set of client side MVC libraries did.
The SPA movement "threw out" the notion of ajaxing HTML snippets in favor of ajaxing structured data for many reasons: better separation of concerns, better asset cacheability, better defaults against XSS, better infrastructure for multi-client architectures, the list goes on. I'd argue that security w/ data endpoints is far easier to audit and reason about than the old school RPC-style send-me-html-when-I-do-X server interfaces.
But when do you update the view? Angular dirty-checks the model on each $digest cycle. React dirty-checks the view.
Why not simply require the component to call a function to indicate it's changed a couple variables in its state? Simply keep references to the DOM elements in your component and update them. It's much faster and gives you more control, and a programmer who forgets to write the function call will realize it as soon as they don't see the update. The IDE or linter can even have a static analyzer that flags a missing call to the function.
I think that a lot of times these attempts at convenience (such as Angular's two way binding, or the virtual DOM) just throw more layers of complexity and slow things down from a relatively simple straightforward approach, while providing little other than saving keystrokes.
This is actually roughly what knockout and ember (pre-glimmer) do. They are known as KVO (key-value observer) systems and have implementation challenges of their own: knowing when to batch operations, dealing w/ computed properties and rx glitches (in reactive systems, a "glitch" is the name given to temporary inconsistencies that occur between stable states), and added complexity in terms of requiring the model layer to be observable-based (as opposed to POJOs in Angular/React/friends).
Also, high quality KVO systems are far more difficult to implement. To my knowledge, Vue is currently the fastest KVO-based javascript library in existence and in order to support its POJO-like model API, it's significantly larger than Snabbdom (which is one of the fastest vdom implementations currently, despite clocking at a mere 200-300 LOC)
AFAIK, most of the challenges faced by KVO system have not been as extensively explored (at least by the javascript community) as virtual dom algorithm optimizations have, so currently I believe high quality virtual dom libraries are likely to perform better at various real life scenarios than current state-of-art KVO systems.
The pain point that templating engines address is automating the process of figuring out what DOM changes are caused by what state changes. In order to do that, you have to either dirty check the state tree (as Angular 1 does), dirty check the template tree (as React/Mithril/vdom does), or have an observable state tree (as Knockout does). If the templating engine defers its responsibility to the developer, then if, for example, you do a `dataList.pop()`, you are responsible for writing out the code to remove the last item in a DOMNodeList, or updating some count label, or whatever else the view may be doing. This works ok in a small app, but it tends to become hard to maintain as a codebase grows in size (due to requirement changes or whatever).
http://qbix.com/platform/guide/tools#dom
Remember, tools are reusable and the tool's developer is the one who has to write that code. The app developer just plops the tool on a page and it renders itself.
Most tools don't need 60fps efficiency for animations. they would implement a simple .refresh() method (similar to React's render method, except without the virtual DOM). When the tool is first activated, it typically renders any HTML it needs to inside this method, unless the HTML was already there (because eg it was rendered server-side). It typically renders a template with some fields fromthe state, just like in Ember.
Right after this, the tool usually just stores references to elements it wants to update. For example,
tool.$foo = tool.$(".someNode");
And then when it comes time to update, you just do: someTool.state.x = 5;
someTool.state.y = 8;
someTool.state.z = "moo";
someTool.stateChanged("x", "y", "z");
And the tool's constructor method would have done this: this.onStateChanged("x","y")
.set(function (oldValues) {
this.$foo.html(
this.state.x + this.state.y
);
});
This event occurs whenever either x or y was reported as changed. Our framework would make sure these onStateChanged events are triggered at most once per animation frame.In your example, I'd signal that some array changed, and the tool would figure out what changed via dirty checking. But why do that crap? Why dirty-check at all? In our framework, we have streams and messages posted to the streams which are supposed to say what changed. A move was made in a chess game. A person wrote a chat messge. These things are updates, which are hard to represent in Angular and React as mere maps from plain data to the DOM.
What's wrong with that? Any tool developer can add event listeners for when something changes, and do whatever update thy have to do. The app developer just updates a tool's state and it just works. If you need 60fps or just want to render 1,000 constantly updating tools on a page (BAD IDEA) then you can do it.
I guess I should have said that the rest of our framework uses the same concepts. Instead of syncing data like Firebase or Parse, we treat data as streams onto which one or more collaborating users post messages. We take care of making sure the order of the messages is the same everywhere, and we take care of a ton more things such as pushing realtime updates, managing subscriptions, access control etc. All you have to do is implement the visual change when the server says a chess move has been made, etc.
We even have a convention for "optimistic" changes that assume that your POST succeeded by simulating messages that should have come in. Once in a while, the assumption is violated, eg if another user posts another message in the meantime, or the server becomes unreachable. Then we .refresh() the stream to its last confirmed state and all tools automatically refresh also because they have event listeners on that Q.Stream object's onRefresh event. Then your tool may want to retry the pending actions with OT, ask the user, or whatever. And so forth.
Have you seen any framework with this straightforward model?
The example I usually use is a data table (sortable columns, filtering, batch delete, pagination, etc. you know, the usual suspects). The main benefit of a templating engine is that you don't need to write various routines to do each variation of DOM manipulation and worry about the various permutations, you just write the template once.
Personally, I prefer to not rely on querySelector if possible in order to avoid code smells related to identifying elements in a page with reused components, and I prefer to avoid observables because I think that their "come-from" quality makes them harder to debug.
In addition, I feel the declarative nature of virtual dom enables a level of expressiveness and refactorability (particularly wrt composable components) that is difficult to convey to someone who's more used to procedural view manipulation.
> Have you seen any framework with this straightforward model?
Yes, I believe Flight is similarly event-based, and Backbone can be used like that, too, pretty much out of the box.
Being a framework author, I take great interest in improvements in framework design, but to be honest, I haven't gotten much out of event-based systems and I generally feel like they are a step backwards from virtual dom in a number of areas. Mind you, I'm not saying that event-based frameworks are bad. Plenty of Backbone codebases work just fine, and if your framework works for you, then that's great.
<div>{{moo*2}}</div>
Which is then picked up by the framework to do two way databinding, dirty checking and other inefficient stuff it assumes you want, vs the equally declarative: <div class="foo"></div>
And then have the component's code look for ".foo", save the reference and update it when the state changes? It's easy for the component developer to know what to do, after all, and it might involve more than just text replacement. Angular has filters as a poor man's declarative version of functions.The trick to fast rendering is: don't read from the DOM, throttle DOM updates to requestAnimationFrame, and turn off fancy css when animating.
It's true that without two-way databinding, you have to read from the DOM. Maybe in that sense two-way databinding is good, but when should the update happen? Onchange?
Well, the difference has already been explained to some extent in other comments. In the first snippet using a templating engine, the engine automates the DOM manipulation. There is no procedural "and-then-have-the-component's-code-do-X" step.
In the second snippet you're responsible for writing that code and making sure that your `.foo` query didn't unintentionally pick up some other random DOM element, that you don't have logical conflicts in the case of some code relying on the class name's presence and other code toggling it, etc.
Re: performance, I think today it would be wise to start questioning the idea of hand-optimized DOM manipulation being faster than libraries, because most people aren't templating engine authors and don't know the tricks that those engines use, the algorithms to deal w/ the hairier cases, or what triggers deoptimizations in js JIT engines, whereas library authors are actively dealing with those concerns on a ongoing basis.
Two-way data binding is somewhat orthogonal to the templating engines' primary goals. All a 2-way data binding does is wrap a helper around an event handler (e.g. oninput) and a setAttribute call. But as I mentioned above, you don't need to use the bidirectional binding abstraction; you can have explicit re-render calls instead.
The answer is in that statements. Angular and React is not you.
> Simply keep references to the DOM elements in your component and (you) update them. It's much faster and gives you more control...
The point of React and Angular is that you don't have to think about updating the DOM.
Would you mind writing "with"? It's two extra characters, but it makes the sentence much more readable. (Words are recognized by shape, especially the shortest ones.)
Professional writers and editors, and I've been both, have considered this one of the standard "UI design" principles of the field for generations.
(And no, I'm not talking about formal versus informal writing. It's a more general principle, such as using mixed case or putting spaces between words.)
w/ is both incredibly short and has a very unique shape.
I, for example, didn’t know w/ meant with until now.
There's a simple set of separations that you need to pay attention to for your code to be what I like to call "not stupid".
1. Separate your code from your data. You shouldn't be kicking out HTML with your code, like this guy does in figure 1. When you combine HTML or any display information with code that means your designer is your coder and your coder is your designer. Designers suck at code. Coders suck at design. Keep that shit separate.
2. Separate your logic code from your code that changes your data. You shouldn't be running updates/saves/inserts from 30 different locations in your code. Define your interface, expect that interface to work. When you need to shift from Oracle to Redis to RDS, you shouldn't have to refactor 80% of your application. You refactor your data update code and leave everything else that works alone.
There you have it. Model, View, Controller. You have a data model that can be displayed in any number of ways, and you control CRUD on that Model via the controller. It's not a religion. Just make sure there's a logical separation within your code so you can delegate as your team and application grows.
Architect things logically and call it whatever you want.
The only material difference I've ever seen is that when people define their HTML output in template files, they have to invent a whole separate language for doing basic control structures like conditionals and looping. Why re-invent the wheel when you can use the same language that the rest of your app is programmed in?
I also find that asking the designers to put keywords in the site mockup and use that as ad-hock templates could work rather well.
Often I find it the other way round. You hire an Angular expert and, if he's junior, you spend the next 3 months unteaching him all the bad habits he's learnt, or, if he's a senior, spend the next 3 months arguing with him about who knows Angular better, all the while kissing goodbye to any maintainability your code base once had.
If you have simple, well factored code, a good coder can learn it quickly. In fact, juniors often get it faster because they don't have to map their limited understanding of "patterns" to the documentation on the website or the behaviour they see on the ground.
What gets me about all this is that web app development is just about the simplest programming you can do. It always staggers me the lengths otherwise intelligent developers (sorry, "software engineers") go to make their architectures as complicated as possible. I sometimes think it's because they're intelligent that they do this, perhaps out of fear of not being challenged?
Generating HTML directly in the code makes it very easy to figure out how everything works, and thus modify it, since you see the whole process in one place.
Speaking as someone who recently turned a ~5kLoC, ostensibly MVC and consisting of over a dozen files (mostly empty or nearly so), but quite trivial application into a single file of less than 100 lines, it's amazing how much complexity some people can introduce.
Here's a couple of examples ---------------------------------
For example, lets say you have a data set that returned user information. Combining it directly with the html may be easier. The issue happens when you want to use that same data (or portions of a that data) elsewhere. From there you would have to rewrite the query. Having the data-set separated (either in a class or a function that returns raw data, then having that data parsed and placed within html works much better. There you don't have to rewrite anything (and have the satisfaction that the data "works").
On the other side, separating the html will be helpful as well. Say that the interface has now changed. You are not going to remove a column in a table and reorganize other components. Instead of having to look through the code where you may have placed the html with the data, all you need to do is to make your changes accordingly in your presentation layer.
All in all, it may seem like a lot more work to get things started (I don't use MVC in the traditional sense, and instead have my own programming rig). The reward lies when you can separate duties among team members. Someone can work on the presentation (and the browser compatibility issues that it includes) while another one can work on the business logic. So on and so forth.
You can still have the separation of duties that you describe because, in the case of web app dev, HTML and CSS are already separate languages
I currently work in a small-ish company, where I am the ONLY person designing/developing multiple systems. (I do get some input now and then, but it's mostly all down to me.)
I like this idea in principle, but you don't always have the resources to achieve this!
How do you feel about the common case where there is one person for both coder and designer roles? This is extremely common. Your comment makes it sound like the coder and designer are always separate people when in reality, for most websites, the front end coder is the designer.
That use case is the "we should only have to pay one guy and he should know everything" use case. Or the "I have an idea for an app. I'm a company now." use case.
Know why so many bootstrap sites look pretty much exactly the same?
--- If someone wants to change the color of the header on a website, should it require a code change?
If there's a table that someone wants to change the border on, should that require a person who knows three languages? Or should that require a guy who read an html book last week?
Conversely, what if there's a bug report about an element that is not displaying on a Nook Color? Should that require a developer to look at? Or wouldn't his time be better used working on an actual programming problem?
--- I interviewed a developer recently and asked him about a particularly difficult challenge that he worked his way through. Usually people respond with a problem that manifested itself in multiple ways or tracking down an important bug in a widely used library. This particular answer was about an errant price change on a major retail web site that took 6 days to implement. A price change should be a zero down time absolutely no-brainer data change. But some idiot along the way decided that he should embed html AND javascript in his java class and it took a team of people several days to track down where exactly the error was that produced the errant price. There's stupid code like that all over the place.
With experience, you learn that you can avoid those kinds of problems completely with very little overhead early on.
A team of people, several days, and no one thought to just grep the codebase to find the relevant pieces? If that "idiot" didn't conveniently put the pieces all in one place, maybe it would've taken even longer to find? I wouldn't blame that on being "stupid code"...
I'm not going to defend this practice or design. I would never have let something like that get anywhere near production myself.
You see a lot of people in this thread who don't feel that separation of code and display information is important. Imagine how that looks in an agile environment where nobody steps back to look at the big picture and developer turnover is high - like maybe a model that included churning offshore resources in and out as requirements demanded it. It's bad.
In reality separation of concerns is a luxury only afforded to larger teams and orgs.
If you have the people, do it. If you don't, you're in for a bad time concerning yourself with it.
Granted the html in Java is just straight idiocy, and my point refers to far less insidious mixings.
separation of concerns in your codebase is a necessity.
Having inherited a new project recently I was disappointed to see the documentation talking about following the philosophy of thin models and fat controllers (the opposite of what is considered best practices for Django, which the project is using). It means that there isn't one obvious place to look for the expected functionality,there is unnecessary repetition of code and its way less efficient than it could be if it was done the other way - models with data definitions and related methods in the same place.
I am all for separation of concerns, but I don't think splitting along the lines of "data" and "code" is the best way to achieve that.
It is a foreseeable problem that you will have to support multiple display layouts with the same set of data. It is a foreseeable problem that you will need to train and delegate.
You can be the full stack guy today and learn everything you can about all aspects that you are interested in. It's a great way to learn. But if there is no logical separation in place, you are stuck where you are until you either refactor the entire thing or you find somebody who went down the same path and has the exact same skill set as you.
Not segmenting your code is stupid. Plain and simple.
If you want to see code that doesn't separate things logically, have a look at old vbulletin or phpbb code. Look at what happened historically in both of those projects. Think about what it's like to add a new feature when you have 40 php pages that you have to touch, each written by a different developer, and each with html mixed in with the php. You have to know the whole set of code in order to do anything productive. The end result for both was security problem after security problem and a design that has not transformed significantly in 10+ years.
You can buy yourself job security by building a project that requires the developer to know a specific language, an MVC library, a specific version of HTML, a particular javascript library, and how to interact with web apis from two vendors from both server side and client side code.
You can earn yourself a promotion and new interesting things to work on by building projects that you can walk away from.
And overly broad, generalizing statements are not?
Remember to be respectful towards your peers.
There's stupid code all over the place. Twenty years ago, you had to know networking, hardware, relational databases, and programming to get anything done. Nobody did QA testing, AB testing, or even had a development environment seperate from production.
We're slowly growing up and realizing our mistakes. If we can't call our own code stupid, then we've achieved a level in our political correctness culture that ... well, that's just plain impressive.
If anyone felt personally attacked, I certainly did not mean for it to come across that way. I am in a bit of a mood tonight...
component/Controller component/Model component/View
Or you group by enity, something like customer_management, where you put all your customer related controllers:
customer_management/View1 customer_management/View2 customer_management/View3 customer_management/Controller1 customer_management/Controller2 customer_management/Controller3
now you introduce subfolders: customer_management/Controller/Controller1 customer_management/Controller/Controller2 customer_management/Controller/Controller3 customer_management/Model/Model1 customer_management/Model/Model2 customer_management/Model/Model3
Both have their ups and downs and still are related to MVC. However you've still outgrown MVC a little bit since now your so big that actually some things doesn't make sense, so you add a datalayer on top of your models or a service layer, etc. things get really messy now, when you don't change. That's why programming is hard. Correctly or logical separation of code changes as your application evolves but people don't change it so they blame the separation concept.
I take it that you are the author and I've completely derailed your thread by going off on my own tangent.
Apologies.
I will give it a second read and see if I can't come up with some more relevant feedback for you.
As a developer, it's pretty easy to pick up design basics when you've been coding frontends for a few years. On the other hand, I regularly see professional designers come up with... very impractical ideas, to put it nicely.
Anyway, your statement is not necessarily always true.
It seems to me at least that every 10 years or so a new group of fresh grads enter the workforce and by sheer will (and all nighters) recreate different forms of the same solutions to familiar problems.
Meanwhile, the previous designers and implementors seem to fade (who knows where they end up?) and the normal evolution we should be seeing in our API's, frameworks, and collective knowledge simply inches (is that too generous?) along.
We are giving different names to original ideas. For example, I have read (sorry, I can't find the links) recently where others have published on interesting new design patterns only to find out they are essentially renamed versions of the original GoF patterns.
The same challenges exist and we are seeing someone else's take on the solution and it feels too familiar because they look at what's out there and provide only a marginal variation on a theme.
I believe this partly explains this "been there, done that" that we're seeing these days.
It's not a bad thing in my view. Watching an inexperienced and enthusiastic team lurch forward with some new hotness, often different angles on old problems, is one of the things that keeps me interested.
That pioneering community mature and start recognising the similarity of their deeper issues with more classical computation problems. Then they start to investigate earlier thinking and solutions - or engaging older developers with wider knowledge.
But they almost always add something in the early stages as they were not prejudiced by legacy solutions.
Rails was a good example of this - it massively changed a lot of thinking in good ways. Many people I met in the early days of Rails went on to need outputs from earlier generations - niche languages, classical data structures, lexers, low level debuggers etc. - the very things they thought they were disrupting.
Older developers are not immune to this - I've sketched out some complicated (to me) data requirement on a whiteboard, with some loose thinking on how we might solve it, only to be informed it's a classical problem with a standard solution pattern developed by someone in Greece 2000 years ago.
How the Ancient Greeks Invented Programming http://www.infoq.com/presentations/Philosophy-Programming
Summary:
Matt Butcher explores the philosophical systems devised by Plato and Aristotle, showing how Plato laid the foundations for what is now OOP, while Aristotle’s dynamic model is at the core of FP.
not sure if it's a hyperbole, but it gave me a good laugh :)
To be fair, most OOP practitioners don't even know what "data abstraction" means: this is what is meant by "it's better to have 100 functions that work on one datastructure than 10 functions that work on 10 different datastructure. The latter is OO, the former is FP.
Good OOP design is very similar, if not identical, to good FP design. For example:
- The iterator pattern: is essential to more abstract FP, see for instance 'the essence of the iterator pattern: https://www.cs.ox.ac.uk/jeremy.gibbons/publications/iterator.... The iterator as a stream is a coinductive data structure and a such a fundamental structure in FP. Also note that transformations on iterators are applicative.
Then, look at many of the other GoF structures: the visitor pattern, which is very similar to recursive algorithms on trees. The adapter is basically applicative, the Factory is difficult, but could be seen as a coinductive structure.
Also, one should note that in (modern) proper OOP, composition is your most important tool. This is very similar to composition of functions.
You have full control over the iteration,. but everything is immutable and thread-safe.
'Promoted' to management, due to the all-pervasive and asinine perception that the only way to recognize a highly skilled technical person is to waste their time with bossing other people around.
In web development it is probably complicated by that fact that, in my opinion, declarative positioning and sizing of elements is a pipe dream. It looks simple until you try to actually implement it, and HTML/CSS has only a rudimentary implementation. (As far as I know, Motif and Apple's constraints are the only UI toolkits that have a solid implementation) Given what we want to do with the web these days, I think we would be better off with programming the web page declaratively. Something like what Qt does. I've never found an easier way to write a UI than Qt.
MVC was popularized because after enough people went and just threw together random things for enough projects, turnover, learning curve, switching between projects, etc just became a huge burden. The big sales pitch for MVC on the web (largely influenced via Rails) was a good enough common structure for web apps that developers could learn and apply across projects.
It worked in that regard, but as usage became more popular we ended up adding on more and more and more and more to try to make the "common" solve everything. Constant changes screw the entire point of the "we all learned and know this" benefit.
Flexibility of your approach is probably more important in the world today than following a rigid structure in an attempt to let the structure solve everything.
I like the approach outlined here...but I'd have a hard time using a framework based on it. I'd rather write my own code using a simplified process and minimizing dependencies if I'm going outside of something that's clearly a major player that can be counted on to stick around.
Unless you are doing something so spectacularly, mind-blowingly irresponsible in your dependency management that changes just come in of their own accord (i.e. Go's defaults), no they don't. They change when you choose to vendor the new version or change the pinned version number.
It's true that your dependencies won't get security updates until you decide to upgrade, but other people are certainly not writing security updates for your in-house code.
You should care about the code quality of the 3rd party libraries you use, with the understanding that you might one day take over maintenance of them, at least for internal purposes. That's still not a reason to duplicate effort.
That's the main thing that I meant. Rails was the first that did things in a way that everyone else tried to emulate.
This gives you a nice, secure environment to build your UI in with the full power of the query language your datastore provides, and it doesn't require any particularly complex architecture or discipline to maintain.
And, of course, I would be remiss if I didn't mention my baby, http://intercoolerjs.org/, as a tool to help you do it.
Javascript is useful for web apps.
When a blog has time to display a load animation in 2016 someone, somewhere should have their client side JS privileges withdrawn ;-)
Using JavaScript client-side doesn't necessitate this. You could inline the data into the page and you would not be able to tell if it was client-side rendered.
The key one we're asking here is "how much business logic do you need in your presentation layer?" Too little then you're round-tripping for simple form validation and your UI is unresponsive. Too much and your UI becomes tightly coupled to your business rules (and you start exposing too much attack surface).
Modern SPA web apps are making a deliberate trade-off, moving more logic into the client so the app is more responsive.
The problem of making the API schema "pure" or tightly coupling it to the UI is the same old "how much business logic sits in the database" debate. Ideally, of course, all endpoints would relate directly to application entities so that changes to the UI don't change the API. But this increases the number of round-trips and reduces responsiveness. Same for rendering HTML on the server - increased round-trips and reduced responsiveness.
The answer depends on the trade-offs that the project needs. Is the API complex and used by lots of clients? Keep it pure. Is the API small and/or used by only one client? Tailor it to the client? Is responsiveness paramount? Put as much as possible client-side. Is security paramount? Put as little as possible client-side.
IMHO there is no right answer that works across all situations, just as there wasn't back in the 3-tier day.
If you throw HATEOS-without-thinking-or-arguing-about-it on top of that, it seems like a no brainer to bias toward that approach.
I used to think that web apps were dumb and thick apps were obviously better in most cases, but I've changed my tune in the last few years as I've come to understand HATEOS and disentangle it from the JSON API quagmire it got into:
If you want to realize those advantages, you will end up introducing a "simple" solution like GraphQL. In an insecure environment.
Read, man. Don't just react.
If u search about these technologies, which are quite old, u can find the positive and negative consequences of their implementations in the wild.
ie. exposing IQueryable<T> is an anti-pattern and security vulnerability. As soon as your API is public, and you try and lock it down from simple DoS attacks, your not going to end up at the beginning. The only place these technoligies belong would be in your trusted environment - API <=> DataSource, not Client <=> API
Yet.
Again, the tradeoff is touching your API (or security model) every time UX needs change, or exposing more and more security issues client side.
No, no it is not in the spec, as of February 15th, 2016:
Update: I think Peter Hunt is talking about Facebook's internal server-side implementation of GraphQL. That's the only way his comments make any sense given what's publicly available.
> For each node type and edge type in the graph, you provide a required canSee() function which controls its visibility.
> It doesn't belong in the spec
_kek_
Am I on candid camera?
permission
authorization
authentication
role
You can return null if someone requests an object they're not allowed to access, or return an error, or whatever it is that you're currently doing.
I've been playing around with GraphQL, and my approach has just been to include a permissions object for the actions a user can take on the resource:
{ permissions: { destroy: false, update: true, ... } }
You SHOULD be checking permissions on each node and edge, but the details are entirely in your hands.I agree 100%.
However, that's not what the GP said above, which was "It is a view model abstraction on top of your database which includes permissions checks for each node and edge, so in many ways it's actually more secure than the alternative of securing each endpoint adhoc.". I contest the use of "includes permissions checks" and "actually more secure" for a system that does not at any point specify any type of security at all. It's just as secure as any random REST API or route (in other words, as secure as you make it, and not any more).
That's maybe what FB's internal vision of GraphQL is, but that's not what we have available out here in non-FB land. If carsongross's argument is that GraphQL is moving the database to the client side, and all of the security issues that go with it, then a rebuttal that says 'Nope, GraphQL is more secure' isn't going to cut water if the only specification of security is locked away. Particularly since people may be accidentally throwing their GraphQL client side not realizing that there are security issues involved at all (since Peter Hunt says it's more secure for example)
> Intercooler responses are HTML fragments.
I'd argue that, just like described at the end of the article, it's just shifting the burden on the server. It's a trade off.
IMHO React gets a lot of things right :
- DOM diffing
- Components
- 1 model as a unique source of truth
And when one thinks about it, IT IS MVC in its purest form, since there is only one model, one big view(the tree of components) and one controller(using event delegation). What React nailed is an efficient way to rerender the view.
Server side MVC and HTML as a transport has a huge number of advantages, not the least that HATEOS "Just Works" without anyone having to think about it, but even if it didn't, I would think that the API churn/security tradeoff would give the development community pause about heavy client-side logic.
I'm not sure what problems you are referring to here, since you don't seem to have defined them anywhere. They sound like they'd be well outside the scope of a library like React, though, which is essentially just a declarative UI rendering tool.
Additionally, I don't see how rendering on the server frees you from thinking about security or setting (and enforcing) proper permissions. All you gain is that the problem is less visible and your entities are obfuscated in chunks of redundant HTML.
In fact, now you may open up new security holes like XSS that you can avoid easily with proper client-side widgets.
Well, it’s not really efficient.
A more efficient solution might be if we wouldn’t even need DOM diffing, but instead every module would be based on a reactive model, and we wouldn’t have to deal with the diffing anymore.
edit: s/nature/definition
Indeed it can't. But you can get close. The key is that the side-effect has to be much more granular. Instead of re-rendering a virtual dom for an entire component as a side-effect, the side-effect is changing a single attribute on an element, or updating its list of children.
This means using a template language where one can make these associations between variables and DOM. JSX doesn't work here because its output could be anything.
I am toying with an experimental framework that implements these ideas. I am convinced we can do better than diffing vdoms.
If your datastore exists in your server side rendering application. I would say that "chaotic front end needs" exist in applications that require data from multiple data sources: many different APIs and datastores that need to be independently queried. If that is true, is there really a big difference between having a server side or client side view model that wraps that complexity?
I am saying that without the full power of that data store on the client side (that is, an optimizable query language, update and insert statements) you will always be thrashing your API around to deal with chaotic UI needs.
If you do expose the full datastore functionality on the client side (which GraphQL is a move towards) then you have a different problem: you are exposing your datastore in a fundamentally insecure environment.
So you are screwed either way.
If you have a large, complex web application that integrates data from many different sources, then an API aggregator or view model is essential.
GraphQL is not an attempt to move the datastore clientside.
You don't have to hassle backend for expensive API updates on a heavyweight language that makes exposing an endpoint a pain in the ass (sorry, Java), and you get exactly the data you need in exactly the way you need.
Or am I missing something?
You can check out the docs here:
I don't know why we keep doing it but often times we cover our eyes on purpose and brush off existing solutions backed by thousands of engineers so that it's easier to make our points.
In a nutshell:
in redux the reducer updates the model as: state.counter += 1 ;
All SAM suggests is that this is an unfortunate coupling, you should write it as: // action function increment(value) { return value + 1 ; }
and then present the output of the action to the model:
state.counter = data.counter ;
Redux does not have any next-action-predicate either.
Regarding next-action, in Redux subscribers are called after the root reducer returns the new state. You can always call dispatch from a subscriber.
You and Sam are proving my point by not actually taking the time to understand the existing solutions.
> in redux the reducer updates the model as: state.counter += 1 ;
That's not how Redux code would look, nor is that how Redux state works.
> you should write it as: [...]
That actually looks very much like how you'd actually write a reducer. Can you please clarify how you think this differs from idiomatic Redux code?
> Redux does not have any next-action-predicate
Inventing terms does not aid in advancing a discussion, especially if you do not define them. But reading through the OP, it appears that a next-action-predicate is just a selector, or possibly a selector used to implement what in Redux would be solved my middleware? The description is quite cryptic, but it at least claims to solve a problem which is already solved cleanly in Redux, which rather raises the question of what the advantage it yields is.
I mean this nicely, but: You're not really convincing me that SAM is a different pattern. Perhaps a simple example app? Ideally some small idiomatic redux todo app ported to SAM; that should show the differences (and benefits) very clearly.
It was kinda disappointing to see him fail to properly address tools that were designed to resolve his original concern. He basically decides that GraphQL forces you to "shape your models to your views" (which is false, GraphQL/Relay just collates and trims your models before delivering them to your views). In a sense, it allows him to continue to say "yes" to his frontend developers (which is good from a product standpoint) without adding a ton of custom endpoints.
If you got out of your insurlar JS/FB/Twitter bubble, u will see the anti-pattern that IQueryable become.
It goes bit beyond simple query builder because it can automatically translate for you more expressive queries into SQL (http://www.infoq.com/presentations/theory-language-integrate... ) But I don't think people could define parts of IQueryable in .ascx files and compose it into single IQueryable result of which feeds the components. That's the main idea of graphql.
I'm not seeing all the complexity we see here or in other frameworks is warranted, but clearly there is something going on making this quite hard.
I'd be interested to see fundamental research (and vulgarization thereof) on this.
The difference is that now, more people on both sides of the spectrum are starting to gain insight into the rest, and starting to realize that good "full stack" development is hard. There are also nearly infinite options, and even more opinions.
Angular does have powerful services to transform objects. For example last week a library (ngTagInput) was expecting a list of objects with {id, name} however the server was returning a list of integer id's. It was trivial to replace the id with the {id, name} object in the service, without requiring changes to either the library or the back end - the API is still generic.
You could, for example, create an Excel file -- lets assume these non-programmers know Excel a bit. One column could designate a template, another column could be used for the question. Perhaps a column for materials (e.g. video files or images). I guess the point is clear, you could make columns that do something specific in the app. Add some documentation and presto, you have an API for non-programmers :)
The Excel file itself could be given to a programmer who implements it or it could be uploaded to some automated process that spits out an iOS app. A rudimentary version could for example attach some pre-specified views with some questions and images.
What do you think, is it possible to create an API for non-programmers via some software that they do know?
If I would create my own abstractions it would be good for me but very, very bad for others.
Is this satire?
div class="opacity-'+slider.maskOpacity
Even better once you notice the actual inline `style` attribute two lines up. headdeskThen when new people come in to your project, the learning curve for them will be steeper than Angular - Also you won't be able to hire any 'batteries-included' programmers because nobody will know your framework when they join your company.
Worse, engineers might refuse to join your company if they see that you've built a custom solution from scratch... Chances are that your framework won't be as good as Angular or React.
Maybe you should try Google's Polymer framework? I've tried all the major ones and Polymer is the least 'frameworky' one.
Beyond that, it certainly makes for less code to make the model directly line up with the view, but you create coupling between the two. This seems like a major difference between MVC I've experienced in the web vs desktop apps back in the late 90's - in a desktop app my view didn't rely on the model's code, just on the model's data. But nowadays with rails and spring and django the view is coupled directly to model code.
It has only a few concepts:
* Pages (webpages)
* Tools (components)
* Events
* Users (accounts)
* Streams (data)
Everything is accomplished around these basic concepts. * models maintain a list of "subscribers" that they regularly send certain
messages to, in response to the messages that they receive from the outside
world. This can as always involve the internal state that each process
maintains.
* views subscribe to models and then present a graphical description of the
messages they receive.
* controllers listen to user-interface events from the view, and use it to send
messages to models.
These have transformed mightily in the intervening years; a model these days often refers to some form of schema for data structures which are returned by services; controllers often query those services and provide them to the view; views may define their own service-queries. Often there is no clear notion of subscription except possibly subscribing to events from the GUI, which is the responsibility of the controller; the controller basically handles everything which isn't either the structuring of data or the organization of the display components.SAM appears to be coming from the latter developments and is concerned with an associated explosion: Every view and interaction more or less gets its own service on the back-end, providing a sprawling codebase which resists refactors; they also get their own controllers which maintain them.
In the SAM idea, the model now reprises its earlier notion of managing subscribers and containing business logic: however it is now "dumbed down" from its potentially-very-general Smalltalk definition: the model is instead meant to hold and maintain a single data-structure. (Can there be multiple concurrent models?) The model apparently only receives requests for an all-at-once update, but it may decide to transform its state `new_state = f(old_state, proposed_state)`. Presumably then it again tells its subscribers about the new state if it is not identical to the old state. (Each view is expected to compute the diff itself, probably?)
A "state" in SAM appears to be identified with a "view": a "state-representation" is a function from a model to a DOM. Your GUI consists of a bunch of these, and hypothetically we can diff the DOM trees to better understand what needs to change on an update of the related model properties; the "view" is basically just a bunch of representations of the underlying state with some "actions." These "actions" are not actually parallel processes at all but do take the classical responsibility of the "controller", routing user-interface events to messages to send to the model. The apparent point here is that they should correspondingly be very "dumb" controllers: they just create a transformed version of the data that they received from the model and then send it back to the model as a "nomination" for a possible change.
Finally there appears to be a strange next-action callback which may be part of every "view update." (It's not clear where this lives -- in the "action"?) I am not entirely sure why this exists, but it may be that the algebra of actions without this callback is merely an applicative functor, not a full monad. The essential idea here is that the function apparently can compute a follow-up action if such needs to happen.
If I'm understanding this correctly, then a simple app which seems relatively hard to structure this way would contain:
* a counter stored in a database,
* a button which should ideally increment that counter,
* a display showing the current value of the counter,
* a notification window telling you when your click has updated the counter.
I'm using a counter since it's got a nice algebra for dealing with coincident updates; if someone else updates the counter then your update commutes with theirs, saving the client-side complexity.Without a framework, we would simply define two endpoints: GET /count (or so) gets the current count; POST /increment will increment the current counter and will say "Success! The current count is now: ____", telling you what you changed the count to.
Here it seems like you need three models. First we have the server-side model of what's going on:
server model Counter:
private count, Subscribers
message increment(intended_count):
if intended_count == count + 1:
count += 1
Subscribers.notifyAll()
return ('success', count)
else:
return ('failure', count)
message count():
return count
The requirement that we only nominate new versions of the underlying data-structure means that we cannot just define the appropriate increment service which always succeeds, but must instead tell the client that the request has failed sometimes. Then there are two models on the client side: one holds a list of outstanding requests to increment (updated by actions, retrying any failures) and the other one holds the currently-cached value of the server-side data (because we need to update this by both the former client-model's update events as well as by some automatic process). You would probably condense these in practice into one model, however they are different concerns. The former model, however, is absolutely required, as it provides a way for the "notification window view" to appear and disappear when one of the requests has succeeded.This seems unnecessarily complicated given the simple solution in terms of two API endpoints -- however it does indeed fulfill its desire for lower API bloat and some separation of concerns.
I'll take another look later, but I'm curious if anyone else got much out of it?
The HTTP server is by its very nature a pipelined or layered application. Requests are turned into responses through a series of transformations. They go down the layers as they work their way to your database, and back up the layers as they are built into responses. This is, incidentally, why functional programming is such a great fit for web servers.
Reading it is worthwhile if only for this phrase.
And speaking of the champion, here's a good write up[1] about tfb's helper library 'react-redux-provide' that automatically matches names in this.props with Redux actions and reducer outputs. It's a simple thing, but tremendously reduces the wiring boilerplate for React+Redux apps.
It might be worth the tradeoff in the short-term, but it's the lifecycle TCO of code counting support and modifications over many projects which will validate or invalidate a particular approach (there is also a cost in terms of hiring and learning curve for inventing an alternate convention).
I hope it works out.
I've made an attempt to clarify what MVC is really about. It was posted here before, I appreciate if you read it: https://news.ycombinator.com/item?id=10730047
https://github.com/chenglou/react-motion
Not that every idea has to be novel, but I think the code in this repo provides a far better example of FRP (which SAM is) than that article.
This is what he said: http://www.joelonsoftware.com/articles/CollegeAdvice.html
You may guess what his number one tip is ;)
My number 1 'hack' that I learned from these classes is to eliminate every unnecessary word and be as short and concise as possible. That way, I make fewer mistakes, get my point faster across and I communicate more clearly in general since there's no risk of being long winded. I never do it in HN comments though, it takes a lot of time.
Also, interesting, is the fact that computer engineer "coding" is much more into the state concepts brought up in the article.
https://github.com/tmpvar/defaults
It will fill your option object with the data if it's undefined
var clone = require('clone');
module.exports = function(options, defaults) {
options = options || {};
Object.keys(defaults).forEach(function(key) {
if (typeof options[key] === 'undefined') {
options[key] = clone(defaults[key]);
}
});
return options;
};
Besides the tests and the fact that someone is maintaining it. It's not much, but it's code that doesn't have to be maintained by you[1]: I have discovered a truly marvellous proof of these principles, which this comment is too small to contain.
Of course, I look forward to the day when we can write our models once for both the server and the client, but I've yet to see a "full-stack" solution compelling enough to get me to abandon both Django and Ember.
Ember fastboot seems like it'll address some of your concerns too - it'll allow for initial rendering of a page on the server with the intention of the client taking over after that.
As for FastBoot, correct me if I'm wrong, but right now it supports rendering static pages for SEO. This is not useful for business apps. Rehydration on the client-side (what you seem to be referring to) is still being worked on. But it does not replace the server-side application.
At any rate, eventually someone will bring together the best of server and client technologies in one full-stack package. With all due respect to what's out there now, I haven't seen anything approaching the elegance of Ember and Django.
This way is good for CRUD apps, but may not be the best approach for others.