Hacker News new | past | comments | ask | show | jobs | submit login
How to Build a Web App with and Without Rails Libraries (shopify.engineering)
185 points by chrisseaton on March 31, 2021 | hide | past | favorite | 60 comments



Not trying to self-promote myself, but I have something similar (creating an HTTP server from scratch) but in Python [0].

I'm a Professor, I teach web development (to BSc and MSc students), and I always go through the "socket experience" before using any framework at all (usually Django, sometimes Flask). This lab exercise and another one for webservices (basically routing and sending json responses through the socket) are quite elucidative for them regarding web apps.

In the end, the message they get is that the internet is all text going back and forth (plus or minus some details).

[0] https://joaoventura.net/blog/2017/python-webserver/


The trick that really opened my eyes was this:

  $ telnet google.com 80
  Trying 142.250.70.238...
  Connected to google.com.
  Escape character is '^]'.
  GET / HTTP/1.1

  HTTP/1.1 200 OK
Then adding a couple of headers - and realising that it really was just text. You can really tell the difference with young developers who've made that leap.


Ditto for HTTPS:

    % openssl s_client -quiet -connect  google.com:443
    depth=2 OU = GlobalSign Root CA - R2, O = GlobalSign, CN = GlobalSign
    verify return:1
    depth=1 C = US, O = Google Trust Services, CN = GTS CA  1O1
    verify return:1
    depth=0 C = US, ST = California, L = Mountain View, O = Google LLC, CN = *.google.com
    verify return:1
    GET / HTTP/1.1
    Connection: close
    
    
    HTTP/1.1 200 OK


I did Tech support at a small ISP a while ago, and this was part of our first day of training. So was sending email via telnet. There was an optional challenge to add an attachment.


I'm old enough to remember the good ole days of "telnet whitehouse.gov 25" and sending email to friends.


I find CGIs very interesting when scaling towards n=1 – they just do a bit of parsing and add no dependencies to your project. And with very few code (and still no dependencies) you get tiny, useful tools (plug alarm!) like https://demo.mro.name/geohash.cgi


Similar to this, upon reading the often recommended book Designing Data Intensive Application, I realize that the concept of a system and the optimization of one is simply a combination of read/writes, storage, I/O, bottlenecks. It's the layers upon layers of work that's been done on it that makes it work the way it does now.


I think it would be easier to just have them look at the network tab of the developer tools of whatever web browser. It will break down requests and responses for you to easily see. I suspect a very small percentage of the web in just plain text. Most of it is encrypted, and if you ignore that, most of it is compressed, and if you ignore that HTTP/2 and HTTP/3 are not plain text.


HTTP/2 and /3 are where "the web" really changes to become just another shitty network protocol. The beauty of HTTP was in it being hyperTEXT; now it might as well be some Novell crap.

I know that there are Reasons and blablabla but at an emotional level it's the end of an era, same to all these sites going React. The web used to be built on simple and easily-understandable tech, and now it just isn't.


>The beauty of HTTP was in it being hyperTEXT

No, HTTP is for TRANSFERRING hypertext. There is no reason that the transfer protocol needs to work in plain text (on top of TCP which isn't plain text either).


Too much abstraction, and not enough diversity. How many exercises could you make around looking the network tab on a browser? With the approach based on sockets, they have to implement the http protocol ( or a subset of it), synchronize the client and server, and if you have a multithreaded server, you get to implement connection keep alive and things like that. The depth you go is much much different!


>How many exercises could you make around looking the network tab on a browser?

I was not suggesting to do an exercise. If the goal of your exercise is to show that the web is built off text being passed back and forth it can easily be shown by just looking at the network tab. From a web development perspective the exact details of how HTTP packets are encoded are not that important. For the same reason a deep knowledge of TCP is not really important.


Yea, I'm a big support of that approach.

My introduction to web programming was raw PHP and it removes any illusions about this stuff being fancy.


This is still my favorite way to garner a path forward in a language / ecosystem. Remove the fluff at first and - if you reinvent the wheel, at least you get to see the power (or lack thereof) of the language - then start digging into paradigms and libs offered to help you grow with.


So your students do not have a networking class where this (not the programming part) should be taught in the first place?


They do have since last year (it used to be after my class, on the third year). It’s called Computer Networks and they learn things about configuring network hardware, OSI layers, etc. However, the “enlightenment” comes not from all the talk in that class, but latter when they start messing with the sockets, sending text back and forth, implementing chat services (and their own adhoc protocols), until they implement web “things” using only text (through the socket) and a browser..

Granted, not everyone of them will really understand all the nuances of what I try to teach them, but hopefully they’ll get some of it, and be better professionals than without that knowledge.


Simples, rápido e eficaz!


>Building your own Ruby web application from scratch however isn’t only educational—I’d argue that it’s also a rite of passage in a Ruby and Rails developer’s career!

>Just kidding.

Well, perhaps it should be? It's a pet-project level of software alright, and it's got a million issues; but I'd argue that dealing with HTTP and HTML at the lowest level is the best way to internalise the foundations of web development.


I think that every software developer should implement an HTTP server from nothing more than sockets as part of their learning journey. It's a great way to validate what you've learned, and gives you good experience with implementing usable software to a specification (in this case, RFC 2616).

I have fond memories of implementing one in C (complete with multithreading and request queuing) at university. I found it immensely satisfying, I felt like I was Tim Berners-Lee back in 1990!

That knowledge came in handy some years later when I worked building a TLS intercepting proxy (basically mitmproxy, but not) as part of an automated testing tool. That job really validated why I studied computer science; I had all the prerequisite understanding to jump straight into the task from day 1.


... and a good resource for network programming is the classic "Beej's Guide to Network Programming": https://beej.us/guide/bgnet/


Writing my own HTTP server in C++ and passing it through to Google’s V8 and allowing me to use print() to output from JS was very educational for me.

At the same time NodeJs came out (:


This is how we learned Ruby at bootcamp. The problem was that once we got to the more complex Rails parts, the instructors didn't have the time to fully explain it so it was explained as "Magic, don't worry about it too much" which was extremely frustrating


I believe we should really dial down the usage of the word "magic". There are some parts of Rails that feel "magical" as in "surprisingly easy to use" or "very convenient", but it's nothing like "magic that nobody understands". You can always read the actual implementation in your IDE, and Rails code is nice and readable with comments and examples. It's just as easy or difficult to reason about as other complex codebases. I don't remember myself ever hitting a wall and still not understanding what's going on two hours later.


Agreed, rather than magic we should call it what it really is: a massive amount of introspection on the name of things creating implicit interfaces that reach across layers of the application resulting in some of the nastiest, brittlest, most highly coupled code you will ever write.


As a huge Rails fan... I wish I could refute this. ;-)


same with Django


Sounds like dark magic.


> You can always read the actual implementation in your IDE

Doesn't Rail's use of metaprogramming mean that often there isn't a simple static implementation of a method in the source code that you can go and find?


Yes and it makes moving through any non-trivial rails codebase a total drag.


In fairness they've been moving away from a lot of those methods. For example the whole find_by_<attr_name> dynamic methods have been replaced with find_by(attr_name: value).

And while you can't find the method code itself, for example the generated code to access a has_many relationship, you can pretty easily find the meta programming that will generate it by following the class method name.


Yes, but it just implies that you cannot rely on grepping the source code. You know the relevant "method_missing" implementation is somewhere, and you can make an educated guess as where to look for it.


I think I’m pretty well informed about Ruby metaprogramming but I still really struggle to read through the magic sometimes. I can appreciate it’s somewhat impenetrable to beginners.


Yea, but the documentation of said metaprogramming is generally quite comprehensive (with some exceptions).


I am with you on this. What's magical in Rails? It imports classes for you by name based on their file path, "resources" routes to one of seven methods, templates are expected to be in a directory and named based on controller name and action, it defines methods on models for you based on the column names in the database, it runs files you you put in the initializers directory. All of this stuff is convenient, gets rid of boilerplate, and isn't hard to understand.


I've been a Rails developer for half a decade now, and I wish I had the time to list all the occasions where I've just about thrown my MacBook out of the window trying to do something that Rails wasn't specifically built to do, or been shot in the foot by ActiveRecord trying to be too smart for its own good. Solving autoloading problems is always a favourite too.

I enjoy using Rails, but sometimes it's a pain in the ass, and usually because it tries to be too clever to reduce the amount of boiler platey code you need to write. In terms of code management, I'd much rather have explicit dependencies. Less `belongs_to :thing`, and more `belongs_to :thing, foreign_key: 'thing_id', klass: Thing`. Makes refactoring and code navigation so much easier.

Also, pre-Rails 5, the defaults for DB migrations and relations were trash.


Of course it no longer seems magical when you understand the implementation. The issue is understanding the application without working your way up from the inner bowels of Rails source.

Things auto running and importing themselves seems magical because no other mainstream language does that


When I get a chance, I try to dig into the "magic" parts of the tools I'm using.

I've wrote a bit on this on my blog in the context of creating a (nano) web framework similar to Rails [1] and a (nano) http client library similar to requests [2].

I find this to help assure me that if I have to go one layer deep in abstraction I'd still be able to learn how it works.

[1] https://mhasbini.com/blog/lets-build-a-web-framework.html

[2] https://mhasbini.com/blog/lets-build-an-http-client.html


Realistically you generally won't have time to fully understand how most things work though.


I know, and accepting that frustration is part of becoming a developer, but there are others schools such as Lambda where you do go into more depth because its 9 months instead of 3


That's why I abandoned RoR early..


Without rails, I usually use any of the other rack compatible frameworks, such as roda, sinatra or padrino. This article is conveying the message that,without rails, "in the beginning, we had TCP sockets.."


>Maple is yet another software developer who made it without a formal education in CS. She currently works on the TruffleRuby team at Shopify where speedy Ruby code isn’t a fantasy.

Interesting Shopify is sponsoring both TrufflyRuby and YJIT on MRI.


It's always good to hedge your bets.

The two represent the common dichotomy between a reimplementation that potentially reach much higher performance, but will continuously have to battle for compatibility, and an in-tree development that will be limited by backward compatibility etc, but that if merged would be guaranteed to stay up to date.

Maxime explains this well in her YJIT talk [0], and it's the same with other languages such as Python, where PyPy is in most cases much faster, but tend to lag a version or two behind.

[0] https://www.youtube.com/watch?v=vucLAqv7qpc


Has anyone here extensively worked with Rails and then gone on to work heavily with Node/Express, or vice versa? Would love to hear your overall experience and thoughts between the two.


Learned to dev in Rails, went to work in big tech building internal tools in Python (mostly Flask), Node, and Go, and am now happily building my own startup in Rails.

I honestly am baffled as to why anyone would not choose rails for most web apps, let alone basic CRUD apps. Maybe Django would be an alright substitute, I just dislike Python as a language/ecosystem. And the Rails core and gem ecosystem is just so mature at this point, any new feature you need is just a gem install away (hyperbole a bit).

In the end, it's not a huge deal which stack you go with and great, successful companies have been built on all of these and even weirder stacks. Just wish the world settled on one so we could double down on the tooling around it :)


"Baffled" was a bit strong I guess. I enjoy a lot of different language/ecosystems (.net, erlang, typescript if you can call it an ecosystem) and see lots of reasons why you may build on them.

Also recognize starting a project with what language/tools you know best is often more important than picking the most optimal one for the job.


Well, same reason you don't like Django, I just dislike Rails (ruby is aight).


> I honestly am baffled as to why anyone would not choose rails for most web apps

Maybe it's the insane memory requirements of Rails leading ot large AWS bills. It can be worse than running a JVM for a fraction of the performance. Rails didn't go out of fashion for nothing.


I worked with Node/Express for a hobby site, and I'm building my next project in Rails.

The difference is.. Oh my!

Rails makes developing so much easier and faster. Maybe I'm dumb, but I'm so much more comfortable with batteries included and developing products the idiomatic way.

With Node, I felt like I was reinventing the wheel for every feature I wanted to add.


I've been with Rails since about the beginning. I prototyped a rewrite of a production web app in the 0.x days, and decided it wasn't ready yet. (Hey, it WAS pre-1.0.) I got back to it in the 2.x days, and it's been my main tool ever since.

I just looked at the page for Express, and the sticking point is in the title: "unopinionated." I WANT a HEAVILY opinionated stack. I LOVE that I can write 1 line of code in 3 specific places in the Rails directory tree to accomplish something that would take me literally 300 lines of raw Java and Typescript in an Angular world. Some people hate it; that's their prerogative. But this is the difference between Rails and so many other stacks: opinionation.

Yes, it takes time to learn where to put stuff. If that irks you, I'd recommend staying away from Rails. The opinionation is what allows me to leverage the stack to be as productive as whole teams of people banging away on Java.


I agree. I believe the phrase they tend to use more is convention over configuration.



Regarding Java: Spring Boot is highly opinionated and also allows you to do stuff with very little LoC.


I was USING Spring, and it was STILL taking 100x the code to write a simple CRUD app in Java/Angular than Rails. You can say, "You were doing it wrong," and you may be right, but I researched examples so hard that I finally emailed the author of jHipster, and got a lead to a GitHub repo I hadn't found in months of looking. It was great, except that it was so out of date, it wouldn't work in current versions of Angular. If Spring is what passes for "opinionated" in the Java world, boy, do I have a bridge to sell to you.


Does anyone have an opinion that's strongly in favor of Node/Express and why? May be once past the MVP stage, Node/Express was a better choice for xyz reasons - I'd love to hear what they are.


I like node, but the only arguments I can find for it are 1) just one language/ecosystem for frontend and backend and 2) node can handle more concurrent connections per MB of ram.

I agree rails is better in every other aspect.


I’m building an app in Objective-C. It is shares code on Mac, iOS and server and I’ve done it with the express purpose of learning every single little bit of the stack. (In part, to discover why Smalltalk didn’t make it.)

I just finished a class I call GTKManySocketManager which abstracts away over the “polling” functions (poll/select/epoll).

I wish I knew it was this easy when I learned Javascript.

I hate hunting a library to do something for me—and, when I do find code I want to use, it is almost always best to modify it.

Love it. Long live the socket. Build your own stack because it’s worth it’s worth it.


Really enjoyed this, but I'm surprised by this line of code:

  loop do
    client = server.accept
An infinite loop to listen for incoming requests? Is that really the right way to do this? Wouldn't this cripple your server eventually?


Presumably accept blocks, so your application would effectively pause at that point until a request needs to be handled. The loop brings the application back to waiting once the previous request is handled.


Ahhhh, that makes sense. Knew I had to be missing something. Thanks!




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: