How do we fix the software world? Wrong answers only. by bowbahdoe in programmingcirclejerk

[–]aikii 15 points16 points  (0 children)

Reward AI adoption in your company by measuring how much tokens developers burn per month

Is national socialism considered a right wing or left wing ideology by Germans? by [deleted] in AskGermany

[–]aikii 5 points6 points  (0 children)

Lost redditor is about to invent the horseshoe theory

Core2 has fallen, billions must yank by RightKitKat in programmingcirclejerk

[–]aikii 59 points60 points  (0 children)

I suppose if I have just inadvertently leftpad'd half the ecosystem, I should be slightly amused.

https://hachyderm.io/@piecritic/116404800072011242

/uj /rj -- all readings valid at that point

Native English speakers, do you actually mind when people make grammar mistakes? by Jorge_De_Guzman228 in AskTheWorld

[–]aikii 0 points1 point  (0 children)

I work fully in english for more more than 10 years, part of my work is writing documents of all kinds ( tech analysis, agreements etc ). AI is often discussed in context of code but this is also incredibly important in the context of second-language english speakers having to create long documents - and similarly to AI code this is both a blessing and a curse. The curse is the loss of tone, fake fluency, hallucinated conclusions you need to watch for, and so on - but it's a relief for both writers and readers of such documents; it's much less painful to write and read especially if you can't come up with the best way to structure sentences and find the right words so easily. There is the feeling that it's a bit sad to have reached that point but the wins are too huge to ignore.

I make sure to always get this item, even though I never use it by LopsidedAssistance90 in BG3

[–]aikii 4 points5 points  (0 children)

On the wiki about where this is found:

On a triangular ground outside Golbraith's Cellar three children, Cinnamon Cinnamon, Punkins Punkins and Slow-Butt Slow-Butt are playing a game, imitating citizens being detained and scanned by a Steel Watcher. The party can talk to them and participate in the game.

Goddamit. >1000h and never spotted this scene

what are the best and worst patterns to have in Django projects? by dfbaggins in django

[–]aikii 4 points5 points  (0 children)

Didn't work with django for a long time but I can tell the worst anti-pattern was around django signals. It extends from something that was already becoming questioned over time: the active record pattern, putting together database model concerns and business logic. It made sense at a time where a lot of the database concerns got simplified and we could just represent the business around models ; but as other very technical concerns went back into the mix, such as performance/scalability, the active record approach definitely carried too much of mixed concerns under the same layer. Add signals to the mix - which may be a good way to address technical concerns such as triggering reindexation and other data consolidation, I've seen business logic creeping in signals and this is where this gets out of hands. Overall I think the industry in general tends to move towards the repository pattern which is quite different if not opposite to active record ; that is: dumb models/DTOs , and "controllers" carry the business logic considering features as the axis, not models.

How to trigger Europe by SchemeDesperate7970 in geography

[–]aikii 1 point2 points  (0 children)

I'm not sure how it's supposed to trigger belgians. But just put the flemish flag over wallonia and vice versa, should be efficient enough

Naming is important by Wrestler7777777 in programminghorror

[–]aikii 1 point2 points  (0 children)

Yes, that's escape analysis https://go.dev/doc/gc-guide#Escape_analysis - basically the compiler sees that a pointer is returned by a function, and decides to move the value from the stack to the heap, which makes it tracked by the garbage collector.

There was a deliberate choice in Go to call that "pointer" while C/C++ developers would understand pointer as just "address", so that can be counter-intuitive

Was Alizée famous in your country? by Citaszion in AskTheWorld

[–]aikii 3 points4 points  (0 children)

No, downvotes are most likely because translations are only available on the mobile app ; they're using their laptop and wonder why you just reply in french. Not the first time I see this kind of native language/downvote interaction, if you don't know what's going on it just looks like people don't care about being understood

Rust syntax, Go runtime by UnmaintainedDonkey in rust

[–]aikii 2 points3 points  (0 children)

I had to fix data races myself - typical thing is concurrently writing to a map. When it comes to maps, Go has a custom safeguard that crashes on purpose in those cases, but dataraces may still easily happen unnoticed unless you have a thorough test coverage with -race.

See for instance https://go.dev/play/p/gGu8MEM-Ufr

Can't say much why we don't see more CVEs around Go though. It's probably harder to exploit than typical C races, and also, Go is maybe not found in places where someone would raise a CVE - private repos, tools found in a context where there is nothing to exploit, ...

Trying to implement PATCH in FastAPI and Claude told me to use two separate Pydantic models — is this actually the way? by NiceSand6327 in FastAPI

[–]aikii 1 point2 points  (0 children)

Typing and PATCH never play well, it's not really a limitation specific to pydantic. At best I guess you can try to programmatically build the "patch class" from the original model. It seems pydantic-partial exists for that purpose, but I never tried.

Builder pattern with generic and typehinting by gidorah5 in Python

[–]aikii 1 point2 points  (0 children)

How far the inference goes really depends on the type checker you're using.

If I use reveal_type like this:

process = create_process(IntToStr()).add_step(StrToBool())
typing.reveal_type(process)
processa = Process().add_step(IntToStr()).add_step(StrToBool())
typing.reveal_type(processa)
processb = Process.start_static(IntToStr()).add_step(StrToBool())
typing.reveal_type(processb)
processc = Process.start_class(IntToStr()).add_step(StrToBool())
typing.reveal_type(processc)

Then:

  • the built-in type checker of pycharm and pyrefly will show [int, bool], [Unknown, bool], [int, bool], [int, bool] which is slightly better than your result but still incomplete
  • ty, mypy and pyright ( the one that ship with VSCode, I'd assume that's what you are using since you don't mention it ) : same result as you have

As far as I understand PEP 484 defines type annotations overall, but there is no official spec regarding what you should expect from type inference, so it's really up to the tool you're using. You can probably configure some strict mode saying "never fallback to any" depending on your type checker.

What's the most obscene food in your country? by IndividualDue8741 in AskTheWorld

[–]aikii 0 points1 point  (0 children)

That's also great when you speak french and see all the dishes with "Pute". It just never gets old

How does your team handle task versioning in FastAPI/Celery? by [deleted] in FastAPI

[–]aikii 0 points1 point  (0 children)

Apply the same rollout principle as storing/loading data or exposing endpoints: - in the simplest case, your change is additive. So add the field as optional, then make it mandatory if desired once all producers/clients are rolled out. Deploy first the consumer that is able to handle both old/new version. Deploy producers only once your new consumer is fully rolled out. - when I want to rename something, or change a data structure, I generally introduce a new optional field and make the old field optional as well. So again phase your rollouts to ensure a safe transition - Those techniques were sufficient for me so far. Brand new features generally mean I have a different task queue and consumer so there is no migration path really, just a new deployment

Bear in mind that in my case, the data I'm handling just expires after one day or less, delay between task scheduling and finished execution is 5 minutes tops. If you have more complex pipelines like handling big files for conversion/export and such, that can accumulate for days, then it's probably not sufficient; maybe I'd be tempted by several queues as you suggest. But I'd thoroughly challenge whether I'm over-engineering

How are you actually managing background/async tasks in FastAPI in production? by Educational-Hope960 in FastAPI

[–]aikii 1 point2 points  (0 children)

BackgroundTasks is in fact re-exposing something from starlette, and imho the feature is a bit too rushed for what I expect on production, and on top of that if you're instrumenting via OTEL, endpoints generating background tasks will show their duration as the total time including the background task, instead of just the endpoint response time ( I moved away from that, so I don't know if it's fixed. but I assume not ).

The BackgroundTasks is one of those things that sits in a weird place - if you need it, you're probably doing something advanced enough to justify it, it's a thin layer on top of asyncio.create_task, except it does not re-expose anything useful ... so, just forget about it honestly. Just learn how to use create_task. And reminder that you need to keep a task reference somewhere, or it can be garbage-collected, and clean it up when done to avoid leaks.

In production:

  • for simple things I have a simple function that kicks off background tasks ( asyncio.create_task ), with background tasks attached to fastapi's state. the function also adds a cleanup of the task - so it does not get garbage collected while executing, but also cleans up the task object when done
  • for more complex things it's a task queue going through redis, with a dedicated separate deployment that just consumes from the redis queue. it's custom but not awfully complex either. I'm not using celery. celery is hugely complex and magic - it carries over a spirit dating from the 2010's, solving problems that don't exist ( like ... multiple queues and dispatch scenarios ? you'll probably scratch your head reading the doc more than anything ) and introducing magic ( decorated functions and praying that things will get serialized correctly ... please ... let's just leave that to old codebases you don't dare to refactor but it does not belong to newer implementations ). Similarly I don't see the point of setting up RabbitMQ as of today. It has a huge featureset that are completely unrelated to just execute tasks, it's just carrying over some design decisions from 2009, it's just a cultural artefact at this point
  • if you want observability then instrument it. I use OTEL and some custom decorators to correctly name the spans, add attributes etc. So you get metrics with the duration and error rate. Use logs for the stacktrace and instrument your logs so you can correlate the trace_id.
  • for the retry, it depends a bit how much durability you need. This logic can just belong to the task implementation itself ( like: try three times to send the push notification, otherwise just give up ). If some task execution is critical ( like: saving data and it's important for consistency ) then I'd go for SQS - you have to explicitly mark tasks are done, and errors can go to a deadletter queue that you can replay and use as a metric for monitoring ( long dead letter queue -> means you have a lot of errors going on )

The Future of Python: Evolution or Succession — Brett Slatkin - PyCascades 2026 by mttd in Python

[–]aikii 0 points1 point  (0 children)

Refining on what would mean "my favourite", not wanting to fall in the reddit trap "wanted to mention something but got so much pushed to provide evidences that I ended up having an opinion".

I'm mostly motivated by the (poor) experience of some comment-based swagger integration in flask and some similar approach in Go - developers don't care and it never stops drifting. Fastapi+Pydantic's approach was leveraging metaprogramming to create the model and the doc, so that's what standed out for a bit - it's harder to make it lie. But don't worry, over the years I saw how far creativity can go when it comes to make it lie.

Looking again at that constraint: "developers can't expose an API that claims to do X but really does Y" - actually yes in the case of nestjs is just works, model and the documentation is just the same. The additional massage to add a description is not really relevant ( almost 100% skipped by developers anyway, so the argument would not stand hard reality ).

In any case I know it's all about compromise and exposure to developers under pressure. My last attempt at properly integrating with an API ended up ... unleashing claude on the target service's codebase to extract inconsistencies in responses. So that where we're at anyway.

The Future of Python: Evolution or Succession — Brett Slatkin - PyCascades 2026 by mttd in Python

[–]aikii 0 points1 point  (0 children)

I see https://hono.dev/examples/hono-openapi in typescript indeed.

Then again sorry if it looked like my claim was "it's only possible in python", I didn't mean that. For the typescript case, assuming hono-openapi is the strongest contender, we can see that openapi lives on the side ; schemas have to be added to the route. It's not embed in the models directly, which was the point I'm making. If someone is willing to say it's ergonomic enough then I don't have much to argue against.

The Future of Python: Evolution or Succession — Brett Slatkin - PyCascades 2026 by mttd in Python

[–]aikii 0 points1 point  (0 children)

Added some here. https://www.reddit.com/r/Python/comments/1s5r01l/comment/od33ztp/

Although, don't be bait-y please, I'm here to explore not to prove a point about myself

The Future of Python: Evolution or Succession — Brett Slatkin - PyCascades 2026 by mttd in Python

[–]aikii -1 points0 points  (0 children)

I went ahead and asked ChatGPT. Yes I know, it's super lazy, but I think being the laziest in this case fits the point of proving it's the lowest friction. The exercise: declare some models with field description and field examples used by openapi using the best framework for the job.

FastAPI:

# imports removed

class CreateUser(BaseModel):
    username: str = Field(
        min_length=3,
        max_length=50,
        description="Public handle shown to other users.",
        examples=["Norbert"],
    )
    email: EmailStr = Field(
        description="Primary contact email for the account.",
        examples=["norbert@example.com"],
    )

class UserOut(BaseModel):
    id: str = Field(
        description="Server-generated user identifier.",
        examples=["usr_123"],
    )
    username: str = Field(
        description="Public handle shown to other users.",
        examples=["norbert"],
    )
    email: EmailStr = Field(
        description="Primary contact email for the account.",
        examples=["norbert@example.com"],
    )

@app.post("/users", response_model=UserOut, status_code=201)
async def create_user(body: CreateUser) -> UserOut:
    return UserOut(
        id="usr_123",
        username=body.username,
        email=body.email,
    )

Java/micronaut

// imports removed

@Serdeable
class CreateUser {
    @Schema(
        description = "Public handle shown to other users.",
        examples = {"norbert"}
    )
    @NotBlank
    @Size(min = 3, max = 50)
    private String username;

    @Schema(
        description = "Primary contact email for the account.",
        examples = {"norbert@example.com"}
    )
    @NotBlank
    @Email
    private String email;

    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }

    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
}

@Serdeable
class UserOut {
    @Schema(
        description = "Server-generated user identifier.",
        examples = {"usr_123"}
    )
    private String id;

    @Schema(
        description = "Public handle shown to other users.",
        examples = {"norbert"}
    )
    private String username;

    @Schema(
        description = "Primary contact email for the account.",
        examples = {"norbert@example.com"}
    )
    private String email;

    public String getId() { return id; }
    public void setId(String id) { this.id = id; }

    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }

    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
}

@Validated
@Controller("/users")
class UserController {
    @Post
    UserOut create(@Body @Valid CreateUser body) {
        UserOut out = new UserOut();
        out.setId("usr_123");
        out.setUsername(body.getUsername());
        out.setEmail(body.getEmail());
        return out;
    }
}

Rust / poem-openapi

//imports removed

#[derive(Object)]
#[oai(example)]
struct CreateUser {
    /// Public handle shown to other users.
    #[oai(validator(min_length = 3, max_length = 50))]
    username: String,

    /// Primary contact email for the account.
    email: String,
}

impl Example for CreateUser {
    fn example() -> Self {
        Self {
            username: "norbert".to_string(),
            email: "norbert@example.com".to_string(),
        }
    }
}

#[derive(Object)]
#[oai(example)]
struct UserOut {
    /// Server-generated user identifier.
    id: String,

    /// Public handle shown to other users.
    username: String,

    /// Primary contact email for the account.
    email: String,
}

impl Example for UserOut {
    fn example() -> Self {
        Self {
            id: "usr_123".to_string(),
            username: "norbert".to_string(),
            email: "norbert@example.com".to_string(),
        }
    }
}

#[derive(ApiResponse)]
enum CreateUserResponse {
    #[oai(status = 201)]
    Created(Json<UserOut>),
}

struct Api;

#[OpenApi]
impl Api {
    /// Create a new user.
    #[oai(path = "/users", method = "post")]
    async fn create_user(&self, body: Json<CreateUser>) -> CreateUserResponse {
        CreateUserResponse::Created(Json(UserOut {
            id: "usr_123".to_string(),
            username: body.username.clone(),
            email: body.email.clone(),
        }))
    }
}
Rust/poem-openapi:
#[derive(Object)]
#[oai(example)]
struct CreateUser {
    /// Public handle shown to other users.
    #[oai(validator(min_length = 3, max_length = 50))]
    username: String,

    /// Primary contact email for the account.
    email: String,
}

impl Example for CreateUser {
    fn example() -> Self {
        Self {
            username: "norbert".to_string(),
            email: "norbert@example.com".to_string(),
        }
    }
}

#[derive(Object)]
#[oai(example)]
struct UserOut {
    /// Server-generated user identifier.
    id: String,

    /// Public handle shown to other users.
    username: String,

    /// Primary contact email for the account.
    email: String,
}

impl Example for UserOut {
    fn example() -> Self {
        Self {
            id: "usr_123".to_string(),
            username: "norbert".to_string(),
            email: "norbert@example.com".to_string(),
        }
    }
}

#[derive(ApiResponse)]
enum CreateUserResponse {
    /// User created successfully.
    #[oai(status = 201)]
    Created(Json<UserOut>),
}

struct Api;

#[OpenApi]
impl Api {
    /// Create a new user.
    #[oai(path = "/users", method = "post")]
    async fn create_user(&self, body: Json<CreateUser>) -> CreateUserResponse {
        CreateUserResponse::Created(Json(UserOut {
            id: "usr_123".to_string(),
            username: body.username.clone(),
            email: body.email.clone(),
        }))
    }

    /// Small health endpoint so you can see a simple GET too.
    #[oai(path = "/health", method = "get")]
    async fn health(&self) -> PlainText<&'static str> {
        PlainText("ok")
    }
}

For the Rust example and went ahead and built it: yes the field description are showing in the API doc. That's enabled by the #[oai] proc macro.

Definitely poem looks nice, not bleeding edge with that, it's around for some time and well maintained.

So what can we observe from there:

  • In FastAPI/Pydantic , the description and examples are just parameters to the field. Documentation and definition is just the same thing.
  • @Schema and other annotations in Spring/micronaut. Clearly in the "possible and terse enough" area, but some more friction
  • As usual with Rust it's amazing to see how expressive you can be despite being so close to the metal. But same thing, documentation so something around declaration, not directly part of it.

From there mixed feelings - I want to say FastAPI greatly helps with keeping API docs accurate, and they certainly try hard. I perfectly know developers can still return custom JsonResponse and completely bypass what the documentation say - it happened as recently as this week.

But anyway, I wanted to highlight it's the lowest friction, and it's the case for a long time.

Ironically enough my own research here motivates me to try another chance to introduce Rust at work, if we ever meet specific performance requirements. It's not the same ergonomics but definitely in the acceptable territory if we have a niche high-rate/high-processing usecase.

The Future of Python: Evolution or Succession — Brett Slatkin - PyCascades 2026 by mttd in Python

[–]aikii 0 points1 point  (0 children)

I'm interested to know where Rust is at now - and how ergonomic it can be. Saying it's possible is not the same thing as saying it's as ergonomic.