HNHacker News
TopNewBestAskShowJobs

linkdd

2,632 karma · joined June 19, 2019

email: david.jose.delassus@gmail.com

  - https://link-society.com
  - https://krouter.cloud
  - https://flowg.cloud
  - https://linkdd.github.io
  - https://david-delassus.medium.com
submissionscomments
linkdd··on Why JSON Isn’t A Good Configuration Language (2018)
> with terrible dependency management like Python

Ah yes, because writing a requirements.txt is complicated, writing a pyproject.toml is complicated, or distributing your app with pyinstaller is complicated.

The Python ecosystem has many options that solve dependency management, this is what makes the standard evolve (like the PEP about pyproject.toml which is now a standard). This is healthy, and installing Python deps, even native has never been a problem since the wheels package have been standardized.

Can we stop with those obsolete claims that Python packaging is a mess? The package format barely changed in the last 20 years, and every solutions rely on setuptools and/or pip.

linkdd··on Why JSON Isn’t A Good Configuration Language (2018)
Expressions that will be evaluated at runtime are just strings, no?

  {"rules": [
    "x > 1",
    "x % 2 = 1"
  ]}
So you will have an "expression parser" to parser your rules, validate them, and execute them. But at least you do not have the edge cases of everything else.
linkdd··on Why JSON Isn’t A Good Configuration Language (2018)
In C++ you get the great https://github.com/nlohmann/json

In Rust you have the amazing serde with serde_json but at this point, you can use toml which is also based on serde. I consider serde as being standard.

In C you have the lib jason which is very good.

In Elixir, I use the compile-time configuration (config/config.exs) with environment variables for production, but that's because in the end, my Elixir system is in a Docker container, running on Kubernetes, with a ConfigMap defining the environment variables, so in the end, it's YAML (or JSON).

linkdd··on Why JSON Isn’t A Good Configuration Language (2018)
The question I must ask then is:

When does a key-value configuration format not meet your needs? Using a scripting language is still about setting key/values.

No, I claim that writing your own is *never* an appropriate choice.

So "think long and hard and then say no".

linkdd··on Why JSON Isn’t A Good Configuration Language (2018)
> Write your own

No.

No.

No no no.

Definitely no.

I wish for a standardized configuration format so that I don't have to learn a new format for each software. At least JSON, TOML (and INI) and YAML are widely used enough so there is little chances that you don't know them.

linkdd··on I think I found a perfect project for myself
> "Don't do it, not worth it"

This might be the worst advice a human being can give to another.

I'm glad for you that you brought it back to life and got to work on something you enjoy.

linkdd··on Async Rust doesn't have to be hard
This is nitpicking, I never said that.

There is still no explanation for what "mess" means, but I don't think it means having multiple competitors providing an implementation.

The fact that there are multiple async Python libraries means that the internals are generic enough to allow that. From what I understand of Rust, there could be another "tokio" as well. And they would not necessarily be compatible either.

This is like saying "You can't use a Django model with SQLAlchemy".

linkdd··on Async Rust doesn't have to be hard
GC-less languages would have to break backward compatibility to implement lifetime/ownership management.

Rust's goals do not fit every single problem out there. As the author said in their articles, Rust is not a general purpose language.

Rust makes you care about many subjects that are solved in an opiniated way by higher-level languages. It wants you to be explicit about those problematics, it wants you to carefully consider the implications and make your own decisions. Rust made me realize that nothing is trivial: even `printf()` can fail.

Certainly, this is not a good fit for the "don't be afraid to break things" philosophy.

But when you are in a field where you care about that, and you need the safety, Rust is actually, to my knowledge, the only tool that can help you.

Rust is complex, because programming is complex. Other languages are simpler, because the decisions have been made for you, and you can only accept it or use another language.

For C and C++, you need extra tools to get to the same level of confidence about your code (just look at the SQLite toolchain/test suite).

You can criticize Rust, just like you can criticize anything. You just have to be constructive about it.

You'll never see the following comment being upvoted:

  Rust syntax is rotten garbage, it's unreadable.
Why? Because it's subjective, it is definitely not constructive.

But the following comment might be upvoted:

  Rust is a complex language that is difficult to approach for a newbie.
Because it acknowledges the problems Rust is trying to solve.

None of those hypothetical comments are praising Rust.

linkdd··on Async Rust doesn't have to be hard
You mean that acknowledging the strengths of a technology and adding constructive criticism is not downvoted while claiming that "it sucks" without any argumentation is?

Who would have thought...

linkdd··on Async Rust doesn't have to be hard
I'd like to have some clarification on the following claims:

  - Rust async is a mess
  - Python async is a mess
What does "mess" means here?

I have been writing Rust code for a few months, and Python code for more than a decade. I have to admit that I do not know the internals of the Python's async model, but as a "user", I think that trio (and asyncio with 3.10 / 3.11 is getting better) is really great.

The ability to call `trio.run` / `asyncio.run` anywhere to start an async loop does not "contaminate" the async/await keywords up to the entrypoint. Which is great.

In Python, calling an async function returns a coroutine object (that can be awaited). In Javascript it returns a Promise. In Rust it returns a Future.

From the "user" point of view, it's all the same. And I don't know many developers who are interested in how it works under the hood, because (like in math/physics/science in general) it's very useful to sit on the shoulders of others.

If I understand correctly, Rust gives you the tools, and the "shoulders" belong to the library developers (like tokio). Which is fine to me.

So, I really do not understand what "mess" means, what it refers to, and what I (as a "user") can do about it. Also, if the internals change, how will this impact my code?

linkdd··on Dangerous Gift
And if you're responsible for fraudulent charges on someone else's credit card, you can get into a lot of troubles.
linkdd··on Dangerous Gift
The domain name must be paid by someone. After the transfer, if the employee is not up to date with their inbox, they may end up paying for something they did not consent.

Is there really no legal basis to sue someone because of this? Is that clearly not malicious behavior from the one who transferred the domain?

The domain could be haha.com it would not matter.

linkdd··on Dangerous Gift
Either way, I think it's irresponsible to target a random employee and throw journalists at him.

No, nobody deserves "reputation damage" for the misbehavior of their company (and here, the one at fault is another company).

linkdd··on Dangerous Gift
B. And then get in trouble (or sued) for diffamation once we discover that the domain was initially registered by you.

EDIT: Being downvoted because I'm against public shaming, way to go HN! Go on, downvote me.

linkdd··on Ask HN: What Do You Want?
Well, it won't be only debts, there are some housing properties with it. And you can't refuse only part of the inheritance, either you refuse it all, you accept it all.

I should have said "mostly" and not "only" in my first message.

linkdd··on Ask HN: What Do You Want?
> write a video game where your enemy player is a neural network that slowly but surely learns how to beat you.

This has already been done: chess

linkdd··on Ask HN: What Do You Want?
I want to live, that means:

  - not being forced to work 2/3 of my time
  - being able to eat, drink, sleep, be warm at all time
  - being able to work on whatever I want, even if it's useless, especially if it's useless
  - being able to travel, meet people, have quality time with loved ones (meet more loved ones?)
  - not having stress, anxiety and chronic depression
Unfortunately, this requires a lot of money, and getting a lot of money requires either substantial inheritance (I will probably only inherit debts) or a shit ton of work, which is stressful.
linkdd··on Ask HN: What Are You Working On?
Kubirds[0], a Cloud Native Supervision Engine.

In the Cloud, monitoring and supervision is all about metric collection and analysis. The good old days of alerting (with tools like Nagios, Icinga, Zabbix, ...) seems to have been forgotten.

IMHO, numbers (metrics) are good for machines, not humans. Alerts provide a very simple way of detecting what's wrong. This is why CI/CD tools have a "Green/Red" status for their pipelines (hello Jenkins, Github Actions, Gitlab CI, ...) and you could build "weather dashboard"[1] representing the current state of your infrastructure.

I (and many coworkers at the time) found that scaling a Nagios or equivalent is unnecessarily hard/complicated. You basically have to maintain 2 infrastructures, your production and your monitoring. It takes time and energy.

Kubirds is a solution for this. It is a Kubernetes Operator, built upon TektonCD[2], so your monitoring will scale along your Kubernetes Cluster. It provides alerting with 4 states (success, failure, regression, fixed) and notifications in a Plug'N'Play way. You put your supervision workload in Docker images, write some simple Kubernetes resources and voila! Your supervision is up and running.

This implies that supervision can (and is) more than just monitoring. Everything that must be run periodically and whose status is something you care about, is a supervision workload.

We are currently using it to run our monitoring infrastructure, and to build a trading bot (not for crypto) with a partner. And possibly other use cases in the future[3].

[0] - https://kubirds.com

[1] - https://kubirds.com/img/screenshots/dashboard-weather.png

[2] - https://tekton.dev

[3] - https://1-click-notify.carrd.co/

linkdd··on Flask Mega-Tutorial (2017)
It's a personal preference.

When I'm onboarding on a huge code base, someone from the frontend reports a bug, I'm like "ok so where does this URL go?", I open the urls.py (which can be split with include), and from there I navigate to the relevant piece of code quite easily.

But with routes as decorators, you need to know the structure of the code beforehand. Which can take some time if you're onboarding a new project.

IMHO, having the route next to the code managing the request does not add useful information to the code being modified.

Also, thanks to django-flags (a feature flag django extension), I can easily enable/disable routes with feature flags in the urls.py without overwhelming the "request handler" with irrelevant information.

But that's only a personal preference.

linkdd··on Flask Mega-Tutorial (2017)
Which is why I put all the logic into a single place.

Extra methods on Django Models? Nope. A function in my business logic package which takes a model instance as parameter? Yes. Models should only contain data.

Huge views that do more than one thing? Nope. A function, or a class, in my business logic package which takes the request data (POST form, GET query string) and returns the data to feed to the template and/or the "state" needed to decide which template to render? Yes. Views should be small.

Also, split your templates, don't be afraid of `{% include %}` (which works well with HTMX as well).

This methodology also have another huge advantage. If you need to walk away from Django, you can. Your business logic won't change that much (there are not many difference between a Django Model instance and an SQLAlchemy model instance, or even a MongoEngine model instance). Your business logic knows nothing of HTTP or serialization.

Django, and Flask or any other framework are just the glue between the WSGI/ASGI and your business code.

If your code is async but your web framework isn't, you can still put a `asyncio.run` or `trio.run` inside your view, and you won't have to change a thing once you switch to an async web framework.

Basically, I use Django for:

  - the ORM
  - the Forms
  - the routing with urls.py
  - the settings management
  - the templating engine
  - the builtin User system
  - the builtin admin website
  - the vast ecosystem (django-anymail, django-tailwind, django-money, django-flags, django-social-auth, ...)
What I dislike about Flask is:

  - routing is tied up to the views (via a decorator)
  - the request object is a global singleton instead of a function parameter
  - no builtin admin website (this is just so useful to get things going at the beginning)
  - there is a lot of boilerplate to make the different extensions work together where django is just about adding a string to INSTALLED_APPS
linkdd··on Flask Mega-Tutorial (2017)
Like I said, you don't need class-based views if you split your code correctly.

You have a function, which takes a request and URL parameters, and returns an HTTP response. You add some decorators to require an authenticated user and/or some permissions. That's it.

This is no different than flask views.

Mixins are an OOP pattern that promotes spaghetti code if not done carefully, especially in Python where there is no encapsulation.

ViewSets are from the Django REST Framework, this is simply all the boilerplate code that you copy/paste hundreds of times. And even that, you might not need it if your API is different enough from your database schema. Even more if you don't need an API.

There is nothing "magical", every single framework have a happy path, you should follow it if you decide to use this framework.

And no, Flask is not a framework, it is a library, much smaller scope, much more boilerplate code that you need to copy/paste, or you build your own framework on top of it.

Flask is about the freedom of choice while Django made the decisions for you 10 years ago. Having some experience with Rails, SpringBoot, Phoenix, Symphony, Laravel, Flask, Express, etc... it turns out that I don't want to make those decisions every single time, for every single project.

linkdd··on Flask Mega-Tutorial (2017)
That's because you should not fight it.

I have some tips I use in all my Django projects:

1. Split your settings.py in multiple files

This is inspired by Elixir's compile-time config per environment/release/etc...

Instead of a huge settings.py, I have:

  settings/__init__.py : Import the correct settings
  settings/core.py : The stuff that Django generates and that you touch almost never
  settings/base.py : The basic settings of your project (your apps, middlewares, ...)
  settings/envs/dev.py : Development settings
  settings/envs/prod.py : Production settings (read from env vars, the 12 factors app way)
  settings/envs/test.py : Test suite settings
See my gist as an example for the `settings/__init__.py`: https://gist.github.com/linkdd/4aac2c2efc4a51af6ca4b05f395de...

2. Separate your business code from your Django apps

In most project, I have the package `myproject.lib` which contains all the business code, easily testable and mockable. Then I have the Django apps in `myproject.apps.<appname>` which imports from `myproject.lib`.

This allows you to make your views quite small because all the logic is not there.

3. Most of the time, you don't need class-based views.

A small function which call your business code and render a JSON document, or an HTML document is more than enough. Django provides many function decorators that are easier to reason about (login_required, permission_required, require_http_methods, ...).

4. You might not need an API

Server Side Rendering is coming back into trends, huge SPA that are heavy on the client's resource are becoming less frequent. Then, why would you need a REST/GraphQL API?

You can work with HTMX, Django Forms, small views that call your business code and return some small rendered template, then sprinkle some Alpine.JS (or jQuery) on top of it, and you get your SSR SPA that scales well enough.

5. Deploy with gunicorn and whitenoise

By default, Django won't serve staticfiles in production, you need to distribute them via a CDN. Which is a bit more complicated to deploy. Instead, use Whitenoise to force Django to serve staticfiles but with the correct HTTP cache headers so services like Cloudflare can take over after the first request (usually done by your E2E test suite by the way).

Then you only need one Docker image, one gunicorn, and if you deploy in Kubernetes, one Ingress resource.

6. Use django-anymail

This is, by far, the best library out there. I usually make a mailjet account, add my API key to my settings, and use the mailjet backend of django-anymail. No SMTP setup required.

All of those tips might seem obvious, but they get you far, very far. Also, IMHO the urls.py from Django is vastly superior to the route decorator from Flask.

TL;DR: Don't fight Django, embrace it.

linkdd··on Ask HN: Why the web lately is all about JavaScript?
Like htmx[0]'s boost attribute?

I've been building a webapp with Python/Django and HTMX, it works like a charm.

[0] - https://htmx.org

linkdd··on Ask HN: How do you keep up with “solid understanding of XYZ^2” requirement?
Ah my bad :) This is why I dislike acronyms.
linkdd··on Ask HN: How do you keep up with “solid understanding of XYZ^2” requirement?
> then you're probably still junior in that field

That seems to be the point of OP, if I'm not mistaken "JD" means Junior Developer

linkdd··on Ask HN: Elixir as a First Language?
> A hello world can literally just be a single line

Yes a bazooka can kill an ant. Does it make it suited for the job?

> things like immutability, pattern matching, anonymous (aka lambda) functions, etc

Immutability is easier to understand than all the problems that arise with mutability. Also with Elixir, unlike Erlang, you can rebind a variable, which does not break mutability and yet gives you some liberty with what you're doing.

Pattern matching might be the most natural thing in the world:

| I have this on the left, does it look like this on the right?

vs

| Bunch of if/else/switch/... that basically answer the same question

Since I tasted pattern matching in Erlang/Elixir, I just feel limited whenever I go back to another language.

But while those features might be nice and all, once you start searching about Elixir, the literature/forums/chats will be all about OTP, best practices, gen servers, distributed systems, and all of that. Because that's what 99% of the people using Elixir are doing.

Just like starting with TypeScript, one might expect to see a lot of Javascript thrown in the mix.

This will only confuse the newbie because they will not know what they're are reading.

linkdd··on Ask HN: General Purpose Templating Engine
I'm not sure if it fits your description, but a while ago me and my associate made https://github.com/link-society/gotempl
linkdd··on Ask HN: Elixir as a First Language?
Erlang/Elixir is best suited for large, long running, distributed system.

Why? Because it has all the tools to handle such complexity, but you still need to understand it.

Someone who has never developed anything serious, or does not know programming, surely don't want to start with implementing such a system because they would not know what is the complexity, what is required, what are the footguns, etc...

By following the principle "use the right tool for the job", elixir is not the right tool to write "hello world".

My subjective answer to your question is: no it's not a good first programming language.

My bonus point: But down the line, you can only benefit from learning it.

linkdd··on Talos Linux is a modern Linux distribution built for Kubernetes
From the website:

> Talos runs in memory from a SquashFS, and persists nothing, leaving the primary disk entirely to Kubernetes.

Also:

> Talos improves security further by mounting the root filesystem as read-only and removing any host-level such as a shell and SSH.

This is not a classical Linux distribution like Core OS and others, it's the equivalent of busybox for Kubernetes.

linkdd··on Ask HN: Do You Miss OOP?
Functional programming does not prevent you from setting up boundaries between modules and group functions together.
← PreviousPage 9 of 29Next →