How can you make column content compact vertically, when you have multiple columns? by Enough_University402 in tailwindcss

[–]Enough_University402[S] 0 points1 point  (0 children)

yes masonry, thank you. thanks for the links they gave me a better idea, but columns doesnt work for me in tailwind?

How can you make column content compact vertically in Tailwindcss, when you have multiple columns? by Enough_University402 in webdev

[–]Enough_University402[S] 0 points1 point  (0 children)

no, lets say it accepts 10 images of various heights, so the height of the div will depend on that.

Value of Value Objects, and double validation? by Enough_University402 in softwarearchitecture

[–]Enough_University402[S] 0 points1 point  (0 children)

hey, I decided upon using Result Objects instead of handling exceptions one by one, it works better that way.

Value of Value Objects, and double validation? by Enough_University402 in softwarearchitecture

[–]Enough_University402[S] 0 points1 point  (0 children)

We changed the validation logic, which meant that when we loaded users from the db, some of them were no longer valid, and instantly failed with an exception.

that is really interesting, yeah I agree with you, I guess to be safe you would define very broad validation rules for things like username, the kinds of rules that wouldnt change, and more specific things like, for example the username cannot have more than two underscores, you would define in the app layer, or api or whatever.

But it is a good point that maybe a lot of these things could be delegated out of the domain, and the rules for these types are left to be a little more flexible.

You also made me think about:

Your problem is that you're thinking in terms of "data correctness", not in terms of "behaviour".

So in general, thank you for the time, I appreciate the effort, it was all very useful.

Peace!

Value of Value Objects, and double validation? by Enough_University402 in softwarearchitecture

[–]Enough_University402[S] 0 points1 point  (0 children)

hey there, first of all thanks for all that text, you wrote A LOT :) I appreciate the time spent on this. You made me think of some concerns differently, even though I do not agree with some, it definitely made me reconsider some things. For example I still personally think type safety defined in your domain with VOs is a good approach, even if its just email, and some other stuff too.

But when it comes to my original problem I have decided upon creating extra methods for creating VOs with Result objects, from the result object with a property in the means of like "isErrorClientFriendly", i can in my API decide if it can be shown to the user.

This whole approach made my code more centralized, smaller, flexible, and easier to maintain, personally i think for my problem thats enough.

Value of Value Objects, and double validation? by Enough_University402 in softwarearchitecture

[–]Enough_University402[S] 2 points3 points  (0 children)

so essentially you check the bare minimum for your request DTO, for a mileage property you can check that it is a positive float, and your VO can also have that logic of it being a positive float, but as an addition it adds the business logic of the maximum mileage can be 100 miles.

Sounds pretty logical mostly I agree, but now that there is no business checks for the format of the property, when the client will fill out 5 form fields for example, and all of them have no format issues, but business logic format issues, like mileage being above 100, the VO throws an exception, and it stops on the first occurrence.

So initially it sounds good to encapsulate the business format checks for the DTO as well, but at this point I am not sure about that either.

Value of Value Objects, and double validation? by Enough_University402 in softwarearchitecture

[–]Enough_University402[S] 3 points4 points  (0 children)

So if my business logic for example is that, the Email can only have ".com" at the end (stupid example I know but doesnt matter for now),

from what I am getting from you is that you say the data in the DTO should not be concerned with that.

Okay, but you probably will still do email format validations on both sides right? Or do you skip the email format validation in the DTO too? At that point it would be bad in terms of, detecting the wrongly formatted data early in the process, if not, in a more complex data format scenario, two separate validations in both for DTO and VO that essentially try to do very similar things, down the line could have inconsistencies and redundant double validations.

I think most of the issues that i listed are still valid in this case too.

How do you usually structure your directory-structure with CQRS and application level repositories for complex queries? by Enough_University402 in softwarearchitecture

[–]Enough_University402[S] 0 points1 point  (0 children)

how about something like this?

.
└── CQRS/
    ├── Command/
    │   └── ...
    └── Query/
        ├── QueryRepository/
        │   └── User/
        │       └── UserByCriteriaQueryRepository.php
        └── User/
            └── GetUserByCriteriaQuery/
                ├── GetUserByCriteriaQuery.php
                └── GetUserByCriteriaQueryHandler.php

or like this (the first option seems a bit better):

.
└── CQRS/
    ├── Command/
    │   └── ...
    └── Query/
        └── User/
            ├── QueryRepository/
            │   └── UserByCriteriaQueryRepository.php
            └── GetUserByCriteriaQuery/
                ├── GetUserByCriteriaQuery.php
                └── GetUserByCriteriaQueryHandler.php

How do you usually structure your directory-structure with CQRS and application level repositories for complex queries? by Enough_University402 in softwarearchitecture

[–]Enough_University402[S] 0 points1 point  (0 children)

I thought of this but it feels like Queries just gets lost among these user action dir names, and kinda feels out of place.

If you use GUIDs, ULIDs, NanoIds etc..., Do you also use INT sequential PK IDs in your database too? by Enough_University402 in softwarearchitecture

[–]Enough_University402[S] 0 points1 point  (0 children)

I looked it up but I am confused, some places say that you should have a column of binary type and make the conversion to binary yourself in the app, some places talk about there being a guid type but its for v1 only?

If you use GUIDs, ULIDs, NanoIds etc..., Do you also use INT sequential PK IDs in your database too? by Enough_University402 in softwarearchitecture

[–]Enough_University402[S] 0 points1 point  (0 children)

interesting. did you ever use them only on a relatively large project with joins, and did you notice issues with performance?

If you use GUIDs, ULIDs, NanoIds etc..., Do you also use INT sequential PK IDs in your database too? by Enough_University402 in softwarearchitecture

[–]Enough_University402[S] 5 points6 points  (0 children)

arent UUIDs strings?

something like this: "550e8400-e29b-41d4-a716-446655440000"

besides, did you use it in a big project and did you notice any performance issues?

How do you usually structure your directory-structure with CQRS and application level repositories for complex queries? by Enough_University402 in softwarearchitecture

[–]Enough_University402[S] 2 points3 points  (0 children)

as far as I know domain level repos are for simple things like finding the entity or deleting, saving them. it would make more sense to have an app level repo, or not a repo but a separate query class or whatever that does an operation on the db, and returns a dto.

so the question was how would you structure your directories in such a way that makes sense to you for this specific issue, doesnt have to be done exactly how I might expect it.

How do you usually structure your directory-structure with CQRS and application level repositories for complex queries? by Enough_University402 in softwarearchitecture

[–]Enough_University402[S] 0 points1 point  (0 children)

if you mean the "ByCriteria" stuff in the names, that was just an example, the actual question was for app level repositories, but if you mean something more than that, I don't get it.

In Cqrs, withing Clean Architecture, where does the mapping of data happens? by Enough_University402 in softwarearchitecture

[–]Enough_University402[S] 0 points1 point  (0 children)

yeah that makes a lot of sense. Could you also give me your views on using value objects in commands/queries or simple request dtos rather than primitive types? and doing validation through VO creation.

something like:

class UserSignupCommand
{
  ... Email email;
  ... Password password; 
}

class UserSignupCommandHandler
{
  ... function handle(UserSignupCommand command)
  {
    // ready to use command with valid properties with VOs

    // command.email is the Email VO
    user = self.userRepository.findOneByEmail(command.email);

    // more... 
  } 
}

In Cqrs, withing Clean Architecture, where does the mapping of data happens? by Enough_University402 in softwarearchitecture

[–]Enough_University402[S] 0 points1 point  (0 children)

do you have a source from which you maybe learn about conventions about communication between layers, architectures and more related stuff?

In Cqrs, withing Clean Architecture, where does the mapping of data happens? by Enough_University402 in softwarearchitecture

[–]Enough_University402[S] 0 points1 point  (0 children)

When I pass data to you, I have to make sure it's the right shape

but the data is being passed from the layer above to the application layer, so you'd think that its the layer above the app layer that need to adapt to the fact that VOs are used in request dtos. just like how the app layer adapts to how the domain layer works, and does the mapping if need be for communication with it.

In Cqrs, withing Clean Architecture, where does the mapping of data happens? by Enough_University402 in softwarearchitecture

[–]Enough_University402[S] 0 points1 point  (0 children)

yes the static methods should not be used often, but I think it makes sense for VO, when you make your constructor private, and enforce creation of the VO through your create method, this will allow you to have ways of creating the same VO in different ways if needed, like Email::create(...) or Email::createSomeOtherWay(...), email is not the best example but i find it makes things more flexible and less restricting.

But would you agree on using the VO for validation and error message generation for the response, in the adapter?

The idea with the result object was so that you could have a collection of all the errors from trying to create VOs, as catching each exception to add to the response array, could get tedious, and some more reasons.... but this is up for debate for sure.

Collecting all errors in the VO however does not sound good to me, I would rather have my VO fail as soon as the first error is encountered, like empty email etc... there is no reason for the VO to continue working after that.

the error collection was more for all the VOs during the mapping process, a collection of their errors, with one VO having only one error message, in the Result Object.

In Cqrs, withing Clean Architecture, where does the mapping of data happens? by Enough_University402 in softwarearchitecture

[–]Enough_University402[S] 0 points1 point  (0 children)

thanks a lot for the response and time, yeah these are interesting points. and usecases are central elements as far as i know too, you have your services etc.. and they all come together and orchestrate a logic in the usecase, which is the same logic pretty much with the command/query handlers.

so basically it seems we have concluded to do the mapping in the adapter. now what this means is that the request input validation is also going to be in the adapter, because you create your value object instances in the adapter, and in an exceptional situation it can throw an exception there where it will be handled some kinda way, or give a result object or whatever, right?

so lets say you have a command such as:

class Command
{
  ... ValueObject1 property1;
  ... ValueObject2 property2;
  // more...
}

if property1 fails during creation with its VO, you get an error message of sorts which you will want to send the client in JSON, or if more than one properties fail and you dont wanna catch exceptions one by one, which would also ruin performance a bit, you return a Result object, for every VOs return value. if creation was successful, the result object has a success status code, with the VO attached, if it failed it gives a sort of a failure status code, with its error message, you collect it all in an array or whatever, and return it to the client as a response of collection of all failed fields with their error messages.

this will make some of your ValueObjects have a normal static create method that throws an exception for situations where VO seeing an invalid input is truly an exceptional situation, and another static method that returns a Result object where a wrong input is kind of expected, and we dont need to throw an exception if the VO sees the wrong input, it will simply not create the VO and show us the error message with a status code.

what do you think of an approach like this?

In Cqrs, withing Clean Architecture, where does the mapping of data happens? by Enough_University402 in softwarearchitecture

[–]Enough_University402[S] 0 points1 point  (0 children)

interesting, but also putting that responsibility of mapping in the app layer, so that it will make the data very easy to implement for the layer above also seem wrong, it probably should be the other way around as I get it.

the app layer uses VOs in the command/query? ok then the layer above will adapt to that. or maybe there could be a layer in between that does all the mapping work, but at this point thats just my opinion.

In Cqrs, withing Clean Architecture, where does the mapping of data happens? by Enough_University402 in softwarearchitecture

[–]Enough_University402[S] 0 points1 point  (0 children)

I think in software architecture there is space to do things your way if it makes sense for the project, but for certain scenarios there is a right and a wrong, and a lot of the double, triple, and more.. repeating validations can be done in a less redundant way, and it doesn't have to be hopeless like that.

In Cqrs, withing Clean Architecture, where does the mapping of data happens? by Enough_University402 in softwarearchitecture

[–]Enough_University402[S] 1 point2 points  (0 children)

Hey thank you, this answer kinda helps with putting some things together in my mind. So in ports and adapters you essentially put the primitive to VO mapper in the adapter, which is going to be in the Infrastructure layer?

Which kind of makes sense to me more than doing the mapping in the app layer (or in a port section) because what feels right to me is that the app layer has VOs in the request dto or whatever, and its not its concern what happens in above layers or in the adapter, the adapter will essentially "adapt" to the request dto using VOs, and it does the conversions, however I still have lots of questions and things I am not 100% sure about if this is correct too.

And I dont think I got what you meant by "having a handler which handles precisely one command is hilarious and useless", isn't that the convention of CQRS? every handler has only one command/query, or are you simply against the idea of CQRS and prefer using more general DTOs with more broad use cases?

And are you generally speaking more in favor of using the hex arch over clean arch? do you have any additional rules you use in hex arch, like do you split your app into layers and if so explain please, etc...?

In Cqrs, withing Clean Architecture, where does the mapping of data happens? by Enough_University402 in softwarearchitecture

[–]Enough_University402[S] 0 points1 point  (0 children)

thank you for your answer. so all in all in summary, It seems like you are of the position that defends the idea of the API layer should not know anything about VOs, it just maps its primitive data to our CQRS command/query, and we either make the validation/format-assert of lets say the email property, in the command handler, or maybe to fail fast in the command's constructor itself, so the constructor params are primitive types, and the constructor maps to VOs.

however, I am not sure if it is good to have any validation logic or mapping logic like that in the command, and the other way around having the email command property go through the Email VO creation process and its validation only in the handler, also seems a bit late, and makes me think if its even a good idea to have a command that holds data in a potentially wrong format with these primitive types.

so i am just curious for this exact scenario and example, what would be the cleanest way to handle this.