Live data from Hacker News

Architecture Patterns with Python

cosmicpython.com

81–90 of 143 posts

Re: Architecture Patterns with Python

#81

Earlier quoted context omitted.

Could you explain how repository pattern is a "huge overkill that adds complexity with very little benefit"? I find it a very light-weight pattern and would recommend to always use it when database access is needed, to clearly separate concerns. In the end, it's just making sure that all database access for a specific entity all goes through one point (the repository for that entity). Inside the repository, you can d…

I find repository pattern useful for testing ... it's a lot easier to mock a repository than to mock stuff that SQLalchemy might need to do.

I rarely mock a repository. Mocking the database is nice for unit-testing, it's also a lot faster than using a real DB, but the DB and DB-application interface are some of the hottest spots for bugs: using a real DB (same engine as prod) gives me a whole lot more confidence that my code actually works. It's probably the thing I'm least likely to mock out, despite making tests more difficult to write and quite a bit slowerq

Re: Architecture Patterns with Python

#82

Wow this book is a goldmine for architecture patterns. I love how easy it is to get into a topic and quickly grasp it. Having said that, from a practical and experience standpoint, using some of these patterns can really spiral out into an increased complexity and performance issues in Python, specially when you use already opinionated frameworks like Django which already uses the ActiveRecord pattern. I’ve been in c…

This has been my experience in working with any kind of dogmatic structure or pattern in any language. It seems that the architecture astronauts have missed the point: making the code easier to understand for future developers without context, and provide some certainty that modifications behave as expected.

Here's an example of how things can go off the rails very quickly: Rule 1: Functions should be short (no longer than 50 lines). Rule 2: Public functions should be implemented with an interface (so they can be mocked).

Now as a developer who wants to follow the logic of the program, you have to constantly "go to definition" on function calls on interfaces, then "go to implementation" to find the behavior. This breaks your train of thought / flow state very quickly.

Now let's amp it up to another level of suck: replace the interface with a microservice API (gRPC). Now you have to tab between multiple completely different repos to follow the logic of the program. And when opening a new repo, which has its own architectural layers, you have to browse around just to find the implementation of the function you're looking for.

These aren't strawmen either... I've seen these patterns in place at multiple companies, and at this point I yearn for a 1000 line function with all of the behavior in 1 place.

Re: Architecture Patterns with Python

#83

Some parts of this book are extremely useful, especially when it's talking about concepts that are more general than Python or any other specific language -- such as event-driven architecture, commands, CQRS etc. That being said, I have a number issues with other parts of it, and I have seen how dangerous it can be when inexperienced developers take it as a gospel and try to implement everything at once (which is a c…

> I have seen how dangerous it can be when inexperienced developers take it as a gospel and try to implement everything at once This book explicitly tells you not to do this. > Similarly, service layers and unit of work are useful when you have complex applications that cover multiple complex use cases; but in a system consisting of small services with narrow responsibilities they quickly become overly bloated using…

may I ask how you're mocking Celery to test?

the two main methods I've seen are to run tasks eagerly, or test the underlying function and avoid test Celery .delay/etc at all

Re: Architecture Patterns with Python

#84
post #76

Earlier quoted context omitted.

Annotations can and should be checked. If I change a parameter type, other code using the function will now show errors. That won't happen with just documentation.

> Annotations can and should be checked Unfortunately Python’s type system is unsound. It’s possible to pass all the checks and yet still have a function annotated `int` that returns a `list`.

Do you mean that you're allowed to only use types where you want to, which means maybe the type checker can't check in cases where you haven't hinted enough, or is there some problem with the type system itself?

Re: Architecture Patterns with Python

#85
post #76

Earlier quoted context omitted.

Annotations can and should be checked. If I change a parameter type, other code using the function will now show errors. That won't happen with just documentation.

> Annotations can and should be checked Unfortunately Python’s type system is unsound. It’s possible to pass all the checks and yet still have a function annotated `int` that returns a `list`.

True and irrelevant. Type annotations catch whole swathes of errors before they cause trouble and they nudge me into writing clearer code. I know they’re not watertight. Sometimes the type checker just can’t deal with a type and I have to use Any or a cast. Still better than not using them.

Re: Architecture Patterns with Python

#86
post #76

Earlier quoted context omitted.

> Annotations can and should be checked Unfortunately Python’s type system is unsound. It’s possible to pass all the checks and yet still have a function annotated `int` that returns a `list`.

Do you mean that you're allowed to only use types where you want to, which means maybe the type checker can't check in cases where you haven't hinted enough, or is there some problem with the type system itself?

The type system itself is unsound. For example, this code passes `mypy --strict`, but prints `` even though `bar` is annotated to return an `int`:

    i : int | list[int] = 0

    def foo() -> None:
        global i
        i = []

    def bar() -> int:
        if isinstance(i, int):
            foo()
            return i
        return 0

    print(type(bar()))

Re: Architecture Patterns with Python

#87
post #83

Earlier quoted context omitted.

> I have seen how dangerous it can be when inexperienced developers take it as a gospel and try to implement everything at once This book explicitly tells you not to do this. > Similarly, service layers and unit of work are useful when you have complex applications that cover multiple complex use cases; but in a system consisting of small services with narrow responsibilities they quickly become overly bloated using…

may I ask how you're mocking Celery to test? the two main methods I've seen are to run tasks eagerly, or test the underlying function and avoid test Celery .delay/etc at all

I just rolled my own mocked Celery objects. I have mocked Groups, Chords, Chains, and Signatures, mocked Celery backend, and mocked dispatch of tasks. Everything runs eagerly because it's all just running locally in the same thread, but the workflow still runs properly-- the output of one task is fed into the next task, the tasks are updated, etc.

I actually pass Celery and the functions like `signature`, `chain`, etc as a tuple into my service layer functions.

It's mostly just to test that the piping of the workflow is set up correctly so I don't find out that my args are swapped later during integration tests.

Re: Architecture Patterns with Python

#88
post #77

Earlier quoted context omitted.

So far off from what actually happens. The type annotations provide an easy scaffolding for understand what the code does in detail when reading making code flow and logic less ambiguous. Reading Python functions in isolation, you might not even know what data/structure you’re getting as input… if there’s something that muddles up immediate clarity it’s ambiguity about what data code is operating on.

>So far off from what actually happens I disagree strongly, based on 20 years of using Python without annotations and ~5 years of seeing people ask questions about how to do advanced things with types. And based on reading Python code, and comparing that to how I feel when reading code in any manifest-typed language. >Reading Python functions in isolation, you might not even know what data/structure you’re getting as…

> using the wrong language

IMO this is the source of much of the demand for type hints in Python. People don't want to write idiomatic Python, they want to write Java - but they're stuck using Python because of library availability or an existing Python codebase.

So, they write Java-style code in Python. Most of the time this means heavy use of type hints and an overuse of class hierarchies (e.g. introducing abstract classes just to satisfy the type checker) - which in my experience leads to code that's twice as long as it should be. But recently I heard more extreme advice - someone recommended "write every function as a member of a class" and "put every class in its own file".

Re: Architecture Patterns with Python

#90

Wow this book is a goldmine for architecture patterns. I love how easy it is to get into a topic and quickly grasp it. Having said that, from a practical and experience standpoint, using some of these patterns can really spiral out into an increased complexity and performance issues in Python, specially when you use already opinionated frameworks like Django which already uses the ActiveRecord pattern. I’ve been in c…

I found the book's use of modeling how to pilot an alien starship to be a little misleading, because a starship is a highly engineered product that functions in large part as a control mechanism for software. It comes with a clean design model already available for you to discover and copy. Domain modeling should not be about copying the existing model -- it should be about improving on it using all the advantages so…

> I found the book's use of modeling how to pilot an alien starship to be a little misleading, because a starship is a highly engineered product that functions in large part as a control mechanism for software. It comes with a clean design model already available for you to discover and copy.

Doctor Who fans will note that TARDIS craft seem to follow a different design: they regularly reconfigure themselves to fit their pilot, don't have controls laid out in any sensible fashion, and there's at least one reference to how they're "grown, not built". Then again they were also meant to be piloted by a crew and are most likely sentient, so it's also possible that due to the adaptations, the Doctor's TARDIS is just as eccentric as he is.

It's not like Doctor Who is "hard" sci-fi tho, it's basically Peter Pan in Space.

Post reply on HN