I'm following Domain Driven Design for this project.
I have got an object containing an image. Let's call it Product:
class Product {
UniqueID id;
ProductName name;
ImageBytes imageBytes;
}
UniqueID, ProductName and ImageBytes are just validated objects that represent respectively a String, a String and a List<int>.
I would like to store the actual image on Firebase Storage and saving the imageId on Firestore.
So, in my idea, I have an image on Firebase Storage with id xYF87Ejid0093RTcxaWpof and a Doc in the Firestore containing this id instead of the actual image.
The problem I'm stuck into is writing the Data Transfer Object of a Product. How should I convert an imageId into the actual image?
Please consider that I'm using DDD, so my DTO and my Entity classes are Unions (using Freezed).
I think I should have an intermediate class called FirestoreProduct at the Infrastructure level that looks like this:
class FirestoreProduct {
UniqueID id;
ProductName name;
UniqueID imageId;
}
So that I can write a DTO that uses this class instead and I can create the Product object from the repository class after I downloaded the image. Is there any better way to solve this problem in the DDD way?
Thanks in advance.
Do you really need the ImageBytes to perform the business logic of your product entity? I even guess that your Product is an aggregate root and thus will have data and corresponding behaviour (business logic) in it.
So from my point-of-view the model of your FirestoreProduct is closer to a domain model than your Product class.
I consider your image a separate aggregate which can reside in the same service but a different storage or which could even live in a separate service.
Either way the Product aggregate should only need a reference to the image. I would model it somehow like this
class Product {
ProductId id;
ProductName name;
ImageId imageId;
}
whereas ProductId and ImageId would be value objects for strongly-typed ids.
I expect the storing/upload of a new image to be performed in a separate transaction than creating/updating a product itself. That means when you create a new product or perform some business logic on it to change it your image has already been uploaded to the Firestore and you only work with the image id in your product aggregate.
Your Product DTO (you could also call it view model) on the other hand which you use for providing data for the UI (i.e. for reading data) can look different then the Product aggregate. This is okay and also makes total sense.
So the DTO would look something like this instead:
class ProductDto {
UniqueID id;
ProductName name;
ImageBytes imageBytes;
}
Note: I don't know if ImageBytes is the right type for the DTO as my flutter knowledge is limited but I hope you get the idea.
With that you can bypass the Product aggregate domain repository completely and have another service class which will give you all the data you need for reading/viewing the Product data. As you do not change anything by reading data you do not go through your domain model and optimize for reads.
The code which than builds the DTO will go to your persistence for querying some Product data but also to Firebase for querying the actual image. You could even reload the actual Firebase image afterwards by a separate call from the UI if performance is an issue, for instance if you retrieve a whole list of product data for reading at once.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With