Live data from Hacker News

Don't let dicts spoil your code (2020)

roman.pt

61–70 of 91 posts

Re: Don't let dicts spoil your code (2020)

#61
post #16

Python's strapped on type annotations have been designed around traditional OOP, and it feels like a bad fit for the language. Duck typing is a tremendously powerful form of polymorphism, and none of the PEPs for type annotations do a great job of supporting it. Protocols don't work well with dataclasses and not at all with dicts. TypedDicts could have been perfect, but they explicitly disallow extra keys. Why even u…

> none of the PEPs for type annotations do a great job of supporting it

Except for protocols.

Re: Don't let dicts spoil your code (2020)

#62
post #52

I really liked the structure of this blog post. But It misses the positive aspects of using dictionaries. Like when you are the owner of the api you consume and just want the JSON to flow through your “application tier”

Hey, molly0! Do you have a specific example in mind? I'm thinking about how common this use case could be but can't come up with anything.

In my case. We have an internal REST like api. It mostly is just a wrapper around our python ORM but returns JSON.

If I update an object model It’s because I want to expose new fields. Else I actively have to tell it not to.

It feels like a normal use case.

Re: Don't let dicts spoil your code (2020)

#63

> Don't let dicts spoil your code (2020) (roman.pt) * Conditions applies * Apply only for when parsing I/O. Do not substitute primitives with classes inside your code base for no good reason. Unless validation is needed, prefer a NamedTuple.

Other than validation, I can imagine several good reasons why one might want to wrap a primitive inside a class.

For example, you may have a function:

    group_by_age() -> Dict[int, List[str]]
which might be perfectly good for your use case, but I can see why one might instead prefer:

    group_by_age() -> Dict[Age, List[CustomerId]]
for self-documentation and expressiveness.

Your test assertions may also become easier to read:

    assert group_by_age() == {
        Age(23): [
            CustomerId("0471"),
            CustomerId("3390"),
        ],
        Age(42): [
            CustomerId("2334"),
        ],
    }

Re: Don't let dicts spoil your code (2020)

#64

Is it so hard to type dictionary?

Given how ubiquitous that type is, wouldn’t the four-syllable word “dictionary”, once written down hundreds of times, be prone to semantically satiating any discussion and code base?

Besides, you could argue it’s not exactly the author’s choice because `dict` is the actual name of Python’s dictionary type.

Re: Don't let dicts spoil your code (2020)

#65
Functions that accept dicts are a nightmare to extend and modify.

Compared to what? I see the article's point about dicts being, like everything else in programming, a tradeoff with benefits and limitations. But the article's needless dramatization of a pretty mundane point (and the button-pushing title) are, to these jaded eyes, a definite turn-off.

Meanwhile I'll keep using dicts when the use case calls for them, thank you. As a sibling commenter put it:

If you don't know how the data should be used, it's often a different story.

Exactly. The whole point (and benefit) of dicts is that they're squishy. Sometimes you need squishy.

Re: Don't let dicts spoil your code (2020)

#66

My take is that dicts are fine as long as your code is well tested. Yeah, dataclasses and frozen classes have much better typing support, but if you code is mostly reading and writing JSON like many modern cloud apps, it can be easier to use plain dicts combined with decent tests to make sure you don't break downstream services.

I’m currently in the middle of refactoring a well-tested but dict-ly typed Python codebase into dataclasses.

Once your app involves a certain amount of business logic, those dicts just beg for you to shove in just that one more temporary field that you’ll be needing later in the calculation.

Of course you can abuse classes just the same. But I feel it happens less often. There’s more social control. The type has a name now. And you have to visit it at home whenever you’re trying to add a field to it. My impression is that some people are underestimating the psychological power of those nudging factors.

Re: Don't let dicts spoil your code (2020)

#67
post #62

Earlier quoted context omitted.

Hey, molly0! Do you have a specific example in mind? I'm thinking about how common this use case could be but can't come up with anything.

In my case. We have an internal REST like api. It mostly is just a wrapper around our python ORM but returns JSON. If I update an object model It’s because I want to expose new fields. Else I actively have to tell it not to. It feels like a normal use case.

Huh, I worked with this architecture, and while it was convenient at first, it became an issue down the road. Here's what we had.

- A few times, we inadvertently exposed internal fields. They were not sensitive, just internal. Still, clients discovered and started using them and effectively blocked us from changing the data schema without updating the API version.

- A risk of inadvertently exposing sensitive fields. We never had this, but the mere fact that it was too easy to have, kept unnecessary pressure on us.

- Adjusting the serialization format for different purposes became a problem. When everything is a dict, it's difficult to bolt in custom serialization logic. We had this issue when we had to support different API versions, different object representations for different clients, or different purposes. For example, when we cache an object, we want to keep all the fields, but when we return it to an object, we need to maintain the subset of them.

- Slower onboarding. When a newcomer joins the project, they need to be aware that any database change may leak as an API attribute. They couldn't start working before they saw the whole picture.

Re: Don't let dicts spoil your code (2020)

#68
post #62

Earlier quoted context omitted.

In my case. We have an internal REST like api. It mostly is just a wrapper around our python ORM but returns JSON. If I update an object model It’s because I want to expose new fields. Else I actively have to tell it not to. It feels like a normal use case.

Huh, I worked with this architecture, and while it was convenient at first, it became an issue down the road. Here's what we had. - A few times, we inadvertently exposed internal fields. They were not sensitive, just internal. Still, clients discovered and started using them and effectively blocked us from changing the data schema without updating the API version. - A risk of inadvertently exposing sensitive fields.…

We haven’t had issues with exposing unwanted fields (yet?). autogenerating API documentation and versioning major updates address the concerns you listed for us.

Re: Don't let dicts spoil your code (2020)

#69
post #60

So types solve this right? Or am I misunderstanding?

I'd rather phrase it as "well-defined data structures help maintain your app." In another comment, leetrout recommended using named tuples. They define a list of their attributes without saying anything about their types, and this may be a perfect choice for some scenarios.
Post reply on HN