Does Single Responsibility Principle Apply to an Variable?

I ponder upon a pile of codes, and wondered what was going on. Why were so many smart decision makers in the lower-level business objects, and why they were making decisions or reversing decisions just made in higher-level layer?

Ok, they were making the decisions based on a parameter passed from higher-level business layer. This parameter was in such higher-level business layer that it had a huge influence on many lower-level business objects.

It dawned on me that this violated the Single Responsibility Principle (SRP), and overloaded one variable with two or more meanings. It, therefore, forced lower-level business objects to figure out the actual meaning in that particular context using adjustments of all kinds of assumptions and guessing.

I usually think about SRP in the context of classes (or objects), and don’t realized it applies to anywhere in our implementation even to a single variable. So we can use SRP to solve the problem here.

For reference to SRP, as quoted “The single responsibility principle is a computer programming principle that states that every module or class should have responsibility over a single part of the functionality provided by the software, and that responsibility should be entirely encapsulated by the class. All its services should be narrowly aligned with that responsibility. Robert C. Martin expresses the principle as, “A class should have only one reason to change.”

References:

  1. Single Responsibility Principle

 

 

Advertisements

SQL Insertion of Thousands Records Too Slow?

Worked on improving another performance issue. This time I found that there were too many SqlCommand.ExecuteScalar() methods, and some of the return values were never used.

So let’s do some math. If we have 1000 records to be inserted, let’s assume that each insert takes 10ms to finish the round trip from business layer down to database and back.  10ms * 1000 = 10,000ms = 166 seconds = 2 minutes 46 seconds. What if we have 2000, 3000, 5000 records or more? Feel the pressure now?

In this case, the refactoring is to concatenate all the sql statements of those SqlCommand.ExecuteScalar() that return values are not used downstream into one big CommandText, delimited by ‘ ; ‘, and insert together using SqlCommand.ExecuteNonQuery(). I guarantee you the result will be impressive.

You might ask what if the string is too long, will it be truncated?

Answer: No. The CommandText can take a batch size of 64K x 4k = 256M [1].  By the way,  the max length of C# string type is 2,147,483,647 [5]. So you don’t worry about that either.

 

References:

  1. https://stackoverflow.com/questions/21390537/sqlcommand-executenonquery-maximum-commandtext-length
  2. https://docs.microsoft.com/en-us/sql/sql-server/maximum-capacity-specifications-for-sql-server?view=sql-server-2017
  3. SqlCommand.ExecuteScalar()
  4. SqlCommand.ExecuteNonQuery()
  5. https://stackoverflow.com/questions/140468/what-is-the-maximum-possible-length-of-a-net-string

SQL Profiler Trace File Truncated?

Worked with a colleague to trace a performance issue using SQL profiler. The trace lasted a few minutes. However, the trace file was quite large. I began to browse through the records, and found out there were no records after a certain point in time. Apparently, the end of trace file was truncated.

Researched and found out the file was not truncated, and it just stopped recording. So if you expect larger size of trace files, please set up the proper parameters.

References:

  1. Set a Maximum File Size for a Trace File (SQL Server Profiler)
  2. Limit Trace File and Table Sizes

Performance Tuning on C# LINQ

There was a performance issue in some large transactions. I investigated this issue. After spent a couple of hours on setting up tests and metrics, I began to time the performance of each component.

It turned out one component was the trouble maker. There were some queries with LINQ deferred operators used in this component, and there were time-consuming processing logics in these deferred operators. These queries were called again and again under the assumption that the result sets were materialized already. Therefore, these repetitive callings of these queries with deferred operators caused the performance issue.

Here is the link to Query Execution. It explains immediate and deferred operations, and when and how to use them.

References:

  1. Query Execution

 

 

Error CS0012, The type ‘XYZ’ is defined in an assembly that is not referenced

Helped to fix this compile error a couple weeks ago, Error CS0012 “The type ‘ABC’ is defined in an assembly that is not referenced. You must add a reference to assembly ‘AssemblyX'”.

We confirmed the type ‘ABC’ was clearly defined in assembly ‘AssemblyX’. We then removed and added ‘AssemblyX’ back a few times. The compile error was still there no matter how we tried. [1, 2, 3]

Finally, we had to edit this project .csproj file directly using notepad and removed the reference. Then compiled to get the compilation error, and added the reference back in. This solved our not reference issue.

References:

https://stackoverflow.com/questions/3431857/c-sharp-type-defined-in-an-assembly-that-is-not-referenced

https://stackoverflow.com/questions/20660999/the-type-is-defined-in-an-assembly-that-is-not-referenced-how-to-find-the-cause

https://stackoverflow.com/questions/17246899/the-type-xxx-is-defined-in-an-assembly-that-is-not-referenced

C# LINQ Distinct

Tags

Debugged through a legacy C# LINQ query, and this query contained a Distinct operator. The query exhibited strange behaviors. It took me a few minutes to realize that Distinct was one of the deferred operations. [1]

Another much more interesting and important topic is that what happens when we use Distinct without supplying an IEqualityComparer comparer [1]. Let’s use an example to illustrate.

public static IEnumerable Distinct(
    this IEnumerable source
)
void Main()
{
   Product[] products = {            
           new Product { Name = "apple", Code = 9 }, 
           new Product { Name = "orange", Code = 4 }, 
           new Product { Name = "apple", Code = 9 }, 
           new Product { Name = "lemon", Code = 12 } };

   IEnumberable noduplicates = products.Distinct();
   
   foreach (var product in noduplicates)
      Console.WriteLine(product.Name + " " + product.Code 
         + ", hash code: " + product.GetHashCode());
}
public class Product 
{
   public string Name { get; set; }
   public int Code { get; set; }
}

The code produces the following output:

apple 9, hash code: 4143056
orange 4, hash code: 52219803
apple 9, hash code: 1080906
lemon 12, hash code: 48640813

Why does “apple 9” appear twice? Why are the hash codes for “apple 9” different?

The system returns a default equality comparer [3]. Without any special equality comparer method implemented on our class Product, the system basically depends first on Object.GetHashCode, and then on Object.Equals to find out whether two objects are equal or not.

For reference  types, if GetHashCode is not overridden, hash codes are computed by calling the Object.GetHashCode method of the base class, which computes a hash code based on an object’s reference. In our case, two product instances of “apple 9” have different object references, therefore, different hash codes, and “apple 9” appear twice.

If value types do not override GetHashCode, the ValueType.GetHashCode method of the base class uses reflection to compute the hash code based on the values of the type’s fields. In other words, value types whose fields have equal values have equal hash codes.

References:

  1. Enumerable.Distinct
  2. Object.GetHashCode
  3. EqualityComparer.Default Property
  4. Object.Equals
  5. GetHashCode and LINQ

LocalService vs NetworkService vs LocalSystem

Wrote down the notes after solved an access issue [1, 2, ,3, 4].

LocalService NetworkService LocalSystem
Predefinied local account Yes, local authenticated users Yes, local authenticated users Yes
Privileges in local computer minimal, run standard least-privileged services minimal, run standard privileged services Extensive, have access to most system objects. Most services do not need such a high privilege level. If your service does not need these privileges, and it is not an interactive service, consider using the LocalService account or the NetworkService account.
Password No No No
Token NT Authority\System, Builtin\Administrators
Network identity Anonymous user* Act as the computer on the networks, computer’s credentials (computer$). By default, the remote token contains SIDs for the Everyone and Authenticated Users groups. Act as the computer on the networks, computer’s credentials (computer$)
Note By default, the Local System Account is a member of the local Administrators group and is therefore a member of the sysadmin group in SQL Server.

ATTN: * – Anonymous user is not equivalent to everyone. Everyone means a group of all authenticated users.

 

References:

  1. https://msdn.microsoft.com/en-us/library/windows/desktop/ms684188(v=vs.85).aspx
  2. https://msdn.microsoft.com/en-us/library/windows/desktop/ms684272(v=vs.85).aspx
  3. https://msdn.microsoft.com/en-us/library/windows/desktop/ms684188(v=vs.85).aspx
  4. https://stackoverflow.com/questions/510170/the-difference-between-the-local-system-account-and-the-network-service-acco

Error CS0006 – Metadata file XYZ.dll Not Found

Met this metadata file XYZ.dll not found error a few weeks ago, and spent quite some on figuring out what was going on. Followed the thread [1, 2], tried most popular approaches, and still cannot fix it.

In the end, I began to try cold leads. Some users mentioned to check the output window [1, 2], as quoted

for any reason, did not show up in the error window. Because of that, the VS build system seemed to miss the error and tried to build depending projects, which in turn failed with the annoying metadata message … First look at your Output Window! …

I looked at the output window before, and didn’t find anything special. Anyway, it wouldn’t hurt to try again. With special attention to output window, I was surprised to find there was really an error message hidden among other regular messages in output window, followed this lead, and fixed the metadata file not found error.

References:

  1. https://stackoverflow.com/questions/1421862/metadata-file-dll-could-not-be-found
  2. https://stackoverflow.com/questions/44251030/vs-2017-metadata-file-dll-could-not-be-found/44258162

Testing Delay Signed Assemblies

When testing delay signed assemblies using VS test projects, we sometimes got security strong name validation errors. Why? According to [2], this should not happen, as quoted:

“So to give the developer a fighting chance to debug and test his code, he needs a way to make it look like the assembly has a strong name. Delay signing uses a temporary private key and puts data in his registry that records that this temporary key is a substitute for the real one. The CLR looks for this registry key when it checks the strong name, giving the okay when it finds it.

So everything works like it normally does. As long as it is done on the specific machine that delay-signed the assembly”

We can fix this problem [3] by x32 or x64 version of sn using the following line.

sn.exe -Vr *,PUBLIC_KEY_TOKEN_HERE

We can verify the entry in the registry at

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\StrongName\Verification

If above method also fails, we might have to use a technique called conditional configuration [1]

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
   <SignAssembly>true</SignAssembly>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
   <AssemblyOriginatorKeyFile>Xyz.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
   <DelaySign>true</DelaySign>
</PropertyGroup>

 

References:

1. https://blogs.msdn.microsoft.com/mcsuksoldev/2013/05/23/unit-testing-delay-signed-assemblies-on-the-hosted-tfs-build-service/

2. https://stackoverflow.com/questions/21902883/my-delay-signed-assembly-is-debugging-why-is-it-like-this

3. https://stackoverflow.com/questions/5784910/how-to-unit-testing-delay-sign-assemblies-using-nunit

4. https://bartwullems.blogspot.com/2016/08/

5. https://windows-hexerror.linestarve.com/0x8013141A

Think Beyond Visitor Pattern

According to GOF [1], Visitor pattern is:

“Represent an operation to be performed on elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.”

If we spend some time on Visitor pattern, we sooner or later will realize that the real purpose behind Visitor pattern is to separate operations from objects. If we don’t just satisfy with our current understanding and look further to the horizon for a deeper understanding, what do we find?

Here is my 2c.

What if we apply this Visitor pattern to database, let database tables to be the “objects”, we then can write queries and commands as the “operations” against the “objects”. Is this a wilder application of Visitor pattern?

Can you find an even wilder application of Visitor pattern? Let me know ….

References:

  1. Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides (1994). Design Patterns: Elements of Reusable Object-Oriented Software. Addison Wesley.  ISBN  0-201-63361-2
  2. https://en.wikipedia.org/wiki/Visitor_pattern
  3. https://sourcemaking.com/design_patterns/visitor
  4. http://www.oodesign.com/visitor-pattern.html
  5. http://www.dofactory.com/net/visitor-design-pattern