Hacker News new | past | comments | ask | show | jobs | submit login

Why not just prevent the construction of bad states instead of constructing bad states and later checking them?





Often, imo, this depends on where you want to put the validation complexity. You can move validation to the front end and "prevent constructing bad states" through a combination of good UI and front end data validation, i.e. validate all the pieces of an entity to make sure the eventual Entity will be valid. But the opposite trade off would be to keep your front end simple, and have the data represent anything that is possible in the UI, and then you can validate anywhere in your stack that you want or where it makes sense for any engineering reason. You can still validate the UI models on the front end before sending them over the wire. You can validate at the endpoint and return HTTP codes. You can run logic in your database to massage/correct/fix the data any way you want. You could even throw things into a queue for post-processing later on, or send to another server for processing, whatever you want.

In theory it sounds great to say "just prevent construction of bad states," but this is a complex problem in professional software that involves coordination between programmers, designers, and product managers to get the UI features into the right place where preventing the construction of bad states doesn't lead to a frustrating UI experience for users. It's often far simpler, more pragmatic, and less complex in terms of coupling in both software and humans to just accept whatever state the UI gives you and figure things out somewhere else where you aren't bothering your users so much.


> Often, imo, this depends on where you want to put the validation complexity. You can move validation to the front end

This has nothing to do with the frontend/backend split since a server will receive arbitrary requests, not just the ones you hope you programmed the frontend to send.

> In theory it sounds great to say "just prevent construction of bad states," but this is a complex problem in professional software

Defeatism.

If you have a User in your domain, and your domain dictates that Users have a UserId, simply do not allow construction of a User without a UserId. What's a UserId? Is it a String, or is it a UUID? If you think the King James Bible translated into Chinese makes for a good UserId, then a String is a perfectly good representation for that. Otherwise pick something more suitable.


I mean I was just trying to have a conversation you don't have to try and roast me with quote-quips and absurdist comparisons... What is happening to this platform these days?

I grounded it.

Any problem can be swept away with "you don't know what you're talking about", "you'll come around to my way of thinking when you're older", "X has nothing to do with Y", etc.

So, make things real with an example.


I think that makes a bad assumption that _you are constructing bad states_ when that isn’t true. You most likely don’t have all the data you need at construction time and the state of the object is still valid. Some data can be null, but later when it is set you want to validate that the data is correct.

For instance when making a person or user you most likely only have their email when you initially create them and then it’s the users job to complete the rest of the data at a later time. Some might want to fill in their age or some might want to fill in their sex. You may never get this data because it’s optional, but when you set it you’ll want to validate it.

And as always in programming _it depends_. It depends on your workflow, requirements, and domain. Being dogmatic about anything is just going to result in worse code.


Use a builder flow, only construct when you have everything you need, don't have any setters, only getters.

That's what I do, anyway.


I personally don’t really like builders. They work in some situations. But if I’m pulling the record from the DB and I only need to set some data on it that is overkill and more complex than need be. The object is already constructed in a valid state.

> The object is already constructed in a valid state.

But that's the entire value proposition of do-not-allow-construction-of-invalid-state!

If a User is actually a User, then you can say "the object is already constructed in a valid state".

If you decide to be 'less dogmatic' and instead construct Users-which-may-or-may-not-be-users-just-throw-an-ex-if-theyre-no-good, then you cannot say that the object is already constructed in a valid state.


I genuinely don't know what you're trying to say here. Perhaps you can show me in code.

That's not the situation described above where data is partial.

In your case I would copy rather than mutate, unless I'm actually getting noticably higher profits from lower memory usage during the time between getting the object and GC. This hasn't happened to me yet.


Maybe I'm not getting what you're saying but the data is partial? In the situation above we have a valid record created by someone else. This is pseudocode obviously, but I genuinely don't know what copying or building or immutability is going to buy me here other than being more complex. There is no worrying about the record being in an invalid state because it could have never gotten to the database in an invalid state.

    class User {
        Long? id;
        String email;
        String? name;
        Integer? age;
        Sex? sex;
        Avatar? avatar;
        
        User(String email) {
             this.email = email;
        }
    }

    record ProfileVm(String? name, Integer? age, Sex? sex, Avatar? avatar) {} 

    // some ui controller
    var user = findById(id)
    if (user == null) {
        return notFound();
    }

    var vm = ProfileVm.fromJson(request.json());
    user.setName(vm.name());
    user.setAge(vm.age());
    user.setSex(vm.sex());
    user.setAvatar(vm.avatar());
    user.save();

    return ok();



Join us for AI Startup School this June 16-17 in San Francisco!

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

Search: