Avoiding Hard Coding and Magic Strings in code and databases
Tags: dotnet, sql, codequality, startup
Published: 2020-01-18 12:37:26

# Hard Coding and Magic Strings
Hi, a fairly small article. Am just putting this here to instil some good practice in developers. I won't detail full code alternatives to doing this, so forgive the article for not being complete.

**About me**
I am currently working on a property platform startup (findigl) and building associated products for my Limited Company. This means I am not working, but starting to look for contracts and client work.

[Info Rhino Limited](http://www.inforhino.co.uk)
[My Blog](http://www.zakwillis.com)
[Property Platform - WIP](http://www.findigl.com)
# Hard Coding and Magic Strings
## Magic strings in code
We see it all the time. 
```csharp 
var customerName = "Fred Smith";
```
It should be easy to understand why the above is bad. If Fred Smith changes to Freda Smith, we have to recompile the application. We know it could be dangerous to do a global find and replace.

## Magic strings in SQL
We see the same thing in SQL. I can't mention the client, but I joined a project very late on and did an export of the codebase, and ran the following regular regex search.
```
(?is-mnx:('([a-z0-9\s]+)'))
```
This finds most instances of hard coded strings. Take it a little further, and...
```
(?is-mnx:(\=((\s|\t|\n)?)'([a-z0-9\s]+)'))
```
Now we can find most where clauses. On this particular project. I found 8000 hard coded strings, and 600 instances of 'USD'.

What really upset me, was that 'USD' can have different contexts attached to it. For example; 
- Settlement Currency.
- Domicile Currency.
- Reporting Currency.
- Leg 1 Curency.
- Leg 2 Currency.

And so on... The code base was awful. No thought process, just developers working in isolation.

### What the team thought when I presented my findings
They were mystified as to why this was a problem. I am shaking my head as I read it. They hated me for a good while. Finally they came around.

To get around this, it is better to have a table configured with these kinds of settings and to pass in the name of the set as a parameter.
```sql 
create table conf.ReportSetting
(
SettingKey nvarchar(100) 
,Setting nvarchar(100)
);
```
In a function or SPROC
```sql 
create procedure rpt.GetCurrencyValues
@ReportingCurrencyKey nvarchar(100) = 'ReportingCurrency'
AS
SELECT
etc...
FROM 
rpt.profits prft
CROSS APPLY conf.GetReportSetting(@ReportingCurrencyKey , prft.Currency)
rptCcyFilter
```
People may say, what about row locking etc. Well there are ways to get around this.

We can create a table variable of the conf.ReportSetting table and pass that into the sproc. You don't get row locking on table variables.
The SPROC becomes 
```sql 
create procedure rpt.GetCurrencyValues
@ReportingCurrencyKey nvarchar(100) = 'ReportingCurrency'
,@settings conf.typSettings
AS
SELECT
etc...
FROM 
rpt.profits prft
inner join 
@settings stng
ON 
stng.Setting =  prft.Currency 
WHERE 
stng.SettingKey = @ReportingCurrencyKey 
```
See how we have suddenly made the intention of the SQL code far clearer? Well, it is the same in C#

## Avoiding hard coding and magic strings in .Net
A Magic String is where some component expects a key or property name to get passed in. The best example is this...
```csharp
ConfigurationManager.ConnectionStrings["ExecutorDB"].ConnectionString
```
Well, this can be solved with the relatively new and amazing nameof operator.
```csharp
ConfigurationManager.ConnectionStrings[nameof(ExecutorDB)].ConnectionString
```
This avoids using Reflection or more complicated approaches to get property names.
### A useful way to take advantage of nameof and string interpolation for strongly typed formatting in C#
What you quickly start to find is, variable names get used in combination with nameof all the time. I guess we could write an extension method or expression function to really  make the code neater.

So whilst this may seem heavy/boiler platey, it means our configuration is all strongly typed.
```csharp
        public void Create(string FolderPath)
        {
            if (checkFolder.ConfirmFolderExists(FolderPath))
            {
                logger.Info($"{nameof(CreateFolderIfNotExisting)} {FolderPath} already exists - not creating it");
                return;
            }

            logger.Info($"{nameof(CreateFolderIfNotExisting)} {FolderPath} about to create it.");
            this.createFolder.Create(FolderPath);
            logger.Info($"{nameof(CreateFolderIfNotExisting)} {FolderPath} should have created it.");
        }
```
If we change any parameter names, we will get build/compile errors on strings.
## Conclusion on avoiding magic strings
I am on the downhill phase of my year long project now. There are several things a lone developer should not do when working on a startup;

1. Spend another 6 months putting in loads of unit tests. 
2. Creating perfect code won't cut it either. 
3. Always follow the Single Responsibility Principle, although we can make objects as small as possible.

What we can do is;
- Avoid hard coding.
- Make applications small in scope, so they are replaceable with other applications if required in the future.
- Avoid Magic Strings.
- Use Interfaces as much as possible.
- Move transitive dependencies to separate classes.

Hopefully, you got some use from this article.
> Written with [StackEdit](https://stackedit.io/).