7 ms·
Where Ruby/Sinatra falls short
- lucisferre 8y agoIf people are looking for a lightweight Ruby webserver, I'd highly recommend checking out Roda https://github.com/jeremyevans/roda https://github.com/jeremyevans/roda More related to the article, the author mentions that routing order is a problem with Sinatra. Is this not common to all route matchers? What different behaviour would make sense? Obviously once a route is matched it should be executed, so is the issue here the way route ordering is done? What order would make more sense than ordering in the way the routes are defined?
- zdragnar 8y agoSome routers- I think hapi in node might be one- match in order of specificity, not definition. Edit: here we go- https://hapijs.com/api#path-matching-order https://hapijs.com/api#path-matching-order
- 33degrees 8y agoThe author is claiming that the order ends up NOT being the order they're defined, but without examples it's hard to tell if the problem is that or that the regular expressions being defined are not working as intended
- bhaak 8y ago"Now imagine not having a classical style Sinatra app, but a modular one." I think the author ran into an issue where files were loaded differently in development mode than in production mode. Likely in development mode only the required files were loaded and the file with the more important routes wasn't. I wonder why that didn't show up in their tests. But I also wonder if they aren't using Sinatra for too large projects. If you have routes defined over several files, it's likely to get problematic. Maybe they should be using a more complete web framework like Padrino or go all the way with Rails.
- ryanbrunner 8y agoEven in a modular project, this seems like a smell. I can certainly imagine load order making things confusing when routes are required in, but I can't think of a good reason why modular projects should have any contention at all between what routes they handle.
- onli 8y agoIt wasn't that setup related. pc-kombo does not need that many routes that I did spread it over multiple files. I generally do avoid that. I wanted to give the specific example at first, but did not find the related commits anymore when writing the article, and in the end if it was really related to some behavior change linked to a version change (or x86 vs ARM) it would not be too useful now. It's meant as an example for the rough edges one can encounter. But the essence is that I had some routes defined using regexpressions, probably like the URL definition for a page in the blog (not saying it was exactly this one): get %r{/([0-9]+)/([\w]+)} do |id, title| And I ran into a situation where on my local dev platform this did not trigger when calling a similar looking route, but on the production server it did. I just remember being surprised that the specificity of the regex-evaluation seemed to change.
- coderobe 8y ago>And besides: If Sinatra starts a server listening for incoming traffic, why does it still seem common to run a regular webserver like nginx in front of that server? This is a common technique used for tls-termination and management of 'virtual hosts', among other things. The mentioned "issues" don't seem to be Sinatra-specific, but rather about the authors shallow understanding of the topic as a whole
- mey 8y agoApache httpd mod_proxy -> a smattering of docker containers
- badosu 8y ago> This is a common technique used for tls-termination and management of 'virtual hosts', among other things. Yes, usually you're not hosting only one application in a server, it's very useful to have the abstraction of a layer on top of many apps. Also, to serve static content.
- adambyrtek 8y agoOne of these "other things" is buffering of slow HTTP requests. Application servers are usually not designed to deal with that and are meant to be run behind a proper load balancer/reverse proxy. This is usually very explicitly mentioned in their documentation, for example in https://bogomips.org/unicorn/PHILOSOPHY.html https://bogomips.org/unicorn/PHILOSOPHY.html
- jrochkind1 8y agopuma does pretty good at buffering slow HTTP requests though. I honestly _don't know_ why we usually put apache or nginx in front of our ruby 'web servers'. But I keep doing it anyway, cause 'everyone else' does, and I don't want to take the time to be sure I don't need to, it works. However, I believe rails deployments to Heroku generally _don't_ put another web server in front. Which, per your point, slow clients is quite exactly why they explained the switch from unicorn to puma as a default web server. https://devcenter.heroku.com/changelog-items/594 https://devcenter.heroku.com/changelog-items/594 It is true that in 2018 web dev has gotten complicated (in a variety of different axes), and if there's a framework/platform that will allow you to not know it is, I don't know what it is! It would probably be one that made a lot more choices for you though (like, say, ruby web server, so you don't need to think about 'oh, unicorn can't handle slow clients but puma can') -- which is the opposite of Sinatra's philosophy -- but then again Rails approach to try to do that has not resulted in something people find easy either. shrug.
- beat 8y agoI find it really interesting that the Ruby language led to two such wildly different, yet equally valid approaches to web apps - Sinatra and Rails. Sinatra is the most minimal web framework I've ever used. It's fantastic for doing quick mockups and small apps. Yes, you will hit limitations. Bicycles are not good dump trucks. And even before you hit hard limits, you're going to find yourself inventing a lot of structure/convention to keep it from devolving into pretty PHP. Rails, on the other hand, is fantastically complete. It does everything for you. Convention over configuration is a brilliant concept, and the self-discovery nature of the ActiveRecord ORM is something that is totally natural in Ruby and quite awkward in other languages. For writing basic CRUD apps (which is much of the software world), it's really hard to beat the efficiency of Rails. And when people whinge about performance... well, so what? Horizontal scaling, friends. Developer performance is much more important than software performance in most cases (especially since networks and databases form the bulk of your performance cost out in the real world). But efficient developers, that's magical.
- kgilpin 8y agoIn my experience with web applications at non-Googley scale, most performance problems are occurring in places like SQL queries, rather than the raw speed of the web application stack itself. Another really common mistake is tasks being performed inside the web request that should instead be offloaded to background job processing. If something is going to take more than milliseconds, it should be a job. If you see a PR where someone is bumping up the HTTP timeout in order to keep their slow processing request from being timed out by the webserver, they are doing something inline that should actually be a job.
- zerkten 8y agoAre there any good books or other resources on building out a system to do background processing? It seems that it's a common task, but there are different approaches.
- ryanbrunner 8y agoThe Ruby world at least seems to have settled on relatively simple Redis backed queues, where you directly request the job to be executed rather than use a more generic message broker. For sure there are more complex scenarios, but if you're just getting started you'll be well served by just reading the docs for sidekiq.
- badosu 8y agoWith micro web frameworks you're doomed to implement a subset of Rails, or have to dig around to find and configure one of the gems usually associated to it. For those that are ok with this, or already have an understanding of the limited scope of your app, I strongly recommend Roda [0], it's a much more straightforward routing system with better memory/cpu usage. I can't find a single instance for which Sinatra can be used where Roda is not a better choice. [0] - http://github.com/jeremyevans/roda http://github.com/jeremyevans/roda
- eropple 8y agoAgreed. Until I wrote Modern[0] - and that was in many ways more of an exercise in OpenAPI/Swagger than anything else - there were few reasons I could find to not use Roda over Sinatra. Grape's also pretty good, but I prefer Roda over it too. Something about writing it feels better. [0] - https://github.com/modern-project/modern-ruby https://github.com/modern-project/modern-ruby
- kgilpin 8y agoSinatra is a great way to build test programs and demos. Once scaling up to a real application I have found that Rails is a better choice because it has a lot of the things built in that feel missing from Sinatra. For example if you are trying to figure out how to add things like flexible initialization logic, security protections, clever MIME type handling, Cucumber testing, and better routing, you’ll find that Rails has these things built in. What you can’t get from Rails is the “one file application” that’s the killer feature of Sinatra. But all those files and directories in Rails are doing stuff that you’ll eventually want.
- always_good 8y ago> And a small issue on top of that: If you define /route, /route/ will still throw a 404. The right solution would be to serve the page on the two routes but set one as canonical source. But you have to do that manually. In most cases you can get away with wholesale removing and redirecting all trailing slashes in middleware.
- astrodust 8y agoRack gets you out of a lot of jams if you know how to use it effectively.
- tcopeland 8y agoThat's the truth. I had a thing come up the other day where a client wasn't including a content type header and thus the body was being interpreted as application/x-www-form-urlencoded. Rack middleware to the rescue on that one.
- stevekemp 8y agoTo be honest I always just define: get '/foo/?' ... That will handle both, although I appreciate I should probably stick a redirect in place to make one the canonical link.
- jillesvangurp 8y agoPart of the issues are with the separation of responsibilities between rack, sinatra, and whatever you use to run rack (e.g. puma is just one of many options here). We had similar issues a few years ago when we still used sinatra (on top of jruby). One of the assumptions baked into rack is that parameters can only occur once. It returns a dictionary of values instead of a dictionary of lists of values (like e.g. the servlet API does in java). So we had some issues with request parameters that could occur more than once because of that. Ultimately we had to grab the raw request and do our own parsing to get that working. Likewise headers are treated the same way. Another issue that was annoying was that rack, sinatra, AND the rack server we used (something on top of jetty that I forgot the name of) each had their own wonky logging primitives and configuration that interfered with each other. So we were getting duplicate log messages with very inconsistent formatting from different frameworks that each assumed to be in control of stdout. In the end some monkey patching (mainly to make rack log calls do nothing) allowed us to log via jruby/java via a proper logging framework on Java so that we could send properly formatted json messages to our logging cluster instead of dealing with unparsable garbage emitted via puts. We even managed to use the MDC, which is a good reason to use Java logging frameworks if you are running on top of jruby anyway. I don't think MDC is a thing in the ruby world. Then there were loads of fun issues with cross site scripting protection in sinatra breaking stuff in subtle ways, double session initialization (i.e. two frameworks trying to set the session cookie), and a few more such issues. I'm assuming some of these things may have improved over the years.
- onli 8y ago> So we had some issues with request parameters that could occur more than once because of that. Ultimately we had to grab the raw request and do our own parsing to get that working. I had to do the same multiple times. Not for this project, but for different ones. Thanks for mentioning it. I should've mentioned it in the article!
- mirceal 8y agoFor me Sinatra is great. It’s the minimum you can get away with in a lot of situations. The whole thing is like 1-2000 lines of code (so totally feasible to actually read all of the code). The limits the author has run into are not necessarily Sinatra limits. The author also wants to do 120mph on a bike which most people will recognize it’s a bad idea. Use the right tool for the job.
- abhchand 8y agoSomeone on HN previously mentioned that every project they've started with Sinatra, they've regretted down the road that they didn't use Rails. I think the complaints about Sinatra are vaild, in that it needs to limit how params are accessed, better startup documentation, etc... But ultimately Sinatra is for building super simple crud apps. I don't even use it for anything that accesses something more than a SQLlite DB. I often use it for serving up basic front end assets and running single page applications that have some small server side component to them. It's footprint is lighter than rails, but so is it's intended functionality.
- nine_k 8y agoI suppose it's a selection bias. You likely heard about projects that achieved some significance, which requires some sophistication which Rails provides. I suppose there's a number of very small, non-public projects that have, say, 10-20 users doing a relatively trivial thing, and are just fine on Sinatra (or web.py, or maybe even a plain CGI script). But they never catch much attention.
- dreix 8y agoFor years I have never looked back. If I had a project that outgrew its purpose I wrote it again, and dropped half of its functionality without looking back.
- ravenstine 8y agoThe answer to points 5 - 8 is basically to use Rails/ActiveSupport. If you're writing an API for a SPA, then Sinatra hardly falls short.
- whalesalad 8y agoThis post would be more appropriately named "Where my knowledge of building web applications falls short" - the title is kinda inflammatory and a lot of the commenters here likely haven't bothered to read it and are just throwing in their two cents on the technologies mentioned in the title. None of the complaints here are the fault of Ruby or Sinatra. One exception could be the trailing slashes complaint. The issue exists in really any web framework, though. Flask, for example, will give you the same hiccup. I tend to defeat it in Flask with `app.url_map.strict_slashes = False` > There are too many ways to access parameters This is a bad thing? The framework gives you flexibility to build your program the way you want, and the way your specific problems might require. > You will need much more than included Well... yeah. This is not a batteries included tool for building websites end-to-end ... it's a simple way to map an HTTP request to Ruby. > Rewriting www.yourpage.com to yourpage.com, or the other way around > Serving your site over https > Redirecting all http:// http:// pages to https:// https:// > Running tasks in the background > Saving data in a database, and reading from it These are definitely not responsibilities for an HTTP -> Ruby library and the first 3 are certainly responsibilities for your public-facing HTTP server (Nginx, etc...)
- skedaddle 8y agoIt's supposed to be more than that. Sinatra is described as "a DSL for quickly creating web applications in Ruby with minimal effort". Entire web applications, with minimal effort. I have not found this to be the case with Sinatra.
- dreix 8y agoThe application is not the server.
- skedaddle 8y agoOf course, I agree. But though in practice Sinatra may be just a library for routing HTTP requests to a Ruby application, it is marketed as a relatively complete environment for building web applications, making a bunch of these criticisms valid.
- hartator 8y agoBiggest thing is something else. Performance of Ruby/Sinatra plus gems needed to make it workable is worse than actual Rails. Might as well directy work with Rails. Better support and more features on top of better performance.
- kposehn 8y agoI've been a long-time user of Sinatra as well as Rails. About 8 years ago or so I decided to move all of my sites onto Sinatra and made a simple file-backed CMS that has scaled quite well over the years. The drawbacks of the approach have been having to write a lot of methods and classes from scratch to handle certain processing data (there is no actual database) but the end result has been something quite bulletproof and scalable to a point, and the experience implementing those features (like TLS, sessions, helpers, etc) has been quite valuable. However, my needs are starting to grow and I think soon we will have to move off of the old framework onto something new as our business requirements grow more complex.
- jdlyga 8y agoRuby/Sinatra is really nice. I wrote a little webapp 10 years ago using it. Faced with the alternative of doing everything in C++, it really made things easier.
- esilverberg2 8y agoMy company runs its entire backend on Sinatra, and has since 2011. We do ~200K requests/min on AWS c5.4xlarges and r5.2xlarges, so we are a fairly significant deployment of Sinatra/ruby. As the sole and still primary maintainer of our production infrastructure, I've been very happy with this choice of tech. I think our problem was made much simpler because, as a mobile app, we basically were building an API. We did integrate ActiveRecord/Support, and today have a massive suite of tests we run in rspec (it's pretty cool, Jenkins will spin up ~50 concurrent EC2 instances running docker, run the tests, and report back in about 15 min). To this authors complaints, I suppose I feel that every framework has idiosyncrasies that you just accept and figure out, and many of the issues cited are felt only once and then not again. Today, running at scale, the main challenges have to do with building and supporting new tests, which rspec is amazing for, and handling application complexity, which we have been addressing using Service Objects.
- jimbokun 8y agoHow does Elixir's Phoenix framework compare for the shortcomings of Sinatra noted here? Give Elixir's commitment to immutability and functional programming, I'm thinking it might be more explicit in some of the places Sinatra has implicit or inconsistent behavior.