4 ms·
I agree with @scarface74 and would go even further in that I would probably create a custom type for List<AccountId> to convey the purpose of what that thing is
by cessor 8y ago
I agree with @scarface74 and would go even further in that I would probably create a custom type for List<AccountId> to convey the purpose of what that thing is now.
And as for the "type shyness":
> Creating a new datatype for something as simple as an int or String defeats that and makes it more cumbersome to work with.
It is never "just an int". Soon you will ask questions about the int, and in a sufficiently large application you will forget the answers to the quesions easily, and scatter the same question (i.e., the same boolean logic) all over the place. Consider an application where you need to filter something by year. A year, you know? As in 1974, 2018, etc. An int is bad, because an int could be -5, which does not make sense. Ok, a uint then? Still bad, because then there is a year 0 and - if your application deals with birthdays of real people, 1800 would be an invalid birthday. The semantics (or pragmatics, linguistically speaking) emerge from how you interpret the integer, and this interpretation can happily live in that one file with that one class that encapsulates "just" that integer.
The AccountId probably shouldn't be < 0, and a specific type could be the one place where you make sure that this is always the case.
What if you start with a 32bit integer and suddenly you realize that your weird Internet-Of-Things-Sensor reading database has grown and the 32bit integer is getting too small? You could just use 64bits. With "just an int", you now get to change every single function that expects an int for the purpose of a SensorReadingId (or an account id or whatever) and change it to size_t, uint, int64 or whatever. OR, you just tell the object that its internal representation uses 64bits now, because the AccountId class is the one single place that deals with account ids. The type provides a consistent interface that allows you to infer the semantics of its use. An int doesn't do that.
This idea predates java by some ~20 years [1]. An int is not an account id. An int is not a year. An email is not a string. The result of working like that is considered a code smell [2].
Still, coming back to the example I made: It was primarily about commenting. I was taught to always comment, and StyleCop enforced comments on each and every field of a class, leading to noisy, superfluous comments.
/// Gets or Sets the Name
string Name { get; set; }
does not add anything.
As for returning an AccountID: I'd like to point out that the Account is a strong and independent object, who can make his own decisions and does not need to return anything. Returning its id like that is actually breaking encapsulation. Still if you do it, it probably shouldn't be an integer.
Why are people scared of creating types and objects?
[1] https://link.springer.com/chapter/10.1007%2F978-1-4612-6315-9_22 https://link.springer.com/chapter/10.1007%2F978-1-4612-6315-...
[2] https://sourcemaking.com/refactoring/smells/primitive-obsession https://sourcemaking.com/refactoring/smells/primitive-obsess...
- jokerx 8y agoI take it you don't write a lot of CRUD apps? You deal with a lot of data that is of only a few simple types, and as I said in my post, interoperability means you can't get too crazy with your class definitions. They need to stay simple or the SYSTEM will become more complicated. As for a variable never staying a simple type, again, see my example in my previous post. A string id is going to stay a string id and its data and behavior is dictated by being an id to remain supersimple. I am not against defining new types; I am against defining a new type for every single variable "just because."
- scarface74 8y agoFor interoperability, you would want to keep the models that are sent out over the wire separate from the models you use in your program. You want the freedom of being able to change your database properties and fields, your domain models which could be some type of crazy aggregation of separate database tables are even information from other sources, without changing the structure that you expose to external clients.
- jokerx 8y agoYour example of needing to define a type because "int" is not good enough is very C/C++ centric. Most languages don't have the plethora of integer types that C has. Java, for example, has just has 2 in general use: int (signed 32 bit) and long (signed 64 bit). (Nobody considers byte a general integer type.) In C/C++, you have to define so many things about the types you use because so much is "implementation dependent." So for C/C++, you may be correct. Most other languages define their types more stringently and include a smaller number of general purpose types.
- scarface74 8y agoC# has nine integral types. https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/integral-types-table https://docs.microsoft.com/en-us/dotnet/csharp/language-refe... But even then, a year is an int, but it would have certain semantics you would want to enforce outside of integers.
- 8y ago