HN user

lipanski

291 karma

https://lipanski.com

Posts15
Comments36
View on HN

If this is the nano version then let me share the pico alternatives with you:

* BusyBox httpd [1]

* thttpd [2]

* Lwan Web Server [3]

* gatling [4]

I built and maintain a super tiny Docker image (~158KB) for serving static files [5]. My current implementation is based on Busybox httpd and scratch but I also tried out thttpd in the past, which worked well but came with a high memory footprint in some cases. thttpd was used to serve big projects back in the day but it doesn't seem maintained any more. The other two projects were on my list of things to try out. All these projects should compile to binaries <500KB.

By comparison nano-web builds a 18.5MB image on my machine. In my experience you can't go below 5-6MB with Alpine (scratch is the way to go if you can compile statically) and you can't go below ~500KB with Golang or Rust, at least not for serving http requests (C or ASM is probably the way to go).

Note that I'm not saying that small is always better, it probably depends on your use case and there are reasons for using nginx for a static website as well.

[1] https://www.busybox.net/ [2] https://www.acme.com/software/thttpd/ [3] https://lwan.ws/ [4] https://www.fefe.de/gatling/ [5] https://github.com/lipanski/docker-static-website

My favourite is thttpd [1] which is super tiny, battle-tested and actually meant for the job (and only this job). It's available as a package on most Linux distros.

Serving a static folder `/static` on port `3000` as user `static-user` and with cache headers set to 60 seconds would go like this:

  thttpd -D -h 0.0.0.0 -p 3000 -d /static -u static-user -l - -M 60
Even if you've got Python lying around on every Ubuntu server, I still don't get why you wouldn't use something leaner to serve your static files, as long as it's easy to install/configure. Same goes for most of the runtimes in that list.

[1] https://www.acme.com/software/thttpd/

Same here, I basically learned how to write POSIX-compliant Shell with the help of ShellCheck. Shell is not a difficult language to learn but it definitely has its oddities and the different flavours (Bash etc.) only add to the confusion.

What people don't always expect is the immense portability that POSIX-compliant Shell offers you. This thing runs on pretty much everything.

I recently installed ClickHouse (part of my self-hosted Plausible setup) and had to modify a record inside the database. At this point my only knowledge of ClickHouse was that it comes with an SQL interface. So I opened up a client and typed "SHOW DATABASES" and guess what - it showed me a list of all databases. Then I typed "USE mydatabase" and I was connected to my database. I typed "SHOW TABLES" and got a list of tables, followed by "DESCRIBE TABLE users" and "UPDATE users SET email_verified = true" (FYI I was trying to avoid having to set up SMTP credentials for Plausible). I was able to use ClickHouse without any prior knowledge because the authors decided to based it on a well-known and fairly simple standard instead of inventing their own.

It felt as good as building Ikea furniture without checking the manual and it's what user/developer experience should be about.

The Airbnbs 6 years ago

Airbnb enabled a great range of people to see places they might have never afforded to see before. It managed to commoditize travelling in a similar way low-cost airlines did. On top of that, it enabled regions with no previous tourism revenue to have a slice of the cake. Sure, the company made a good profit while there was a profit to make, but their service benefited consumers as well and I think it did leave a positive impact not only on the travellers but also on some of the communities that understood how to balance its pros and cons.

In my experience, automatic eager loading is the most elegant solution to this problem. For ActiveRecord, I'd recommend Goliloader [1] (which is a gem similar to ar_lazy_preload but with emphasis on doing that automatically) while for Sequel, you can enable the TacticalEagerLoading plugin [2].

These tools don't require explicit `includes`or `preload` calls. They can infer the tables that need to be eager loaded through usage (e.g. if you iterate through users and every iteration requests the user's posts, the first iteration will eager load all posts for all those users). This fits really well with GraphQL because different clients might trigger requests for different associations. Automatic eager loading allows you to optimize for all those different cases without writing a single line of code.

The other solutions are either way too explicit or might be eager loading too much. Things like graphql-batch don't even feel like ActiveRecord any more (and for a good reason - it's a different kind of abstraction, meant to batch all sorts of things, including HTTP requests).

There are more caveats when it comes to eager loading, mainly there are many things that can break eager loading. I recently wrote a blog post [3] about dealing with those issues.

[1] https://github.com/salsify/goldiloader

[2] https://sequel.jeremyevans.net/rdoc-plugins/classes/Sequel/P...

[3] https://lipanski.com/posts/activerecord-eager-loading

Give me all users whose phone number starts with 555

There's no magic there, it's left up to you whether you expose such functionality and you are in full control of all fields that make up your API. Most of the time your APIs will reflect your database associations `{ users { posts { comments } } }` which should be indexed anyway. Custom queries on top of that, like a search filter, can be indexed/optimized individually. Resources can be paginated quite easily and you can also enforce a maximum depth when requesting associations, so that you don't end up with requests too large to deliver.

The main problem with GraphQL comes from the many different ways you can use it, which makes caching or eager loading difficult.

There are a couple of points where Crystal really feels cleaner and somehow more expressive than Ruby.

The authors of the language avoided aliases (no more size vs. length or inject vs. reduce discussions) and generally there's only one way to do things (Strings are always wrapped in double quotes).

Crystal has abstract classes/modules/methods, generics and method overloading, three powerful techniques which are missing in Ruby entirely and which can be very helpful in some cases.

You can mark global methods as private and you can also mark classes as private. The latter can prevent users of your "shard" (gem) from accessing such classes, pretty much like how Rust modules can be marked for external use or not.

Constructor arguments can be turned into instance variables automatically, if you add `@` to the argument names.

Marking a construct as private happens inline with the definition, unlike in Ruby where it functions as a divider. This makes your code a bit easier to read and you can group methods in any way you like.

I find the built-in JSON, YAML and XML parsers to be very elegant. For the common use cases, you just have to define normal classes with attributes and include the JSON::Serializable module - this will also traverse attributes in search of serializable types. You can also do more complex transformations with annotations - have a look at https://crystal-lang.org/api/0.35.1/JSON/Serializable.html - but writing an HTTP client for some random API in Crystal feels very natural. On top of that, the built-in HTTP client is more than decent (which I can't say about Net:HTTP).

Generally the standard library is packed with goodies and, though the ecosystem is scarce in some areas, it's usually easy to replace and you can get away with less dependencies.

The inferred static typing which allows for union types is a neat choice - it doesn't force you to write types (most of the times) but it does give you some guarantees. I personally prefer to explicitly name my types, especially in public method definitions, because it helps document the code without having to write anything on top, but it's up to you.

To be honest I'm not really missing the metaprogramming aspect. In large Ruby projects this can easily turn into a mess and it makes searching through your codebase a horrid experience. Crystal does have macros but they have some limitations (they operate at compile-time).

Performance is just amazing and you can also build static binaries.

If you like Ruby, I'd really encourage you to give it a try, at least as an experiment to an "alternative Ruby".

To conclude, here are some code samples (shameless plug, but you can also browse https://crystalshards.xyz/ for other projects):

* https://github.com/defense-cr/defense/blob/master/src/defens...

* https://github.com/defense-cr/defense/blob/master/src/defens...

* https://github.com/lipanski/kilometric/blob/master/src/kilom...

Is Rust web yet? 6 years ago

I spent some of my time building or trying to build various web apps in both Rust and Crystal. The Rust web experience of several years ago was very frustrating and it was partially due to the lacking ecosystem but also due to the nature of the language. The safety guarantees that the language provides are great if you care about that, but they can be quite a pain when you just want to get something out. The majority of web projects fall in the last category. The language ergonomics have improved since (you don't have to do so much pointer juggling any more) but it's still no way near other languages that might only cover these guarantees partially or not at all. Language ergonomics is a very important aspect because it can limit both the development speed of your project but also the speed at which the ecosystem develops.

The performance aspect (aside from WebAssembly, where it has few contenders) is something that can be partially matched by other technologies.

By comparsion, developing for the web in Crystal is quite enjoyable. The language has great ergonomics (I'd say even better than Ruby). The web ecosystem might not be mature but it's blooming and it has you covered in the main areas. Most importantly, if you're missing something, it's very easy to build it yourself. The standard library contains a lot of web goodies, including a very decent HTTP client, a server, easy to use and fast JSON and XML parsers, an OAuth2 client (yes!). The language feels like it was built for the web, which I can't say about Rust.

In the end, what matters is your use case and the trade-offs you are willing to make (development speed vs. performance vs. safety guarantees). If I would have to build a load balancer, I might consider Rust. For a normal web app, I'd personally go with something like Crystal, Ruby, Python, Node.

I'm not sure that's always practical. Consider the average Rails or Symfony app - you'd have to include quite a few files (even if you add entire directories at a time).

One of the most common mistakes I see is not using a .dockerignore file or, better said, relying on .gitignore when calling `COPY` on entire directories. Without a .dockerignore file in place, you could be copying over your local .env files and other unwanted things into the final image.

On top of that, you might also want to add `.git/` to your .dockerignore file, as it could significantly reduce the size of your image when calling `COPY`.

A more subtle issue I've noticed is the fact that `COPY` operations don't honour the user set when calling `USER`. The `COPY` command has its own `--chown` argument, which needs to be set if you'd like to override the default user (which is root or a root-enabled user in most cases).

I wrote up a similar article a while back, though it's focused on general best practices: https://lipanski.com/posts/dockerfile-ruby-best-practices

At the end of the day concerns are just Ruby modules and they are a core feature of the language. They are an acceptable style of programming. It all depends on the task, your team's size/maturity and the hard boundaries you'd like to enforce.

The problem with concerns is that they can easily start leaking logic into other concerns or models and you've only got your team's conventions and common sense (which are all very soft boundaries) to steer you away from this. As a matter of fact, same goes for Rails engines - they make it very easy to call the parent app from within an engine and it's very tempting to do so at the cost of leaking logic and breaking these boundaries.

If your team can agree and stick to a set of conventions in regards to concerns, there's nothing wrong with using concerns the way Basecamp uses them. If you prefer stricter boundaries, there are other patterns that you can follow (like service objects or ActiveJob or events).

I personally use concerns when the behaviour tends to be very generic ("Paginates", "Cacheable", "SoftDeletes") and service objects for anything that touches the business logic.

5G Just Got Weird 6 years ago

As I’ve learned more and more about 5G

Out of curiousity, what's a good source of information on 5G? I assume the standard itself is not the easiest thing to digest so I'd appreciate your input.

https://whoishiring.io which is basically an agregator.

I also like the concept around https://www.honeypot.io (I think it's only available in Berlin though). Once you sign up and add your CV, you get a list of quite detailed offers almost every day, including company name (wow, I know, crazy) and salary range. You can accept or reject them through the UI, by just clicking a button. No endless chain of messages to figure out what company or position you're actually applying for, no horrid misspelling of your name, no waiting for the recruiter to contact the company and check if they're actually interested in your skill set - your CV is presented to the company beforehand so you've already passed their vetting. The one time I tried, I didn't find a job through Honeypot, but I definitely appreciated the experience.

Is it just me or HoloLens sounds a bit like a Hooli product?

All jokes aside, given that the rendering quality improves, this could have interesting applications for scientists researching facial and body expressions in certain environments. It would enable them to replay scenes and emotions which current 2D/3D video fails to capture, especially because it allows you to change your viewpoint.

I doubt this will be a game changer for teleconferencing, mainly due to the oversized device you have to wear, but then again all these gadgets tend to look a bit creepy in their initial phases (e.g. the Google Glass prototype).

Product Hunt is mainly focused on actual products, some of them pretty mature, while Show HN has also been about small pet projects / weekend projects / experiments.

I like them both, but as a developer I'm actually more curious about the experimental side of Show HN projects.

I totally see your point, was my first thought as well, but Product Hunt hasn't really got me away from HN, it's more of a side dish.

If I were to be cynical, I'd say age and wage (and the feeling of knowing it all).

However, contrary to some of my previous experiences, a senior is that person that has an answer to most of your questions (and the disposition to answer them). It's that person in the office that can pull a project or a team on his own on the long term, without major fuck-ups and with a clever solution for all unexpected problems.

And if you're interested in the more superficial description: human resources would call a senior someone who's been mastering his domain for at least 3 years.

when I was younger, Flash was <the thing> in interactive web development and UI awesomeness. you couldn't get anywhere close with HTML and Javascript and Java applets were just about to die. 10 years ago we still had the Flash Festival in Paris, where I saw some of the coolest interaction concepts til now. those things weren't just websites, it was poetry! (and don't get me wrong here, I'm not stuck in the Flash age, but it really was poetry and really amazing UI)

that's about the time I started writing ActionScript and learning how to use (Macromedia) Flash to do some basic animations. I got as far as teaching myself the Flex Framework, almost had a paying customer for a Flex project, but it actually never went beyond the hobby phase. the Flash picture portfolio I wrote for myself is still out there and I love it. it's ActionScript 8.0 but I never had any compatibility issues with any browser or Flash version. I looks the same everywhere. and I bet the compiled swf file, which is still online, dates back to 2003 or something. nowadays thefwa.com has been rebranded to "the Favourite Website Award" - it used to stand for "the Flash Website Award". that's where I discovered group94.com a Belgium-based advertising agency who were writing some crazy ActionScript back then. nowadays their website has gone HTML. it looks boring. and basic. it looks just like all the other agency portfolio websites out there. it used to be funny and clever and poetic. it used to be well... flashy. take a look at the Flash scene 10 years ago and take a look at how web interaction has evolved: nowadays you want something cool, you get it parallaxed... millions of websites all taking on the same design element. the Flash websites I saw were all different in many ways. the Flash world was a place of inspiration.

I don't really remember when I stopped reading thefwa.com (which I used to do on a daily basis). I didn't really notice when Flash got replaced almost everywhere by HTML(5). I just did now. and I feel sorry for it, because Flash used to be (and still is) a great tool and a great concept.

EDIT: I'm not talking here about the mediocre Flash world. there's plenty of bad Flash websites out there. I'm talking about the glamorous one. and in my opinion the glamorous Flash world from 5-10 years ago is still more artsy than the glamorous HTML5 world nowadays.

In my opinion, the hacker who hijacked this guy's Twitter account didn't have had ANY interest in explaining how he got to it, besides creating a hoax to confuse and divert attention. Just think about it, in just one email he puts the blame on both GoDaddy, for doing phone validation over unsecure criteria (like credit card numbers), and PayPal (for giving out the last digits of the card number to a complete stranger). There might be some truth to it (GoDaddy's phone validation sucks and GoDaddy sucks altogether), but I've read the original HN thread and the majority of comments are directed against GoDaddy or PayPal, rather than the real perpetrator. There are a million ways to hijack someone's account - including but not necessary by exploiting flaws of GoDaddy / PayPal - but I wouldn't trust the hijacker to kindly explain to me how he actually did it.

What's the difference between this and the bash '&&' operator? Except for the timebomb flag, I don't really see any difference. Please correct me if I got this wrong.

The '&&' operator, as in which ruby && echo 'found it!', triggers the second command, if the exit code of the first one is 0.

Also good to note, the '||' operator triggers the second command only if the exit code of the first one is different than 0. As in which ruby123456 || echo 'could not find it!'.

EDIT: typo.

I share the same opinion. Appart from that, I'd love to have the opportunity to see and play with the actual codebase before signing up for a job. During my first days with a really friendly and somewhat generous company, I inherited a mind-blowing codebase (well I'm gonna call it "code", but I might as well call it absurd theatre). All the blubber that HR, product managers and team leaders feed you during interviews, gives you like 10% of the job description accuracy you would get from actually reading their code.

Anyway, I think attitude plays a really important role here. A candidate might be able to recite Linux Kernel code by heart, but if he doesn't show commitment or a bit of flexibility, I would never get him on my team. I'm not talking here about an 8 hour long test run. I bet the guy could have negotiated it to 4 hours or something. I gave away 8 hours of trial work once (+ 3 hours spent talking to managers during the other stages) and I never felt bad about it. I really don't get what the problem is here, I was always really eager to show what I can and to impress. It's all about being competitive. We're not pealing potatoes, we're writing code. Show some passion for Christ's sake. Or find a job that makes you happy even when you're not getting paid. That's the kind of job you'd like to keep for the rest of your life.

I can only agree. Do had a really clean, intuitive design. I didn't used it on a daily basis, but - just like latraveler - I was checking out the competition for my company's product a couple of years ago. Out of all the todo list apps I signed up for (and hell, there sure is a lot to choose from), Do was actually the easiest one to use, basically everything was where I expected it to be. It had the perfect balance between the Basecamp feature-rich but complex UI and the glamorous but over-simplified Wunderlist.

Also they must have payed a fortune for their domain, Salesforce probably intends to reuse it soon.

for the .ro (Romania) domains this is not really true. the national domain registrar (rotld.ro) doesn't charge anything for updating name servers. probably the additional fees you're talking about are imposed by some third-party / reseller.

what I also found interesting or at least peculiar is that the Romanian registrar charges a one-time only fee for registering a domain and it has been doing so for as long as I know. you pay 50 Euros per domain but you get to keep it for your whole life or as long as they don't decide to charge on a yearly basis. I'm curious if there's any other domain provider offering lifetime registration?