1. 44

A little report about my experience building an ecommerce website on Racket.

  1.  

  2. 5

    Error reporting during test runs or when I’m manually testing stuff is the most frustrating part of working with Racket.

    Ironic that this comes right before the bit about how great racket-mode.el is, because drracket (the IDE that ships with Racket) handles this extraordinarily well: https://p.hagelb.org/drracket-error.png

    It’s definitely the main thing I wish would get ported to Emacs, but unfortunately I don’t think the rendering engine of Emacs could support that style of overlay.

    1. 11

      Ironic that this comes right before the bit about how great racket-mode.el is, because drracket (the IDE that ships with Racket) handles this extraordinarily well: https://p.hagelb.org/drracket-error.png

      I considered mentioning that drracket might handle some of those things better (although I can’t image it handling every error quite as well as your screenshot shows, unless it does something more than instrument code with errortrace), but I haven’t really used it much because I find it to be severely lacking in many other ways. I don’t think that makes up for the fact that error reporting to stdout/stderr (eg. in your process output assuming you have a long-running process like a web app) isn’t better.

      To be perfectly honest, I think the focus on drracket is one of the things holding back Racket from wider adoption. Despite some of the unique features that it has, it scares off people who are used to better text editors and IDEs. I know it did me when I first looked at Racket years ago.

      1. 2

        I never read about bad things in Dr. Racket. What are they in your experience?

        1. 6

          Objective complaints:

          • it’s slow: scrolling the viewport is laggy within long files, switching between tabs in the preferences pane takes upwards of a second, as do all of the “overlay” features mentioned by @technomancy
          • it’s heavy: it uses upwards of 500MB RAM for even the simplest programs on my machine – I’ve seen folks recommend that you turn off background expansion to lower the RAM requirements, but that just leaves you with a really basic text editor so why not use a better text editor instead?
          • it’s single-purpose so you can’t edit non-Racket languages in it

          Subjective complaints:

          • syntax highlighting is weak: every identifier is highlighted the same way (here’s the same code in emacs and drracket)
          • font hinting seems to be different from every other app on my system (on macOS) for a subset of the UI
          • it doesn’t support OS-level custom keybindings (for example, I have option+f bound to moveWordForward and it works fine in every single app (including Firefox, where I’m currently typing this message), but it doesn’t work in drracket, printing ƒ instead)

          Like I said, though, I haven’t used it much so some of the above might be wrong/unfair.

          1. 1

            Appreciate the review!

    2. 2

      Curious why you chose Racket instead Clojure or another Scheme?

      1. 7

        I think Clojure is fine, it’s just that Racket is a better fit for the way my brain works. I prefer working with concrete data types so I use Racket’s structs a lot and I’m not a fan of the everything-should-be-these-4-datatypes mantra in Clojure. Not a huge fan of the JVM either, having worked with it professionally a bunch. Racket’s pattern matching facilities and its facilities for working with macros are significantly better afaict. Racket has more/better documentation that is more standardized across the whole ecosystem.

        As for other Schemes, I like Racket precisely because it’s a Scheme with a bunch of much needed enhancements and batteries included. You can pry syntax-parse out of my cold, dead, hands.

      2. 2

        Thx for the write up. You also got an A+ on SSL labs test report. :-)

        The javascript code base seems to be small, am I correct to assume that you are doing most of the UI on server-side?

        Also I see that some images are hosted on cloudfare (and there are some cookies) is that something you have chosen?

        Host: media.matchacha.ro User-Agent: Mozilla/5.0 (X11; OpenBSD amd64; rv:67.0) Gecko/20100101 Firefox/67.0 Accept: image/webp,/ Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate, br DNT: 1 Connection: keep-alive Cookie: __cfduid=xxxxxxxxxxxxxxxxxxxxxxxxxxxxx Pragma: no-cache Cache-Control: no-cache TE: Trailers

        1. 6

          You also got an A+ on SSL labs test report. :-)

          Mozilla Observatory gives it a pretty good score as well! (A+, 115/100)

          The javascript code base seems to be small, am I correct to assume that you are doing most of the UI on server-side?

          JS is only sprinkled through for very minor UI enhancements and it’s all very much written the way I used to write JS code ten years ago. I don’t use webpack or babel and the code is merged together and then minified by broccoli. As for vendored JS, I use Quill in the admin for rich text editing, mapbox to display a map to the user after they complete their order and unpoly to enhance the navigation. Here’s what one of my javascript “modules” looks like:

          $ cat resources/js/app/discard.js                                                                                   
          /* global up */                                                                                                     
                                                                                                                              
          (function() {                                                                                                       
            up.compiler("[data-discard]", function(el) {                                                                      
              const timeout = el.dataset.discard * 1000;                                                                      
              const timeoutId = setTimeout(discard, timeout);                                                                 
                                                                                                                              
              el.addEventListener("click", discard);                                                                          
              el.addEventListener("animationend", onDiscardEnd);                                                              
              return function() {                                                                                             
                el.removeEventListener("click", discard);                                                                     
                el.removeEventListener("animationend", onDiscardEnd);                                                         
                clearTimeout(timeoutId);                                                                                      
              };                                                                                                              
                                                                                                                              
              function discard() {                                                                                            
                el.classList.add("discarding");                                                                               
              }                                                                                                               
                                                                                                                              
              function onDiscardEnd() {                                                                                       
                el.classList.add("discarded");                                                                                
              }                                                                                                               
            });                                                                                                               
          })();
          

          Also I see that some images are hosted on cloudfare (and there are some cookies) is that something you have chosen?

          I use the free Cloudflare plan for that tiiiiny extra bit of security I get from hiding my origin host as well as the free CDN. You can read about what that cookie is used for here. CF does act as a CDN for my media, but the origin server hosts the actual images. I have CF pointed to an nginx instance on the origin that serves the media files and reverse proxies to the application.