But maybe not for long. When we get long-running AIs, the knowledge locked inside the AI's thinking might supplant docs once again. Like if you had an engineer working at your company for a long time and knowing everything. With all the problems that implies, of course.
That's the weird best thing about LLMs - there is finally incentive for projects to create documentation, CLIs, tests, and well organized modular codebases, since LLMs fall flat on their face without these things!
GitHub API is actually quite tricky here because there is a different between “comment” and “review” and “review comment” (paraphrasing, I don’t remember the details). So it’s not as simple as one API call that grabs the markdown. Of course you can write a creative one-liner to extract what you need, though.
If the DNS resolution call blocks the thread, then you need N worker threads to perform N DNS calls. Threads aren’t free, so this is suboptimal. OTOH some thread pools e.g. libdispatch on Apple operating systems will spawn new threads on demand to prevent starvation, so this _can_ be viable. Though of course this can lead to thread explosion which may be even more problematic depending on the use case. In libcurl’s situation, spawning a million threads is probably even worse than a memory leak, which is worse than long timeouts.
In general, what you really want is for the API call to be nonblocking so you’re not forced to burn a thread.
I think it's because of all of those transition mechanisms and fallback code added over the years. IPv6 fails the same way IPv4 does, but because of the terrible bullshit ISPs do to IPv6 connections, you end up with tons of software triggering obscure timeouts and fallback mechanisms that lead to a system of almost working networking code.
If the absence of IPv6 would've been treated the same way absence of IPv4 is, troubleshooting would've become a lot clearer. In fact, it probably would've been easier because ISPs can't just ignore and disable ICMP on IPv6 so you can actually get a hunch where in the network the problem is rather than seeing traffic vanish into the void.
This is an interesting point. Hangs usually cost $ from user experience, with serverless they cost $ from compute. All the more reason to set strict deadlines on all API calls!
> All the more reason to set strict deadlines on all API calls!
I've seen this backfire in production though. E.g. suppose there was a 5 sec limit on an API call, but (perhaps unintentionally) that call was proportional to underlying data volumes or load. So, over time, that call time slowly creeps up. Then it gets to the 5 sec limit, and the call consistently times out. But some client process retries on failure. So, if there was no time limit, the call would complete in, say, 5.2 seconds. But now the call times out every time, so the client just continually retries. Even if the client does exponential backoff, the server is doing a ton of work (and you're getting charged a ton for lambda time), but the client never gets the data they need.
Or a slow anything else, e.g., SQLite queries. This thread has focused on the network aspects, and they do stand out since there can be such a large gap between a network call vs a local SSD read. But we're still talking about a database, which could be huge (presumably it's the main, single DB for the whole app). And there is still all of the actual SQLite work that needs to happen to execute a query, plus opportunities for really bad performance b/c of bad queries, lack of indexes, all the usual suspects. Not to mention the load on the owning process itself. So, I'm agreeing that a loading state is needed.
I think this strongly depends on the application and use-case. I've worked at two businesses so far, and they target small and medium-sized companies in a tenant-style manner.
All data for one customer that is important enough to load easily fits within less than 5MB. That is of course not counting logs and such, but it's all "important" user-specific data. It's not -that- dissimilar from a small to medium-sized redux store in complexity. Lots of toggles, forms, raw text and some relations.
Of course this architecture doesn't scale to the enterprise level, or to other certain heavily data-driven applications (like imagine running the entirety of your sentry database in-browser?), but that's what architecture is -for-! Pick one that synergizes well with your use-case!
Assuming you're serving a frontend that makes network calls to a backend, you'll need to handle loading states in the frontend regardless of how the backend retrieves its data.
You're just saying, even if all you were doing was fetching a static JSON blob from the memory of the frontend server, you'd still want load states, right? (That makes sense, I'm just checking my understanding.)
The key here is to make a single API call to the backend which then runs 100+ SQL queries at once and combines the results into a single JSON response - that way you're only paying the network cost once.
I've implemented GraphQL on top of SQLite and found it to be an amazingly good match, because the biggest weakness of GraphQL is that it makes it easy to accidentally trigger 100s of queries in one request and with SQLite that really doesn't matter.
that doesn't eliminate need for loading states at all, and is already solved by things like react server components or remix (see waterfall removal graphic https://remix.run/)
i think this discussion is confusing the use of sqlite in local-first apps, where there's no loading states because the database is in the browser. you can use sqlite on your server, but you still need a "loading state".
even with postgres, if your data and server are colocated, the time between the 2 is already almost 0
now maybe the argument is your servers are deployed globally each with an sqlite db. that's not all that different from global postgres read replicas
If the data and the server are colocated on the same machine, the database network overhead is almost zero. But that's not necessarily true otherwise. For an HTTP request that incurs a single query, you can round it to zero, but you have to be careful not to write request handlers that incur lots of queries if you're trying to stay below the 100ms threshold.
On my very first onramp I nearly totaled it under the back of a heavy, slow truck. I was so used to flooring the pedal to get up to highway speed and totally unprepared for that instantaneous acceleration.
Does it? Instead of a single parameter you now have two names, and a type info to boot
pub fn replace(
in string: String,
each pattern: String,
with replacement: String,
) {
// The variables `string`, `pattern`, and `replacement` are in scope here
}
replace(in: "A,B,C", each: ",", with: " ")
When argument variable names and labels are combined you have two problems:
1. Labels are accidental. If all arguments automatically create labels then the programmer has not considered and deliberately designed the API. Gleam is designed to make sure that APIs are always carefully thought about and designed as appropriate.
2. Renaming a variable becomes a breaking change. We don't believe that renaming a variable should ever result in a semver major version bump.
3. Since Gleam doesn't enforce labels or check labels in any way, it doesn't "make sure APIs are carefully thought out". Labels will be just as random and accidental as parameter names following the whims of the programmer who decides to use them
1. Every class/method/function/whatever declaration is an API, doesn't matter if it's internal or which language it's written.
2. Why do you think it's better? It looks like it tries to cater to everyone, and leads to inconsistent API usage and requires teams to agree on linting rules and use tools to enforce consistent coding standards.
3. It's a tool for _you_ to design good APIs that are clear. Languages without named arguments don't give you this tool.
> So does renaming a label.
In languages without this feature, any renaming breaks the API, unlike the ones with distinct internal and external names. This is not the same.
the idea is that within the function body you would rather refer to the variables as e.g. `for s in string.match(pattern)` than `for s in in.match(each)`