Hacker News new | past | comments | ask | show | jobs | submit | unculture's comments login

SQLModel is supposed to be the best of both Pydantic and SQLAlchemy, but by design an SQLModel entity backed by a database table doesn't validate its fields on creation, which is the point of Pydantic.

https://github.com/fastapi/sqlmodel/issues/52#issuecomment-1...


Repository pattern is useful if you really feel like you're going to need to switch out your database layer for something else at some point in the future, but I've literally never seen this happen in my career ever. Otherwise, it's just duplicate code you have to write.


What is the alternative that you use, how do you provide data access in a clean, separated, maintainable way?

I have seen it a lot in my career, and have used it a lot. I've never used it in any situation to switch out a database layer for something else. It seems like we have very different careers.

I also don't really see how it duplicates code. At the basic level, it's practically nothing more than putting database access code in one place rather than all over the place.


OK, let's first define some things.

What we are talking about is a "transformation" or "mapper" layer isolating your domain entities from the persistence. If this is what we call "Repository" then yes, I absolutely agree with you -- this is the right approach to this problem. But if the "Repository pattern" means a complex structure of abstract and concrete classes and inheritance trees -- as I have usually seen it implemented -- then it is usually an overkill and rarely a good idea.


Thanks. In my mind, anything about complex structures of (abstract) classes and/or inheritance trees has nothing to do with a Repository pattern.

As I understand it, Repository pattern is basically a generalization of the Data Access Object (DAO) pattern, and sometimes treated synonymously.

The way I mean it and implement it, is basically for each entity have a separate class to provide the database access. E.g. you have a Person (not complex at all, simply a value object) and a PersonRepository to get, update, and delete Person objects.

Then based on the complexity and scope of the project, Person either 1-to-1 maps to a e.g. a database table or stored object/document, or it is a somewhat more complex object in the business domain and the repository could be doing a little bit more work to fetch and construct it (e.g. perhaps some joins or more than 1 query for some data).


> for each entity have a separate class to provide the database access

Let me correct you: for each entity that needs database access. This is why I'm talking about layers here: sometimes entities are never persisted directly, but only as "parts" or "relations" of other entities; in other cases you might have a very complex persistence implementation (e.g. some entities are stored in a RDB, while others in a filesystem) and there is no clear mapping.

I recommend you to approach this from the perspective of each domain entity individually; "persistability" is essentially just another property which might or might not apply in each case.


Naturally, Repository is a pattern for data(base) access, so it should have nothing to do with objects that are not persisted. I used "entity" as meaning a persisted object. That was not very clear, sorry.


Well, again, that is not completely straightforward - what exactly is a "persisted object"? We have two things here that are usually called entities:

1. The domain entities, which are normally represented as native objects in our codebase. They have no idea whether they need to be persisted and how.

2. The database entities, which are - in RDBs at least - represented by tables.

It is not uncommon that our entities of the first type can easily be mapped 1:1 to our entities of the second type - but that is far from guaranteed. Even if this is the case, the entities will be different because of the differences between the two "worlds": for example, Python's integer type doesn't have a direct equivalent in, say, PostgreSQL (it has to be converted into smallint, integer, bigint or numeric).

In my "correction" above I was talking about the domain entities, and my phrasing that they "need database access" is not fully correct; it should have been "need to be persisted", to be pedantic.


I’ve seen it, but of course there was no strict enforcement of the pattern so it was a nightmare of leakage and the change got stuck half implemented, with two databases in use.


It's quite cold a lot of the time in Northern Europe, and people who are cycling to commute there often really aren't going very fast so won't sweat much.

You can also get "moisture wicking" clothes, that might help with a certain amount of sweat.

There is quite a lot of e-bike use in Amsterdam and Copenhagen. Google "bakfiets" - it's a whole "suburban parents with a family size e-bike" cliche (but a good one!).


It’s been cancelled, sadly.


You don't avoid naming - you name the components and the styles live in the components. The key is to avoid the false separation of concerns of style and structure.


If you're making a wholesale design change, you should expect a wholesale code change. If you're making a small change to a component that's the same every everywhere you should ideally expect to make that change in a single place. If you don't have that, that's a problem, but it's not Tailwind's fault.

Global defaults are a separate matter. As are prose styles / styles for UGC text because you don't know the HTML structure ahead of time - by all means use the cascade here, but for almost but for everything else you have two maintainable options:

1) Some CSS naming system or scoping system, e.g. BEM where you enforce proper naming and selector complexity limits (except in rare circumstances). This is extremely hard to do in the long term on a big project.

2) Leverage the component system / template system of whatever system you're using to make reusable components and use utility styles.

Using the cascade extensively on a long running project is a recipe for maintainability disaster - you will face a wild goose chase for the file you want every time you want to make a change, and then another wild goose chase for unexpected changes because your selectors weren't specific enough.

I'm also pretty strongly of the opinion nowadays that separation of concerns of CSS and HTML is a false separation - the single concern is how a thing looks on the page.


You really need to cut out these accusations of dishonesty - it’s a bad look.

He’s not saying “separation of concerns and good naming practices” are bad things, he’s saying that separation of concerns between HTML and CSS is mostly a false separation (it’s the same concern - making the UI look right) and that good naming practices are hard - best just do that in one place, the component that address the concern with both style and structure.


This is just demonstrably not true.


Agreed. I read and maintain tailwind every day. Rewriting it regularly would be highly unproductive.


Come on - your turn. Come back with your version of that Catalyst button that does everything that’s being done by those Tailwind styles.


I've written an entire article that about Tailwind's "don't clean things up" attitude:

https://nuejs.org/blog/tailwind-vs-semantic-css/

The bloat takes several forms

1. The amount of source HTML/CSS needed

2. The code complexity (class & DIV/SPAN "soup")

3. The weight of CSS & JS on the resulting website

Happy to write a comparison to Calypso, which is on a whole new level. Betting 10-20x bloat differences to semantic CSS.


Both this and the post you linked are great.

I do think it would be great to make a follow-up post on Calypso, even if only on the button. Looking forward to it.


Option 1: Find a visual error, open devtools, find the nearest most descriptive class or id (.primary? Oh no…), open IDE, global search in styles folder structure (most likely but not the only place to find CSS) for “.primary”. 40 files returned. After 15 minutes find a file that looks like it might be the right one. 10 minutes to understand the CSS (lots of advanced CSS in here…). Find the cause of the visual error, make the 1 line change. 30 minutes - job done.

Option 2: Find a visual error, open e.g. React Devtools, find the component name, open the IDE, find the component source file, find the HTML, change the utility style class, job done - 5 minutes.

These are not contrived examples. I had a one liner take 40 minutes to find in a codebase a couple of weeks ago. Not an exaggeration.

I really used to believe in separation of concerns but I don’t any more, because of all the time I’ve had to spend fighting with “option 1” codebases over the years. Pretty much any big codebase with normal CSS is going to be an “option 1” eventually unless it’s the work of a single good CSS developer (rare skill), or a team where someone who’s a good leader also cares about CSS enough to enforce a convention like BEM in perpetuity (even rarer skill).

Anyone building anything complex these days is using some component abstraction - whether it’s client side or not - to manage complexity. May as well make use of it for styles if it’s already there.

The reason that there’s a backlash against separation of concerns, the cascade, and (low) specificity is that each of these things is a complete disaster for maintainability in the long run.

One note in making an example of that Catalyst button. If you wrote out all the styles required to do the amount of work that button is doing it would also be extremely difficult to understand, and what’s more, it’d be in a completely different file to the single thing that gives it any meaning - the HTML.


This is exactly my experience as well. CSS in bigger codebases becomes unmanagable pretty quickly, and making small changes can become a big pain point. Tailwind doesn't completely solve this problem, but it absolutely improves it by reducing the distance between related concepts - and that's always a good thing.


Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: