-
Notifications
You must be signed in to change notification settings - Fork 170
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Server-side web programming #22
Comments
I'm going to CC: @snoyberg on this discussion who knows better than I do about how Haskell stacks against other languages for web app development. Note that the "Mature" rating does not necessarily imply as good as a front-runner, but rather good enough for most use cases. If Haskell were competitive with, say, Rails in terms of feature-completeness and ease-of-use then it would be a candidate for "Best in class" and not just "Mature". Although the post does make relative comparisons to other languages in the descriptions the final judgement for maturity is based on absolute worthiness for the task (i.e. is it "good enough"). Also, the rating takes into account that where Haskell might be deficient in some areas compared to other languages it might be stronger in other areas (like types, performance, and concurrency). So it's also a question of "Is the time/money I will spend compensating for the lack of X in Haskell less than or greater than the time I will spend compensating for the lack of Y in some other language". However, if that were reasoning behind my conclusion I would update the post to make that explicit in my rating. There were other independent requests to add a "Debugging / Tooling" section to the post which would echo your concerns about visibility into performance and interactions with other components and I think that would definitely warrant an "Immature" rating. With those general issues out of the way, I'll address some points more specifically that I have some knowledge about and let Michael or others discuss the points that are outside my area of expertise.
This is actually something Haskell excels at, but not in the traditional approach that you are accustomed to in other languages. The reason you don't see a lot of dependency injection frameworks in Haskell is not due to a lack of effort or interest, but rather because we have alternative preferred solutions that are more idiomatic to the language. The two most common approaches are:
I'm pretty sure that Yesod has a configuration mechanism and while it doesn't do exactly what Symfony does out of the box this seems in principle like something that would be pretty minor to configure.
Yesod actually excels at composable request processing using However, there is a decent chance that I am misunderstanding what you mean by event system so you might want to clarify what you mean here.
You're probably right, and this would fall under immature debugging / tooling, but I'm not entirely sure that this is a dealbreaker for the "Mature" rating. I've deliberately chosen not to answer the other points because I don't know as much about those other areas and I think Michael Snoyman could do a better job of discussing them. |
@thkoch2001 as I mentioned in Issue #24 I think that this may be due to the fact that learning Haskell can be quite difficult at first due to the fact that you're not just learning a new set of words for something you already know, you're learning a new set of thoughts to think, and also a way to understand the "thinkings" you've already thought before. This is not easy because learning is often not easy (but it needent be as hard as it is, and this is changing as we speak). An analogy might be helpful here: If you're used to banging nails in with a hammer, and I give you a nail gun and don't teach you how to use it, you will probably end up trying to hit the nails in with it like it were a hammer. So, it seems we need to teach you how to use the nail gun that is Haskell. One man with a nail gun and the know-how to use it can do the work of 10 men hammering nails with a hammers, but it does take some effort to learn the new skill. Having said all this, I feel your pain. Building a web app in Haskell is just not the same ease of ramp-up as building one in PHP, Node, Seaside (Smalltalk), Rails (Ruby) or Django (Python). Part of this is what I discussed above: it's a new, alien technology, and so the way to do things is new and foreign. However, even taking that into account, things are harder than they are in other ecosystems, even for seasoned Haskellers. With the new stack build tool, and the efforts of those who made it and others, this is changing pretty quickly. The other part of the problem is that the web app dev landscape in general is also undergoing rapid change. We've moved largely from "the server controls all" to having smarter clients of various kinds interacting with a services-based backend. Even the way to build these "smarter frontends" in HTML/CSS/JS is being massively debated, but it seems that a "flow-based immutable data" consensus is slowly immerging (elm lang, ReactJS, what's happening with Ember lately for speed, Om & Om Next / Reagent in the clojurescript world). So, it's not entirely sure what is needed during this period from a "full stack solution". There's currently no "complete" story with regards to a turn-key system in the Haskell world for web development. Yesod aims to be this, but it doesn't address the front end in a great way. Snap also has a story to tell in encouraging component-driven development with their snaplets. However even Rails - an opinionated full-stack story if ever there was supposed to be one - is having some issues with the front end. (The latest Rails - v5 - has an abomination called Turbolinks 3 whereby javascript is used to punch out and replace server-driven rendered HTML. This feels like it might be the wrong approach, driven from a wish by DHH's wish to only program in Ruby.). This being said, it doesn't seem like a full stack opinionated framework is a very compatible idea with Haskell as a language - being that Haskell seems to be about understanding the things that you're making as you're making them, and giving you the power to choose wisely yourself as a programmer. Clojure feels similarly to me, but less so than Haskell. There's a message in both of these languages, and that seems to be "know what you're building, how it runs and what what you're doing when you make something". There are some obvious caveats in this. Some things we're happy to let the machine abstract away, such as Garbage Collection, or in Haskell's case, even execution order and optimisation when it's not important to us (which it turns out is probably most of the time). It's not trivial to build some of the things you mention, though. An authentication & authorization system, email system, environment system, front-end solutions, etc. etc. are tricky problems to solve, and very tricky to solve in a way that makes everyone happy. Design is decisions, and these things imply a multitude of decisions. Having said this, there actually are a few solutions in these places. Also, some of the things you mention are just not relevant in Haskell. In a language where you can pass functinos around as first class citizens, and where functionality is decoupled from data, do you really need dependency injection? Does it even make sense? How would it look any different from Snaplets? It feels to me a little like you might want to broaden your research into the Haskell web dev story somewhat. But you're right, this stuff needs to be "easier to approach" and there needs to be a well explained story there. |
I'm not going to claim that Haskell or Yesod have every single feature that exists in any web framework in existence. That wouldn't be true. However, many of the points raised above are in fact supported by Yesod (and possibly other frameworks, I'm just not an expert at them). However, they may have different names. For example, you mention a bundle system. From your description, that sounds a lot like widgets in Yesod, where you can create reusable HTML/CSS/JS that can perform server side actions and be embedded in arbitrary pages. They're covered at http://www.yesodweb.com/book/widgets. (You mentioned subpages, I think you meant subsites. That's another composability feature, but at a different layer.) Gabriel's already commented on a few of the other bullet points. I think that gives a decent overview of the fact that, even if at first glance you think a feature's missing, it's likely to be there. There's always a learning curve coming from another language/framework, and the differences can seem large. But if you read through the available documentation, get on the mailing list, and try writing an application, I think you'll find the vast majority of your needs are met. |
With all due respect, @snoyberg it seems the following are not particularly well addressed, which @thkoch2001 brought up more or less:
|
@agrafix replied to a question I had on the spock issue tracker a while back which related to and replicates a lot of these questions, with the following:
However, the transit library is experimental and the author has expressed he won't be working on it anymore. |
I'm not going to respond to that list here. If your question is "how do I On Wed, Aug 26, 2015, 8:33 PM www.getcontented.com.au <
|
Some of these I know the answers to. I'll give a more detailed summary of what I know (and update the document, too) later today |
Gabriel: feel free to ask me questions while doing so. I'm happy to get the On Wed, Aug 26, 2015, 8:50 PM Gabriel Gonzalez [email protected]
|
@snoyberg hehe :) Sorry if I came across in a way that bothered you! :) You're free, of course, to do whatever you'd like. I was working under the impression that the document that @Gabriel439 is attempting to build was a way to explain to everyone who cares to know, just what the current state of Haskell is: especially beginners, and non-Haskellers. I think this is sorely needed in the Haskell community if we're to achieve our (I thought agreed-upon) aim of better adoption. I'm not asking you to provide answers on how to do x,y,z in Haskell. I'd personally love to know some of this myself, but I'm asking for the document, not (only) for me. |
@snoyberg I wonder if it's possible to use Yesod's environment features with Scotty... or other web servers... in the clojure ecosystem, it's entirely possible to do this, for example, because things are built as composible blocks. I'd consider that composiblilty incredibly useful and "best of breed" (and from my novice understanding, more in line with the Haskell way of doing things). All good tho. |
BEAM looks pretty cool as an alternative to TH based libraries. Not sure if it's the best tho. https://github.com/tathougies/beam http://travis.athougies.net/posts/2015-01-12-beam-typesafe-haskell-database-interface.html |
The reason I read your comment as not actually looking for how Haskell does things us because some of the points in your list are obviously covered by existing libraries. For example, csrf support is first class in Yesod. For the specific case of environments, the Yesod scaffolding has the ability for both environment variable overrides- which is what I use in practice- and fallback config files for each environment. It includes an example of a separate set of test settings. |
Thanks @snoyberg ... what we're looking to do here, though, is to explain how the points in the list are "obviously covered by existing libraries", and to what degree there is coverage. To explain it. You bring CSRF protection up, but the only time that is mentioned in the document is in reference to Spock. You know CSRF protection is first class in Yesod. And, yes, I know it's there, also, but this document is about telling everyone that that's the case. (Sorry if my hammer-it-home style is annoying, I'm just trying to be clear and obvious). Personally, I don't like the "bundle it all in" approach to things particularly. For this reason, I would not say that Ruby has first class CSRF protection. Rails does, but it's not a separate library in Ruby, and for that reason, you can't really say Ruby has it. You'd have to say Rails has it. In the same vein, if Yesod has a separable library for CSRF protection (whatever that would mean in reality, as it's likely pretty well bound to HTTP request processing), then you could definitely say Haskell has a great story for CSRF protection. Now if you want an example of what I would consider modular CSRF protection in a library at a language level, check out Clojure's excellent Ring anti-forgery library... https://github.com/ring-clojure/ring-anti-forgery Clojure has something called Ring which is based around Ruby's "Rack" abstraction: an extremely lightweight HTTP abstraction - it's basically a map/tuple. All the middleware wraps this. It's incredibly modular. https://github.com/ring-clojure/ring For the "kitchen sink" case: that is, where new users don't really want to know how it works (best of breed defaults, similiar to Rails, but still very configurable), there is ring-defaults. https://github.com/ring-clojure/ring-defaults This architecture is substantially better than a big kitchen sink (monolith?) in a lot of ways, because it's a composition of smaller, simpler parts - this architecture is what the clojure ecosystem is built on. Personally I think Haskell has a massive advantage over Clojure in that it has modularity built in a much more basic level. In Clojure, there are lightweight abstractions, but it's essentially a LISP at its core - that is, all code is data: eval and apply. This means that "all machines are at the same level as the stuff they process", but only until evaluation time. However, because in Clojure all code is data, but not all data is code... that's a massive disadvantage. In Haskell, all data is code, and all code is code... even at the evaluation point... (ie in a runtime system) which means because of laziness, types and currying, there is a lot more possibility to be efficient and modular. There's even more opportunity to have a dynamic system here, but it seems that's currently not the way things are done. (Perhaps this has something to do with not fully embracing the fact that all code is code... when all code is code, and all data is code, you kind of need a very basic AST wrtten in the most base data of the language to allow inspecting of code - which would appear as if a Lisp, but would have one very definite advantage - live runtime inspection and modification possibility) I think modularity only wins out over non-modularity if you also address the "common best practices kitchen sink", though... and clojure does this by providing these frameworks/libraries such as Luminus, which is a "set of good defaults"... it doesn't build a monolith, but rather selects some sensible defaults from the set of modular libraries. I'd love if it wasn't "Yesod versus the world" but rather "Yesod has parts, and everyone uses those parts". If that makes sense. That way, all the nice things in Yesod would be usable by everyone, not just Yesod users. Note there's a chance I don't know what I'm talking about and that Yesod is composed in this way, but if that's the case, then this document needs to explain that, because it is definitely not obvious at this stage. :) |
I agree with @GetContented that this is an information gathering exercise. Yes, it is time consuming and exhausting but it greatly benefits people who prefer to learn in isolation without having to reach out to others for assistance on mailing lists or chat channels (like myself). Here are the answers to some of the questions that @GetContented raised, either from answers within this thread or from my own knowledge:
This seems like a really strange request to me since my interpretation of this is that it would be really simple. You just thread an environment parameter through your program, no different from any other configuration parameter. I get the impression that environment management must have some additional connotation that I'm missing. Also, as @snoyberg mentioned elsewhere:
I hear this requested a lot from Clojure programmers. I'm not sure that it's wise to have a REPL into your production system, for a couple of reasons: (A) it's extremely prone to incidents caused by a cowboy programmer adding a hotfix gone wrong and (B) it leaves no trace so it's difficult for other programmers to understand and maintain (code edits are not logged or under version control so the only way to understand the system is to reset it). Also, Haskell will (probably) never support live editing of code because you deploy a binary and not source code.
Yesod supports this (and I believe it's a library that other server frameworks can use). I know that @snoyberg gave a recorded talk on exactly this subject but I can't seem to find it.
You want the https://hackage.haskell.org/package/lucid ... and @chrisdone's announcement post for Lucid is also an excellent summary of the state of HTML combinator libraries: http://chrisdone.com/posts/lucid
Regarding auto-building on code changes this what the http://www.yesodweb.com/blog/2015/07/yesod-devel This project is basically taking Yesod's
For sending e-mail you can use
Any time you want to see if there are higher-level libraries you can check out this useful reverse dependencies service (also built by @snoyberg): http://packdeps.haskellers.com/reverse/persistent If you go there you can find all the libraries that build on top of Two other libraries you should also check out are
I think
http://www.yesodweb.com/book/persistent#persistent_migrations
My impression was that most Haskell programs used JSON for this purpose (using the
There seem to be several Haskell libraries for interacting with
There is the
I believe
I believe this is provided as a feature by most higher-level Haskell frameworks (incuding Yesod, Snap, Scotty, and Happstack) but I'm not aware of it being factored out as a separate library (and I don't even really know what that would mean)
Basically everything in the "Educational resources" section of the server programming section. |
Thanks, all of that should go into the document, I guess! :) The environment or profile usually manages the database name, can choose different database backiends, which libraries are included, and how they're configured. It's not very simple. REPL access in production is usually about being able to fix incorrect data, or adjust stuff that there isn't an API to do so with the web app proper. That's all. This is not about code changes at all. It's about poking around the codebase and data context without changing the code. What do you recommend in lieu of this? This is only useful when one has a very easy SQL creation tool. Speaking of which, I've looked at the libraries you referred to, but they don't provide anywhere near the high level capabilities of something like ActiveRecord, much as I have complete disdain for it, it's incredibly useful. Esqueleto is incredibly lacking in features compared to AR. I don't understand how Yesod can share code between the backend and frontend given that it currently only really supports either straight JS, or julius templates... I'm taling talking about GHCJS code being shared with GHC code... the same model of data, for example, and using GHCJS code to generate HTML via a front side framework (like Elm, Reflex, etc, but capable of communication with the backend). About the HTML templating, cool, the HTML template story is actually quite a bit better than I'd realised. Apologies there. I wasn't aware of that. Apologies for that. The trouble with auto building on save is that the data context is lost... so, say you're building a web application, and you're working on your "users admin" section, but only when the filter box has a certain thing typed into it, and only when you have three "disclosure triangles" open in your permissions section for a particular user (hopefully you can envisage what I'm talking about)... but the default on-load representation of this doesn't have anything put into the filter box... and all triangles are closed... whenever you save, you get all your data reset back to normal, which means after each change, you have to re-set your data context. This isn't a problem with simple apps, but can become a complete nightmare with complex apps. Mine, for example, has a case where you manipulate potentially large trees of data... Session Store: Not all WebServers run on WAI, unfortunately, so the Yesod one won't necessarily be the best thing here for all cases. JSON/Transport: Transit sits on top of data, and uses JSON as (one of) its transport(s). However, Transit is capable of marshalling other types of data, and being much more efficient than pure JSON. Haskell kind of needs something like this if the front-end to back-end story is going to work well. If you built your data model on your back end and had the same code on the GHCJS front end, then how do you get your data back and forth without resorting to "dumbing it down" to inefficient JSON? It's just not very advanced in terms of what's possible. Because of all of these problems, I'd say that the Haskell WebServer ecosystem has a mature story as at about 5 years ago, but the web has moved forward in a lot of ways since then. It doesn't seem to have a complete story - but rather a fairly fragmented one. Of course, this is probably just my opinion. |
I think @GetContented's approach is somewhat like this. ;-) |
@GetContented I just want to point out that you are evaluating Haskell on the basis of whether or not it has the exact feature set that Clojure has, and by definition that sort of comparison always favor Clojure over every other language. This is the famous Blub paradox fallacy. You are neglecting that Haskell has some killer features of its own that Clojure does not that counterbalance those deficiencies. For example, I could approach Clojure's web ecosystem and say "I don't see any support for static types, type-safe migrations, compile-time prevention of XSS/broken-links/code injection, or STM transactions that support Anyway, the point isn't to say that Clojure or Haskell is bad but rather that you have to weigh the deficiencies of Haskell against its strengths when comparing the two languages. Comparing only the weaknesses doesn't give the full picture. |
@chrisdone not really :) I'm not trying to get help here. I'm pointing out what it's like to be a beginner coming from other languages. That's it. @Gabriel439 Perhaps you misunderstand me. I prefer Haskell. Also, I'm not singling out Clojure here to explain where Haskell is missing things. I go out of my way to use LOTS of other languages. However, if you want to explain the state of the union, it's good to take the good and the bad. It's useful to see the flaws. It's pretty obvious to me where Haskell shines. As you say, there are simply no types in most of the languages we're comparing here other than Haskell. Try doing something akin to equational reasoning in Ruby - you can't even begin, because it's not that kind of language - it's a message-passing language. You can't do equational reasoning with Clojure either, because it has no types. Clojure's core.typed is unfortunately a bit of a joke mostly because of lack of adoption, and the syntax is really ugly (IMO). The Smalltalk Seaside framework has continuation-passing style token session management. Haskell is missing that. Is this a deficiency? Only if you want to use that style. However, in Haskell we only have one reactive front end framework. In fact, I only know of that one front end framework at all. In javascript or coffeescript there are dozens and dozens. In Clojurescript there are half a dozen, some based on ReactJS, others not. I talk about these languages because they're the ones where there are reactive front end frameworks. It's not to point out Haskell's deficiencies other than to explain where we could improve, and it's not just to poke fun at your "favourite pet" for no reason. It's my favorite pet, too. But let's not get caught up in being happy just because we like it. There may be a better way, and if we miss out on that, it'd be sad. As to the server side, there have been masses of advancements in this area, too. Rails's ActiveRecord and ActiveModel affords a level of abstraction over SQL that has hitherto been unheard of. I'm very NOT pro-Rails, by the way. I used it for a few years, but it has some extremely large, obvious shortcomings. That's not to say we can't learn from them, though. These things are somewhat present in Spring and Hybernate, too. Haskell doesn't have such an advanced set of abstractions over the database as far as I can tell. It's a little ironic, given that the language abstractions proper are so incredibly far in advance of, and simpler than, anything either the imperative/OOP or Lisp communities approach. So much so that we sometimes can have a massive difficulty in even explaining what we're talking about! I'm not saying Ruby is better than Haskell here. I'm saying that if you want to do some work with relational databases and you want to model the relationships and work with them, it's harder in Haskell. Take a Haskeller and a Ruby person of 2 or 3 years, and the Ruby person can get more done in the same amount of time because they're working at a higher abstraction level. That's all I'm saying. The Haskeller would also need to know a lot more SQL, I'd wager. To talk of a "complete web story" without talking about the front end is really to talk about the web as it was 3 to 5 years ago. There was no such thing as a front side web application: the JS engines just weren't up to it. That's not the world we live in now, though. This is my attempt at being somewhat impartial. It's pretty obvious you're taking my comments as a bashing, but that's not how I'm intending them. When we are very close to something like we all are to Haskell, though, it's very easy not to see the warts, afresh. I'd assumed that this document is kind of a way to illustrate those warts, as well as to celebrate the things Haskell does awesomely. Anyway, it's not my interest to annoy or bother people. Really. So, if any of this isn't stuff you think is worth discussing, that's cool. I'll be quiet! Just say the word. (It's a lot less effort required on my part). |
Sorry, I misunderstood, then! I appreciate the time you take to discuss this :) I think I have a lot of material for expanding the server-side programming section. I will take a stab at adding what we've discussed here and see what people think |
Don't worry about it. I often come across in ways that I don't intend to, so if anyone should be apologising, it should be me. I'm sorry for my manner. I can be too kurt. It's not a good thing, but it's the way I usually communicate unless I remember and make an effort to be more considerate and thoughtful about other perspectives. Glad to be of help! (and by the way, this is an EXCELLENT thing you're doing with this document, IMHO - kind of gives Haskell a hub for discussion around improvement and issues, etc. but you're obviously aware of that). |
@GetContented In case it's useful for furthering communication, the line that I think caused some confusion (at least for myself) was:
If what you're actually saying is "as a beginner I don't see a single document describing how all of these are addressed," I would have understood that better with a question such as:
I still would probably have pointed you to the mailing list for that, but it wouldn't have implied we needed to get into an argument if I disagreed with your claim that something wasn't provided by existing libraries. |
I'm going to go ahead and post what I have since it's the last day of August (and I wanted to get this out by the end of the month). I will still expand this section later and announce this on my blog at least once a year. |
I can't speak for anyone else, but I'm pretty happy if this issue is closed. |
I'm leaving it open to remind myself to add some points from this discussion to the Server programming section |
Thank you for your sotu post. However as a newbie to Haskell and long-time (and suffering) PHP programmer I can't share your assessment in regard to "Server-side web programming". Haskell is barely usable in this area, IMHO.
Of course I'd love to use a better language than PHP. But the sheer size of the PHP ecosystem in the end leads to the availability of at least a few impressing frameworks and libraries.
When I compare it with the PHP symfony framework, I see the following mising pieces in the Haskell world:
Of course Haskellers tell me that I'm doing it wrong and that I won't need all this stuff in Haskell. But still there's no book that provides me with proven best practices to solve my problems. For example I want to make gitit2 usable for different use cases, different authorization concepts and different ways to render page. I've no idea how to do this.
So I'd consider Haskell to be promising but immature for web app development.
The text was updated successfully, but these errors were encountered: