Question: What are some other strategies on avoiding magic numbers or hard-coded values in your SQL scripts or stored procedures?
Consider a stored
Well to start with, Business Logic should probably be avoided in the storage layer.
As this seems to be unavoidable when using a DB such as Sql Server where a lot of the BL can exists in the DB, I think you might rather revert to using string IDs rather than auto IDs.
This will be a lot more managebale than auto ids, and can be handled in better ways, even when using the actual application layer.
For instance using a .Net approach, a lot of the the unique string IDs can be store anywhere from the config files, to additional lookups using the selected db, XML files.
At some level, there's going to be some "hard coding" of values. The idea of eliminating them comes from two sides:
'Acknowledged'
rather than 3
is probably going to make your intentions more obvious to the reader.Making bit
columns for various states can be a good or bad idea; it really just depends on the data. If the data goes through various "stages" (Received, Acknowledged, Under Review, Rejected, Accepted, Responded, etc.) then that approach quickly scales itself out of viability (not to mention the irritating process of having to ensure that only one of the columns is set to 1 at any given time). If, on the other hand, the state is really as simple as you describe, then doing that can make the code more readable and indexes perform better.
The biggest no-no in hard coding values is hard coding values that reference other entities (in other words, hard coding the primary key for a corresponding object). The string 'Acknowledged
' is still a hard-coded value, it's just more transparent in its meaning and it isn't a reference to something else. For me, it boils down to this: if you can (reasonably) look it up, do it. If you can't (or if something makes it an unreasonable task either from a performance or maintainability perspective), hard code it. Using this, you can look up the value of 3 by using Acknowledged
; you can't look up Acknowledged
from anything else.
We've taken a simple approach: Add a column named 'code' that contains a string that, once a record is created, is never changed.
If you hard-code the ID value you have problems - what if you deploy some functionality (such as stored procedures that hard-code an ID and assume you'll create the corresponding record with that ID value) to another database instance that already has that ID value used by another record? Or your code is deployed as SQL scripts that create the tables and data - and you cannot guarantee each deployment will generate ID values in the same way.
If you hard-code a field like 'Name' - there is a good chance 'Name' is displayed somewhere. What happens if the field is user-maintainable? If someone decides to change a Name value they break your procedures and functions. Even if it is not user-maintainable, some change in future will say 'We have to change the Name' and that will get done by SQL, breaking your dependent code and requiring a search for all dependencies, fixing same and testing all over again.
But if you create a 'Code' column that never changes, who cares if the Name value changes? Name is shown to the users - they can see what they want. Code is visible only to developers, and if absolutely necessary they can later comment the code to say 'Code value X refers to Y - the name changed as part of request number Z'.
Very simple approach.
If the 'Status' entity, which forms part of your domain model, has predefined values, some of which need to be handled in a specific manner by stored procedures, then it is perfectly OK to hardcode references to those specific values in your code. The problem here is that you are confusing what is potentially an abstract key (ID identity column) for a value that has a meaning in your domain model. Whilst it is OK to keep your ID identity column, you should use a meaningful attribute of your domain entity when referring to it in code, this can be the name, or it can be a numeric alias. But this numeric alias should be defined in your domain model, e.g. 3 means 'Acknowledged', and it should not be confused with the abstract ID field which, as you say, may be an identity column in some of your database instances.
I recently figured out that magic numbers can be implemented by views:
CREATE VIEW V_Execution_State AS
SELECT 10 AS Pending, 20 AS Running, 30 AS Done
DECLARE @state INT
SELECT @state = Pending FROM V_Execution_State