I have to say I don’t understand your point! The parents comment is both clear and a reasonable, common approach of programming
> Can the objects a function creates be mutated by functions they call?
No
> can functions modify their input parameters?
No
> If a function returns one of their input parameters (modified or not), does that mean the calling function can no longer mutate it?
No. Because the called function isn’t allowed to mutate its inputs, there’s no problem for the caller to mutate it. It’s irrelevant whether the input was also an output of the called function as it cannot mutate it anyway.
I suppose you can get into race conditions between caller and callee if your language provides asynchronicity and no further immutability guarantees. Still, you eliminated a whole lot of potential bugs
Let’s put your uncertainty to rest: at the extreme, any function execution spends both time and energy, both of which are observable side-effects.
So yes, you’re right that there no such thing as an absolutely pure function. “Pure” always assumes that all dependencies are pure themselves. Where it’s a reasonable assumption and whether it’s still useful or not depends on your program: assuming an API call to be pure is certainly not reasonable for many use cases, but it is reasonable enough to be useful for others.
> ensure user input is properly escaped when inserting into sql
I used to wish for that and got it in JS with template strings and libs around it. For what it’s worth (you got a whole PEP done, you have more credibility than I do) I ended up changing my mind, I think it’s a mistake.
It’s _nice_ from a syntax perspective. But it obscures the reality of sql query/parameter segregation, it builds an abstraction on top of sql that’s leaky and doesn’t even look like an abstraction.
And more importantly, it looks _way too close_ to the wrong thing. If the difference between the safe way to do sql and the unsafe way is one character and a non-trivial understanding of string formatting in python… bad things will happen. In a one-person project it’s manageable, in a bigger one where people have different experiences and seniority it will go wrong.
It’s certainly cute. I don’t thing it’s a good thing for sql queries.
I understand your concern, and I think the PEP addresses it. Quite bluntly, t"foo" is not a string, while f"foo" is. You'll get a typecheck error if you run a typechecker like any reasonable developer, and will get a runtime error if you ignore the type mismatch, because t"foo" even lacks a __str__() method.
One statement the PEP could put front and center in the abstract could be "t-strings are not strings".
For all their ills lawyers basically never engage in that "clearly my experience transfers" type crap. Getting them to say anything about stuff they're not experts in is like pulling teeth.
People who have time AND enjoy doing this sort of thing in their free time will do this for fun. That’s the self-selection, then from this pool talent hopefully gets translated into results.
Why reduce your pool to “free time and enjoy doing bounties in free time”? That’s excluding many talented people. I’ll also point out that it’s discriminatory: single childless wealthy men tend to have a whole lot more free time (for example women do most of the unpaid care work in all countries, leaving a whole lot less time for this sort of thing).
I also have a suspicion (not based on any data) that people who enjoy doing bounties in their free time certainly tend to be technically talented, but also tend to have non-technical weaknesses around communication and other soft skills. So you’d self select for this weakness too.
They’re not talking about distributed transactions: it’s not about a task being published and consumed atomically, it’s about it being consumed and executed atomically.
My understanding is that hatchet isn’t just a queue, it’s a workflow orchestrator: you can use it as a queue but it’s kind of like using a computer as a calculator: it works but indeed it’d likely be simpler to use a calculator.
On your point of using transactions for idempotency: you’re right that it’s a great advantage of a db-based queue, but I’d be wary about taking it as a holy grail for a few reasons:
- it locks you into using a db-based queue. If for any reason you don’t want to anymore (eg you’re reaching scalability issues) it’ll be very difficult to switch to another queue system as you’re relying on transactions for idempotency.
- you only get transactional idempotency for db operations. Any other side effect won’t be automatically idempotent: external API calls, sending messages to other queues, writing files…
- if you decide to move some of your domain to another service, you lose transactional idempotency (it’s now two databases)
- relying on transactionality means you’re not resilient to having duplicate tasks in the queue (duplicate publishing). That can easily happen: bug of the publisher, two users triggering an action concurrently… it’s quite often a very normal thing to trigger the same action multiple times
So I’d avoid having my tasks rely on transactionality for idempotency, your system is much more resilient if you don’t
Giving your anecdotal experience is only useful if you include anecdotal context: seniority, years of experience, technology, project size, sprint goal complexity…
When writing a migration, the resulting schema is usually much, much less important than the characteristics of the migration itself. When I review a migration, my first question isn’t “is this the right schema” but “is this migration going to bring downtime”. I’d much rather a smooth migration to an incorrect schema than having a critical table locked for minutes/hours.
I think that updates of stateful components should be imperative (explicit migrations), not declarative (implicit migrations). For example I don’t think Terraform is great tool to manage RDS: it doesn’t tell you the consequences of changing an attribute (database restart or other downtime-inducing stuff), I’d much rather I had to explicitly say how to get from state A to state B.
Similarly, I don’t think SQL migrations are perfect: they’re still declarative, you still need implicit knowledge to know if a migration will take a lock and what will be the consequences. I’d much rather have to code “take explicit lock; alter table xxx;”.
This tool probably allows editing migrations, but I don’t think it’s a step in the right direction. Maybe it’s a step towards databases being much better at migrations (so that we can rely on never having downtime), but even then I think it’ll get worse before it gets better
> it doesn’t tell you the consequences of changing an attribute (database restart or other downtime-inducing stuff)
Modern diff tools are designed to provide better guardrails in these situations. For eg, pg-schema-diff [0] tries to generate zero downtime migrations by using lock-free migrations and warns you about potentially hazardous migrations.
I think it's good direction to bake these best practices into the tooling itself, rather than relying purely on the experiences of engineers.
This is exactly the key point. Declarative schema management is typically better at catching hazardous operations, because declarative schema management tools inherently require the ability to introspect your desired CREATE definitions and also introspect the current database state.
Once a tool has those abilities, adding linters and destructive-action guardrails is much easier. Especially when compared to a traditional migration tool, which often has no underlying understanding of the ALTER TABLE operations being requested.
> Can the objects a function creates be mutated by functions they call?
No
> can functions modify their input parameters?
No
> If a function returns one of their input parameters (modified or not), does that mean the calling function can no longer mutate it?
No. Because the called function isn’t allowed to mutate its inputs, there’s no problem for the caller to mutate it. It’s irrelevant whether the input was also an output of the called function as it cannot mutate it anyway.
I suppose you can get into race conditions between caller and callee if your language provides asynchronicity and no further immutability guarantees. Still, you eliminated a whole lot of potential bugs
reply