As many of you might already know, properties are a neat way to define getters and setters. Many languages, such as C#, Delphi, Javascript or PHP support them and they are first-class citizens in the .NET ecosystem. Although properties are a handy resource, some property implementations can turn out to be evil. Very evil. Let’s dive into them.
Side-effects in property code
Causing side-effects is the worst practice when using properties, and it’s more spread than it seems at first. What can we consider side-effects? Modifying a nested object state, making a database query that modifies database state or change values in other fields that have nothing to do with the actual Property are side-effects examples. Properties are an abstraction to fields, so noone will expect that when I get a value in a property, other values change. This principle is also applicable to getters and setters in languages where properties are not available.
Slow properties
Properties are an abstraction to fields and fields are expected to be as fast as reading/writing a memory address. If you are reviewing why your code is slow, you are not going to expect a property is the responsible at first. Use methods instead of properties for slow methods, even better if you can make these methods async if I/O is involved.
Properties as method arguments
Some APIs, use properties as method arguments. Imagine a ZIP compressor that works like this.
InputFiles and OutputFile are not natural ZipCompressor properties, they look more like Compress method arguments. Wouldn’t it be cleaner if instead of properties, regular method arguments were used?
This code smell can be found with methods that would need several arguments because of high configuration. In these cases it’s better to define a value object that would have the default arguments already set. We could simply instantiate it and set the properties we need to customize the configuration to our needs.
This way code is far cleaner. Code is not going to mislead the reader to think that the code is mutating the ZIPCompressor object and the API user would not have to remember to reset all these properties in future calls to the Compress method.
When to use properties then?
Rule of thumb, use them as getters and setters. Just that. Some other legitimate cases would be caching values or making helper methods to object attributes. For example, calculate the Age from the BirthDate. The best advice is to keep always in mind that properties are an abstraction to fields. Keep that in mind when writing your properties and WTFs will decrease in your codebase.