Skip to content

Instantly share code, notes, and snippets.

@SelrahcD
Last active November 23, 2016 21:33
Show Gist options
  • Save SelrahcD/d56f19bd832060dedad29a6ba3b842b1 to your computer and use it in GitHub Desktop.
Save SelrahcD/d56f19bd832060dedad29a6ba3b842b1 to your computer and use it in GitHub Desktop.
Time sheet system
In my opinion we have two options :
1) The notion of time sheet is only a view concept (I want to see all entries of week #10) :
* a TrackTime command that only creates a new entry in a list and takes the (time; imputation) as parameters
* TimeSheet is a projection of the entries, here probably a subset of the list entries
2) The notion of time sheet is important in domain (I don't have an example...) :
* a TrackTime command that adds an entry for that specific time sheet and takes (timesheetId; time; imputation) as parameters
* TimeSheet can possibly be used in the read model too. (Lot of ifs here)
For both cases if an entry had to be modified I'd go with a CorrectTimeEntry(timeEntryId, correctedTime) command.
@webdevilopers
Copy link

Currently I am lucky and the UI for TimeSheet creation and update share the same fields.
I only use to different constructors on both commands - one fromContract (setting the Project for instance) and fromTimeSheet (setting the ID and Project etc. from the existing TimeSheet).
Currently 2 commands and 2 Handlers. Maybe there will be some more logic involved soon. E.g. some read only fields that should not be changed.

But to take it away from my example: let's say your UI has about 30 fields and the form and Command (DTO) share the same data except that the UPDATE one has the ID: would you really "duplicate" that code?

It's fine with me - since it is no duplication in a sense of domain code. And large DTOs could be UI design problem.

@SelrahcD
Copy link
Author

SelrahcD commented Nov 17, 2016

Currently I'm lucky

This is interesting, because it indicates something that is just coincidental. This as a lot to do with DRY. This article is really interesting if you haven't read it yet : http://verraes.net/2014/08/dry-is-about-knowledge/

As a second example will a User Profile (email address, age, profile picture, ...) do the job ?

I guess, yes, the command could be the same for both create and update but I'm not sure CQRS is a good fit for this kind of project. A bit overkill. If the domain doesn't require a precise level of granularity maybe a CRUD app would do the job, then why bother. CRUD apps are cheap and easy to setup.

Does it make sense to the domain expert to update the profile in one shot ? Can you (as a dev) make the whole system work listening to a event saying that 30 properties have changed ? This are the questions I'd try to answer first.

I tend to think that a command with so much properties is an indication that it does too much. If it's an issue then try to get more knowledge and refine. If not, install a CRUD framework and hop, done :)

@mauroservienti
Copy link

Sticking to the time sheet sample:

But to take it away from my example: let's say your UI has about 30 fields and the form and Command (DTO) share the same data except that the UPDATE one has the ID: would you really "duplicate" that code?

The question I'd ask is: what happens when a time sheet entry is changed (update)? If there must be a consequence then I'd design it with 2 commands and 2 different events.
A time sheet can be seen as a event stream, each time sheet entry represents a event in the past, if this is the case one should not be allowed to change history. If it happens, e.g. a entry is updated, it is a completely different story compared to a new entry is created.

The scenario is much more foggy when it comes to things where the business meaning/value is near to zero, take for example the concept of a draft. The draft might have hundreds of fields, but until it is a draft what happens simply doesn't matter, in such a case modelling this specific concept with CQRS, and even in the DDD world, might be overkill and feel useless. If you think about it's a pure CRUD.

In the above scenario, IMO, [1] is merely a CRUD, the second one fits much better a DDD/CQRS world. And in my experience a time sheet on its own means nothing, a time sheet (on the contrary) has a lot of business value in the broader context (e.g. ERP, Accounting apps, management apps, etc.) where what happens at the time sheet level impacts other elements in the ecosystem.

@SelrahcD
Copy link
Author

I've been thinking about it since I wrote it and clarifying what a TimeSheet is would help for the conversation.

As I see it (from my past experiences with time tracking software) it's a recap of time entries during a week. We have two notions : opening a new TimeSheet and tracking a new entries. And then separated commands : OpenTimeSheet (could be triggered by a CRON, a create cmd), TrackTime (a create cmd), CorrectTimeEntry (an update cmd - would be a create command too if doing event sourced).

The notion of time sheet is important in domain (I don't have an example...)
I found an example : If an employee can have several opened time sheets at the same time. A freelance working for several companies for instance.

The draft example is a good one. I've been working with this concept a few days recently and we had several notions :

  • StartDraft
  • UpdateDraft
  • PublishDraft

We used two different commands for StartDraft and UpdateDraft. Some of the code looked a lot the same (we had only a few fields so it wasn't really an issue). If the number of fields had grown we probably would have introduced some sort of service playing with command data to populate all the fields. Looks like a lot of setters would be needed though, which points out we're getting closer to something CRUDy. I guess a service and an abstract command are quite the same in the end, so yes, an abstract command would work. I won't use the same command yet and keep the two "real" commands separated.

I suppose using an abstract command for similar commands is ok for exceptional cases but if it's the norm of the system a CRUD app would probably have done the job perfectly.

@webdevilopers
Copy link

webdevilopers commented Nov 23, 2016

Since I can't upvote on gists and we don't get any notifications I moved the discussion to the PHPDDD project:

See you there!?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment