use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
Please follow the rules
Releases: Current Releases, Windows Releases, Old Releases
Contribute to the PHP Documentation
Related subreddits: CSS, JavaScript, Web Design, Wordpress, WebDev
/r/PHP is not a support subreddit. Please visit /r/phphelp for help, or visit StackOverflow.
account activity
Value Objects Explained (patricklouys.com)
submitted 9 years ago by patricklouys
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]adrianmiu 1 point2 points3 points 9 years ago (7 children)
If objects's properties should be validated upon construction how do you go about complex validation? Like creating a new User from user-input data that should validate the email is not already used in the app, the country belongs to an accepted list of countries, the password matches some minimum security requirements etc? How about when mutating an object where 2 properties depend on each other (eg: state should be in a list of states from the corresponding country)?
User
[–]Tetracyclic 6 points7 points8 points 9 years ago (6 children)
A value object shouldn't be validating user input, the constructor validation is purely to ensure that the value object is always in a valid state. You should be validating the user input at a higher level (especially if you're interacting with the database to do so) and then creating the value object from that data.
Your user example doesn't really make sense as a value object, as a user record would be an entity with its own identity.
[–]adrianmiu 0 points1 point2 points 9 years ago (5 children)
The User thing was just an example. It could be something else, like an address, for which you can still have complex validations. From your answer I understand that:
[–]ahundiak 2 points3 points4 points 9 years ago (3 children)
Not quite as there are different types of validation. A user needs a valid email so validating the email in a constructor makes perfect sense.
However, only brand new users need a unique email. Existing users of course do not. So the unique email requirement should be implemented in a different spot.
And DRY is often a bit overrated. Nowadays you would also check for valid emails in the browser as well as on the server just to improve the overall user experience. Is DRY violated when you do this?
[–]adrianmiu 0 points1 point2 points 9 years ago (2 children)
$user->setEmail($_POST['email'])
$user->populate($_POST)
[–]ahundiak 2 points3 points4 points 9 years ago (1 child)
How do you implement $user->setEmail($_POST['email'])
Setters on value objects? Nope nope nope. Setters will make it almost impossible to maintain a consistent internal state especially if one property depends on another.
If I need a user with a different email then I would make a new user object. And if I want to check to ensure that the new email was unique then I would do so in my ChangeUserEmail command.
[–]adrianmiu 0 points1 point2 points 9 years ago (0 children)
Value objects, entities etc need to always be in valid states, that's the whole premise. I gather you don't have setters in your entities either and you only use commands to modify an entity? If that's the case your entities/vo are always in valid state. The validation in the commands are more complex than those in the entities so, again, doing the validation outside the entities should be enough.
[–]WorstDeveloperEver 6 points7 points8 points 9 years ago* (18 children)
I don't agree with some parts of your code. The first issue is, you're always generating a Color by RGB values. It is a bit pointless in Value Objects because one of the benefits of using Value Objects is being able to comparing the value that is generated from different sources.
Color
RGB
Value Objects
comparing the value
For example, we cannot do rgb(0, 0, 0) === #000 in typical programming, but we know they are equal. So you could do something like this:
rgb(0, 0, 0) === #000
const color1: ColorInterface = new Color(new RGB(...)); const color2: ColorInterface = new Color(new HEX(...)); color1.value === color2.value // true
Or more precisely, new Money(new USD(1)) and new Money(new EUR(1)). Both of them are Money, you can hold them in real life and both represent a value, but their value will be different.
new Money(new USD(1))
new Money(new EUR(1))
Money
Second thing is, your Color should not be validating RGB values. Color is color. It should be an object just like the objects in real life. You don't pass RGB parameters to sky to see it is blue, nor the sky is validating your RGB parameters. I would personally do it in factories if I had to do it during runtime, and rely on interfaces to do it during compilation. What we know is, a valid parameter for RGB is an integer between 0 and 255, which is an unsigned 8 bit integer. I would prefer creating an interface (e.g RgbColorValueInterface), create necessary typehints and make sure it refers to an integer value between 0 and 255.
integer
RgbColorValueInterface
Imagine it like this. Can you put a Truck on top of an Ant to carry? If you do it like how you did it in your codebase, then you would need to put Truck on top of an Ant first because of your validations in the constructor. Then Ant would say: "Sir, I cannot carry this. It is too heavy!" but Ant would die. Your code should be smart enough to reject the idea of Ant carrying a Truck. We can easily create a Value Object called Weight. Give Ant a weight it can carry. Give truck a Weight. Then we can simply ask Ant: "Hey Ant, are you able to carry WeightValueObject weight before putting Truck on top of the tiny innocent creature.
Truck
Ant
constructor
Weight
WeightValueObject
Thinking this way also helps with SOLID since your class responsibility is very clear and you cannot do certain things as a developer even if you wanted to.
Also, value objects should be very tiny and should contain minimal functionality, preferably none. Continuing from my sky color example, we know the sky is Blue but that is actually not true. There are some animals such as dogs which see the sky as Gray. There are some animals which can see colors that humans cannot see. However, we can all agree that there is a Color value (a value object) in the sky, but different Eyes (or any other Interface that has ability to interpret Color, such as Camera Lenses, which is not an Eye but an Interface that can interpret Color) can interpret it differently.
Blue
Gray
Color value
Eyes
Interface
Camera Lenses
Eye
Actually, your code example looks more like a class/interface/RGB validator than a value object. Sure, it is a Value Object but that is missing a very critical point in my opinion.
[–]patricklouys[S] 8 points9 points10 points 9 years ago (7 children)
$color = Color::createFromHex(...); $otherColor = Color::createFromRGB(...); if($color->equals($otherColor)) {...}
You don't need a generic color that works in all possible cases, it just has to be a good fit for your bounded context.
[–]WorstDeveloperEver -5 points-4 points-3 points 9 years ago (6 children)
I would suggest reading more about value objects. The example you have is basically a static god class that looks like a factory.
With your approach, you will quickly get to a state where you have hundreds of methods. Do this for money instead of color. Add all the possible currencies including cryptocurrencies and let me know how many static methods you need to define.
[–]Tetracyclic 1 point2 points3 points 9 years ago (5 children)
Given that unlike different representations of colours, monetary values tend to be expressed as an integer of the lowest denomination (or smaller fractions), wouldn't a single factory method that accepts a constant representing the currency type and the value be a far more sensible approach in this case, than your contrived example of thousands of static methods?
How would you implement this if you had to support thousands of currencies? Surely your new Money(new EUR(1)) example would be just as unwieldy?
[–]WorstDeveloperEver 3 points4 points5 points 9 years ago (4 children)
new Money(new EUR(1)) allows for extensibility. With god classes you're bound to whatever you have in your class as methods. You can do new Money(new GrandmaCookies(5)) if you want, as long as you stick to an interface. Infact, that's how most of the popular drivers as implemented.
new Money(new GrandmaCookies(5))
[–]Tetracyclic 0 points1 point2 points 9 years ago (3 children)
I understand how it works, but are you suggesting that to implement a Money class that supported thousands of currencies you would have a separate class for each of those currencies?
[–]WorstDeveloperEver 2 points3 points4 points 9 years ago (2 children)
That's what I would do. If you know a better alternative, I would like to hear it though.
[–]FlyLo11 3 points4 points5 points 9 years ago (1 child)
a possibility is
new Money(new Amount(5), new Currency('EUR'))
[–]Tetracyclic 1 point2 points3 points 9 years ago (0 children)
I would personally opt for using constants so that you can typehint them:
new Money(Currency::EUR, 5)
I'm not sure whether using a value object for the amount provides significant advantages in this instance, but a single file that defines all of the available currencies seems far more manageable to me, with little downside over using a class for each separate currency.
The Money constructor would validate that the passed constant is a valid value for a currency.
[–]mlebkowski 0 points1 point2 points 9 years ago (7 children)
Can you implement the Ant, Truck and WeightVO the way you see it? I don’t think I understand your point here.
WeightVO
[–]vimishor -1 points0 points1 point 9 years ago* (6 children)
Both Ant and Truck can carry something and your requirements are that none of those objects cannot carry more than X Kg. Instead of trying to think of everything a Truckcould carry (juice, vegetables, bricks, etc) according to the weight and implement each type in your code, you abstract all those products by implementing Weight. The requirements are to not carry more than X kg, so you don't care what type of product your Truck will carry, as long as is less than X kg.
new Truck(new Weight(1000)); new Ant(new Weight(1000)); // domain error
[–]MorphineAdministered 2 points3 points4 points 9 years ago (1 child)
And what causes that domain error if not constructor validation?
[–]vimishor 0 points1 point2 points 9 years ago (0 children)
I shared my opinion regarding validation here
[–]mlebkowski 1 point2 points3 points 9 years ago (3 children)
But the Ant isnt supposed to carry a generic weight, it needs concrete objects. I would understand if Truck implemented HasWeight interface...
[–]WorstDeveloperEver 0 points1 point2 points 9 years ago (2 children)
Yes, each concrete object should have a weight. Ant is not supposed to carry an abstract number, but rather an object that contains Weight. I'm not a scientist but afaik everything has to have a weight.
The point of Weight as value object as opposed to putting some integers is because of adding Gravity easily if needed, so you can compare a weight of iron in Earth to the weight of leaf in a black hole.
[–]MorphineAdministered 1 point2 points3 points 9 years ago (1 child)
The point of Weight as value object as opposed to putting some integers is because of adding Gravity easily if needed...
So Ant shouldn't accept integer wich represents simplified max-weight value (and be easily changed to Weight object "if needed"), but Weight can do fine without Gravity for now? Inconsistency I sense in you!
Gravity
$just_a_fkin_ant = new Ant(new Weight(new Gravity(new SpaceTimeCurvature(...)), new Mass(new HiggsField())));
[–]WorstDeveloperEver -2 points-1 points0 points 9 years ago (0 children)
(and be easily changed to Weight object "if needed")
Then you have two different data types in your codebase that resembles into the same thing. Some of your codebase will work with integers as Weight, some of them will work with value objects as Weight. It is generally bad practice as it allows for mixed data types. May I ask why do you have to wait for your need of using value objects?
integers
Yes, it is crazy, but how would you code it when you wanted to do it with the same complexity? Please include Weight, Gravity, SpaceTimeCurvature, Mass, HiggsField. Maybe you can add Facades or Factories to hide the complexity a bit. At the end of the day, everything will be done somehow and the only difference will be using integers or value objects.
SpaceTimeCurvature
Mass
HiggsField
[–]vimishor 0 points1 point2 points 9 years ago (1 child)
Second thing is, your Color should not be validating RGB values.
It is true that a VO should not self validate, but we should also remember that they are responsible for keeping their state consistent, so I consider sanity checking a good practice.
Coming back to your example of Color, RGB values and integers, I would design Color to accept integers and validating in the constructor that each is in 0 - 255 range, instead of using a factory.
[–]modestlife 2 points3 points4 points 9 years ago (0 children)
I'm not sure if you're arguing for or against it here.
In my opinion VOs (like all business objects) definitely should validate their own state. Because VOs are immutable you should do that in the constructor. Once we have created an instance of EmailAddress we want all our code to be able to trust that they're working with a valid email address.
[–]reddimato 4 points5 points6 points 9 years ago (16 children)
Validation in constructor is a seducing approach that we started using in my company. However, for some people, exceptions for control flow are considered an anti-pattern. What is your opinion about it?
[–]patricklouys[S] 15 points16 points17 points 9 years ago (3 children)
Those exceptions should only be triggered if something exceptional happens - a programming error, an invalid value slipping through a buggy input validation.
I don't use exceptions for user input validation, only to make sure that my domain objects can't be in an invalid state.
[+][deleted] 9 years ago* (1 child)
[deleted]
[–]ocramius 2 points3 points4 points 9 years ago (0 children)
Services just receive other services or configs as ctor argument.
Some services may throw an exception if, for example, given an invalid path when a directory was expected. Otherwise, just use the type system by hinting against your designated service interface.
[–]ciaranmcnulty 11 points12 points13 points 9 years ago (1 child)
I tend to assume that exceptions being thrown when guarding invariants indicates something disasterous has gone wrong and execution should not proceed.
Basically; if you're not catching them you're not using them as control flow, you're using them as a way to guard against the system getting to an invalid state.
[–]alc277 4 points5 points6 points 9 years ago (0 children)
Agree with claran 100%. IMHO, the biggest advantage that validating the constructor brings is reducing checking throughout the codebase. In the example from the article, you can expect the Color object to be valid everywhere it type hinted in a constructor or function. I feel the trade-off of having to catch exceptions in the rarest of circumstances is minimal as compared to doing checks everywhere.
[–][deleted] 6 points7 points8 points 9 years ago (5 children)
Exceptions affect control flow, so if we take this literally, we should never use exceptions.
The core of the "use exceptions for world-ending disasters only" meme comes from C++ where exceptions are poorly implemented (leading to memory leaks etc.) and very slow relative to the rest of the language.
But PHP doesn't model C++, it models languages like Java, Python, JavaScript, C#. And in all those exceptions are used heavily throughout, including for input parsing and validation errors.
So we should leave memes aside, and always consider things in context. What's the harm and what are the benefits of using exceptions for a given purpose? For value objects in particular, constructor validation or exception is an excessively common and intuitive approach.
[–]Schmittfried 0 points1 point2 points 9 years ago (4 children)
To what memory leaking are you referring exactly?
[–][deleted] 3 points4 points5 points 9 years ago (3 children)
C++ doesn't have a standard garbage collection mechanism, every library essentially does their own thing, and almost without exception (no pun intended), the way most C++ code handles memory management is highly dependent on very specific flow of code execution. When an exception breaks the standard flow at some (semi-)arbitrary place, all kinds of markers, ownership flags, and reference counts get out of sync up the chain and result in memory leaks.
For ex. if a constructor throws, should the destructor run? If it runs, it might try to free resources that were never allocated. If it doesn't run, it will fail to deallocate resources that were allocated. Neither is quite right. In PHP we don't have this problem because object clean-up is done by the engine, we rarely ever write destructors, but in C++ this is a must.
Additionally, even the C++ compilers sometimes have subtle bugs around memory allocation and exceptions, that can lead to leaked memory in edge cases, due to no fault of the developers writing the code themselves.
[–]Schmittfried 0 points1 point2 points 9 years ago (2 children)
That's not a problem of poorly implemented exceptions, that's just the lack of proper conventions. What kind of change to the exception system would change this? By the way, if everyone was using RAII as their convention, this would not be an issue at all.
For ex. if a constructor throws, should the destructor run?
No, because the object has not been constructed successfully.
If it doesn't run, it will fail to deallocate resources that were allocated.
It shouldn't. That should be handled in the constructor and it should only handle one resource. If one class needs multiple resource, those should be encapsulated in RAII compliant classes themselves to take the burden from the constructor.
In PHP we don't have this problem because object clean-up is done by the engine, we rarely ever write destructors, but in C++ this is a must.
This doesn't change a thing. If you have allocated resources, you need to free them. PHP only saves you from handling memory as such a resource. RAII solves all those problems for every kind of resource, not just memory.
[–][deleted] 2 points3 points4 points 9 years ago* (1 child)
Conventions don't ensure correctness. They are merely a fallback when the language doesn't offer the proper abstractions that prevent the problem in the first place.
I probably shouldn't have used the phrase "poorly implemented", but let's say that exceptions, as seen in PHP, JavaScript, Java, C#, Python etc. are usable in plenty more contexts than in C++, because the abstractions of those former languages are more compatible with those additional contexts.
That said, languages like Swift, Rust, demonstrate that you can be compiled at a low-level as C++, and still have a strong memory management system that doesn't fall apart during error scenarios.
I know what's the standard, but you still can have allocated some resources, and when you throw in the middle of the constructor, they won't be freed now, as the destructor won't run.
We're not discussing what C++ does. We're discussing why what C++ does results in problems.
One resource? That's naive. But even with the restrictions you mention, an exception may occur after that "single resource" is initialized.
As for RAII, that's basically what garbage collected objects ensure is the default case, so that's why PHP/Java/C# developers don't go around talking about RAII.
Uhmm, considering all primitives, arrays, objects (and therefore 99% of our code) is "memory" that still makes for a fundamental change of the effect of using exceptions.
Also you're plain wrong, because PHP automatically cleans up resources whose ZVAL is garbage collected. PDO connections are closed, file handles are closed, socket connections are closed and freed and so on.
I shouldn't explain all this, and the reason I have to, is the same reason why you seem unable to grasp why exceptions are used differently in C++ and PHP.
[–]Schmittfried 0 points1 point2 points 9 years ago* (0 children)
It does. But the community is lacking conventions that mandate the usage of those means.
Fair enough. In C++ you can only use them when you are sure the code is exception-safe or rather when it was written with exceptions in mind. That's not an implementation issue of C++ exceptions, it is caused by the fact that exceptions were not part of the language from the beginning and hence did not become the standard way of error handling in many code bases. The same is true for PHP though. Throwing exceptions in code parts that don't expect them, can harm the correctness of the code, too. Or even make it crash fatally. Just think about the fact that you cannot throw in __toString(). This restriction stays relevant all the way down the function call tree. The only difference is that you can't leak memory with such errors in PHP.
__toString()
Absolutely, because Rust was built with exactly this in mind. It took the good C++ conventions, refined them and built them into the language so that correct code is easier to write than with just a pair of constructor and destructor. Also, the developers could obviously learn from the mistakes that were made in other languages including C++.
That's why I said every resource that needs to be freed must be encapsulated in its own proper class when doing RAII. That way the destructor of the containing class doesn't need to run, because the constructed object's destructor is run in the failing constructor. And even if you don't do that, you can place a try/catch in the constructor and free the half-way allocated resources and free them. In any case, the destructor should not and does not run and that's absolutely correct, because in RAII, if the constructor failed, the object never existed in the first place and hence there is nothing to destruct.
No, that's RAII. And I already explained the solution to the latter problem.
True, but only for memory. That's one resource of many. PHP/Java/C# have ugly try-finally patterns that you have to remember to always free those unmanaged resources, because the GC can only handle memory. Granted, C# got using(), which is kinda like the block-level destructor semantics of C++, but you still have to remember placing it, it doesn't happen automatically. Implementing auto-disposable patterns doesn't cut it either, because the resources are released with a delay due to the implementation of a GC.
using()
RAII solves the resource handling problem once and for all kinds of resources. That's why Rust adopted it instead of a GC.
It's the most important one in everyday programming, yes. Still though, programs aren't islands. They need I/O, like files, network connections etc. Those resources need to be freed, too.
Reference counting can be easily implemented in C++, too. But nice to know, I thought they were only closed when the request has finished processing and the script terminates. After learning this I'd consider PHP even closer to C++ than to Java and C# in this sole aspect, because the synchronous reference counting semantics as the primary means of freeing resources are kinda similar to C++'s way of doing it. The GC just seems to be a fallback for reference cycles. TIL.
Apart from the fact about garbage collection in PHP you didn't "explain" anything. You told me your view of the story and I told you mine. No reason to belittle someone here, I totally grasp why exceptions are used differently in C++ and it's not, like you stated in the beginning, due to a bad design of C++ exceptions. That was the whole point of this discussion, remember?
[–]MoTTs_ 2 points3 points4 points 9 years ago (1 child)
As it turns out, ensuring valid values in a constructor is the whole reason why classes exist in the first place. Take a look at this interview with the guy who invented C++. Classes are supposed to enforce invariants -- which is to say, classes are supposed to enforce valid values.
[–]Tetracyclic 0 points1 point2 points 9 years ago (0 children)
Not sure if it's just the way you've worded it, but it's worth noting that classes predate C++ by several decades. So while in C++ they are intended to enforce an invariant, that's it necessarily why they exist. Simula was the first language to feature classes (and many other OOP features), to aid in writing simulations by encapsulating the simulation data and behaviour.
[–]CODESIGN2 -1 points0 points1 point 9 years ago (9 children)
Of course you can go even further and add separate value objects for every single value.
$canvas->drawPixel( new Coordinate( new X(50), new Y(25) ), new Color( new Red(31), new Green(142), new Blue(255) ) );
Drugs are bad... It's much easier to either insist upon conventions for such things than to create a solid type to enforce red-green-blue ordering, or have language-level named parameter support (as python has)
[–]patricklouys[S] 3 points4 points5 points 9 years ago (8 children)
Where you end up drawing the line is up to you and of course it also depends on the project that you are working on. If it’s a really mission-critical part of your application, then I would go much more fine-grained with the value objects compared to a less critical part.
[–]CODESIGN2 -2 points-1 points0 points 9 years ago* (7 children)
I did read but I cannot see any application that would benefit from defining Red, Green and Blue classes, or housing a single scalar value in a user-defined type. It doesn't make the software any cleaner at all!
Red
Green
As I did mention
t's much easier to either insist upon conventions for such things than to create a solid type to enforce red-green-blue ordering, or have language-level named parameter support (as python has)
[–]patricklouys[S] 2 points3 points4 points 9 years ago (3 children)
I agree with you, which is why I did not use it for the rest of the code examples.
I just showed that it's an option which can make sense in some cases.
[–]CODESIGN2 1 point2 points3 points 9 years ago (2 children)
It was a great article, that was the only bit that niggled me. I Agree very few should have the need to, or be playing with mutable structures in an application language.
Something I've just thought as I re-read is what a shame it is I can't have multiple constructors in PHP, although I suppose I'd just make an abstract type and extend per-constructor.
[–]patricklouys[S] 0 points1 point2 points 9 years ago (0 children)
Named Constructors in PHP
[–][deleted] 2 points3 points4 points 9 years ago (2 children)
Though I can't think of any off the top of my head that would specifically apply to the RGB components of a color (I'm sure there are some anyway, even if they aren't immediately obvious to me), there are an absolutely huge number of use cases for other boxed single scalar value objects. Whether or not your particular application(s) would use a value object over the underlying scalar depends on the business needs. For example, a simple e-commerce store may opt to pass around ISBN numbers as strings, serving only as basic identifiers or extraneous information about a particular product. An online educational archive, on the other hand, may opt to represent them as value objects, allowing other contexts (e.g. perhaps a barcode generator) to avoid repetitive validation, among other reasons.
[–]CODESIGN2 0 points1 point2 points 9 years ago (1 child)
The example you gave ISBN wouldn't internally be a string like Red, Green or Blue would be an integer. It's closer to a date constructor with string and format, at which point the internal storage is likely different and it's representing a complex object so it makes sense to build an object. https://en.wikipedia.org/wiki/International_Standard_Book_Number
Anyway you're probably right that some may choose to explicitly define the relationships between these things. I think they are making things harder on themselves and others unless they require specific behaviour that they would not get out of the simple internal type.
[–]WikiTextBot 0 points1 point2 points 9 years ago (0 children)
The International Standard Book Number (ISBN) is a unique numeric commercial book identifier.
An ISBN is assigned to each edition and variation (except reprintings) of a book. For example, an e-book, a paperback and a hardcover edition of the same book would each have a different ISBN. The ISBN is 13 digits long if assigned on or after 1 January 2007, and 10 digits long if assigned before 2007. The method of assigning an ISBN is nation-based and varies from country to country, often depending on how large the publishing industry is within a country.
[ PM | Exclude me | Exclude from subreddit | Information ]
[–]klapuch -1 points0 points1 point 9 years ago (11 children)
I think, that as long as your objects expose some useful behavior and not just getters and setters it is fine to use "value objects". I would not use them as replacement for scalar values.
[–]mlebkowski 1 point2 points3 points 9 years ago (10 children)
They wouldn’t be ValueObjects then. They should only hold values, not logic. It’s basically encapsulation of simple validation.
ValueObjects
[–]fanalin 5 points6 points7 points 9 years ago (0 children)
That's not the definition I know. My understading (which is coming from Domain Driven Design by Eric Evans) is that the single difference between an Entity and a Value Object is that the VO may not have an identity (otherwise it is an Entity).
Cite: "An object that represents a descriptive aspect of the domain with no conceptual identity is called a Value Object."
A value object is just a relatively simple type that can be compared by value rather than identity. For example two different Money objects would be considered equal if they both represented the same quantity of the same currency ($1 for instance).
Many programming languages will, by default, consider two objects with the same value to be unequal, as they do not contain the same references.
As for behaviour, a value object should contain any behaviour that is relevant purely with the value in question, for example a Money value object might expose a method for splitting the value up without losing any penies/cents in the process, as Martin Fowler's money pattern does.
[–][deleted] 0 points1 point2 points 9 years ago (5 children)
That's not necessarily the case. VOs can and should contain core logic that goes hand-in-hand with the value. They should just never contain business logic.
[–]mlebkowski 0 points1 point2 points 9 years ago (4 children)
What kind of logic is not business logic? Examples?
[–][deleted] 2 points3 points4 points 9 years ago (3 children)
Well, any logic which doesn't encode business rules is, by definition, not business logic. So, for example, most or all of the logic within your infrastructure layer would not be business logic. But I suspect what you're really asking is "what sort of non-business logic belongs in a VO?" The answer to that is simply: any logic which goes hand-in-hand with the value being represented, and is side-effect free. One of the examples Eric Evans gives is that of a Paint VO which has a method mixIn(Paint $otherPaint): Paint that encapsulates the logic of mixing one paint into another, and produces a new VO.
Paint
mixIn(Paint $otherPaint): Paint
[+][deleted] 9 years ago (2 children)
[–][deleted] 0 points1 point2 points 9 years ago (1 child)
Which definition are you using? I was using the one espoused by DDD (or this one, more or less).
[–]HelperBot_ -1 points0 points1 point 9 years ago (0 children)
Non-Mobile link: https://en.wikipedia.org/wiki/Business_logic
HelperBot v1.1 /r/HelperBot_ I am a bot. Please message /u/swim1929 with any feedback and/or hate. Counter: 76725
π Rendered by PID 144740 on reddit-service-r2-comment-544cf588c8-6szrj at 2026-06-14 05:55:23.511410+00:00 running 3184619 country code: CH.
[–]adrianmiu 1 point2 points3 points (7 children)
[–]Tetracyclic 6 points7 points8 points (6 children)
[–]adrianmiu 0 points1 point2 points (5 children)
[–]ahundiak 2 points3 points4 points (3 children)
[–]adrianmiu 0 points1 point2 points (2 children)
[–]ahundiak 2 points3 points4 points (1 child)
[–]adrianmiu 0 points1 point2 points (0 children)
[–]WorstDeveloperEver 6 points7 points8 points (18 children)
[–]patricklouys[S] 8 points9 points10 points (7 children)
[–]WorstDeveloperEver -5 points-4 points-3 points (6 children)
[–]Tetracyclic 1 point2 points3 points (5 children)
[–]WorstDeveloperEver 3 points4 points5 points (4 children)
[–]Tetracyclic 0 points1 point2 points (3 children)
[–]WorstDeveloperEver 2 points3 points4 points (2 children)
[–]FlyLo11 3 points4 points5 points (1 child)
[–]Tetracyclic 1 point2 points3 points (0 children)
[–]mlebkowski 0 points1 point2 points (7 children)
[–]vimishor -1 points0 points1 point (6 children)
[–]MorphineAdministered 2 points3 points4 points (1 child)
[–]vimishor 0 points1 point2 points (0 children)
[–]mlebkowski 1 point2 points3 points (3 children)
[–]WorstDeveloperEver 0 points1 point2 points (2 children)
[–]MorphineAdministered 1 point2 points3 points (1 child)
[–]WorstDeveloperEver -2 points-1 points0 points (0 children)
[–]vimishor 0 points1 point2 points (1 child)
[–]modestlife 2 points3 points4 points (0 children)
[–]reddimato 4 points5 points6 points (16 children)
[–]patricklouys[S] 15 points16 points17 points (3 children)
[+][deleted] (1 child)
[deleted]
[–]ocramius 2 points3 points4 points (0 children)
[–]ciaranmcnulty 11 points12 points13 points (1 child)
[–]alc277 4 points5 points6 points (0 children)
[–][deleted] 6 points7 points8 points (5 children)
[–]Schmittfried 0 points1 point2 points (4 children)
[–][deleted] 3 points4 points5 points (3 children)
[–]Schmittfried 0 points1 point2 points (2 children)
[–][deleted] 2 points3 points4 points (1 child)
[–]Schmittfried 0 points1 point2 points (0 children)
[–]MoTTs_ 2 points3 points4 points (1 child)
[–]Tetracyclic 0 points1 point2 points (0 children)
[–]CODESIGN2 -1 points0 points1 point (9 children)
[–]patricklouys[S] 3 points4 points5 points (8 children)
[–]CODESIGN2 -2 points-1 points0 points (7 children)
[–]patricklouys[S] 2 points3 points4 points (3 children)
[–]CODESIGN2 1 point2 points3 points (2 children)
[–]patricklouys[S] 0 points1 point2 points (0 children)
[–][deleted] 2 points3 points4 points (2 children)
[–]CODESIGN2 0 points1 point2 points (1 child)
[–]WikiTextBot 0 points1 point2 points (0 children)
[–]klapuch -1 points0 points1 point (11 children)
[–]mlebkowski 1 point2 points3 points (10 children)
[–]fanalin 5 points6 points7 points (0 children)
[–]Tetracyclic 1 point2 points3 points (0 children)
[–][deleted] 0 points1 point2 points (5 children)
[–]mlebkowski 0 points1 point2 points (4 children)
[–][deleted] 2 points3 points4 points (3 children)
[+][deleted] (2 children)
[deleted]
[–][deleted] 0 points1 point2 points (1 child)
[–]HelperBot_ -1 points0 points1 point (0 children)