Showing posts with label design. Show all posts
Showing posts with label design. Show all posts

Friday, January 18, 2008

Debug.Fail

Formerly I thought why should we use Debug.Fail and not to use exception throwing? About a year ago I thought out the case where Debug.Fail will be better than exception throwing. But... I didn't write it down so I've forgotten it :(
But now I want to note an another case:
If we use, for example Abstract Factory of Factory Method we could use Debug.Fail.
Consider the code (it's just a sample to demonstrate one practice not all!):



public IReporter GetStrategy(Type entityType)
        {
            if (entityType == typeof (DictionaryEntity))
            {
                return SimpleMenuStrategy();
            }
            else if (entityType == typeof (ProgramEntity))
            {
                return ExtendedMenuStrategy();
            }
            else
            {
                throw new ArgumentException("Unknown type of entity" + entityType, "entityType");
            }
        }

Than you add some others entities, quantity of them grows quickly. One day (usually it happens right before the build :) ) you add one more entity type and forget to define strategy for it. Oh, damn! Exception is generated. Not good solutions, especially if the function was missed by tester and client will see the exception message.
So, let's rewrite the code:



public IReporter GetStrategy(Type entityType)
        {
            if (entityType == typeof (DictionaryEntity))
            {
                return SimpleMenuStrategy();
            }
            else if (entityType == typeof (ProgramEntity))
            {
                return ExtendedMenuStrategy();
            }
            else
            {
                Debug.Fail("Unknown type of entity" + entityType);
                return SimpleMenuStrategy();
            }
        }

Now we get an exception only during Debug time no runtime on the customer's side. We just return a strategy that can perform only the minimum set of functionality. May be it's even will be good enough to customer and won't turn into the fatal error that should be fixed ASAP (e.g. minimal menu will contain "Open" and "Delete" items, but won't contain "Call this person" which absence is not critical for customer for a time).

Yes, it's a fake code and a little far-fetched solution. But it works and I think works better in the second case than in first one. And general rule: call Debug.Fail where the developer's mistake that you should cover with some solution, and throw exception in other cases.

Thursday, January 17, 2008

Exception rehandling

Sometimes problem of exception rehandling is occurred in the application.Consider the following situation:
  • You have a class with two methods: LoadData and GetEntity
  • You have ExceptionHandler class that handles exceptions and manages it in something way.
  • Caller classes could call both LoadData and GetEntity
  • You decided to around LoadData and GetEntity methods' bodies with try-catch and handle exceptions using ExceptionHandler.

All is ok. But imaging you call GetEntity from LoadData method and error is occurred in the GetEntity method (e.g. requested entity was deleted). Exception handler handles the exception, process it (e.g. shows message box "Object was already deleted from the storage") and .. what to do further?

  1. Return null signaling that object was not loaded.
  2. Return fake object that signaled the object was not loaded
  3. Rethrow the exception
  4. Throw another exception

Let's consider pros and contras of every approach:

Return null

Pros:

  • You signal that object is not loaded, so no data will be shown;
  • Caller could check for null and make a decision of what to do;

Contras:

  • Caller should always check null instead it gets NullReferenceException (the one of the worst exception I know);
  • Because null is not an often case unnecessary checks will be performed;
  • All the callers have to know about this peculiarity;
  • We should make check and make a decision again of what to do in every place we return null (in Load method and in its caller).


Return fake object

It means returning something like NullValueObject

Pros:

  • NullReferenceException is avoided;
  • If null check is missing in some place we just bind an empty object;
  • Load method could not take into account return value and transmit responsibility on decision making to the caller transparently;

Contras:

  • If no checks made Bind method (that binds data to the form) could bind empty object and it is good if no exception occurred;
  • We should create NullValueObject for the data for every entity. And if the quantity if entities is big and we couldn't support small count of NullValue entities support and creation of such entities could be very hard;

Rethrow the exception

I think it's a bad method at all - to rethrow an exception. E.g. if we rethrow the exception in GetEntity method, then it will be catched in LoadData method and processed in ExceptionHandler again, and there message will be shown again. I think it will confuse user (seems like, "Hey you, you can't understand it from the first time!").

Throw another exception

Pros:

  • Rethrowing another exception (e.g. ExceptionHandledException) allows us to not handle in in the ExceptionHandler again but up on stack as higher as necessary;
  • It allows us not to process incorrect return values;
  • We definitely won't process empty data;
  • Load method shouldn't take care on the possible double error handling and other staff.

Contras:

  • We should catch ExceptionHandledException on the highest level to not obtain UnhandledException
  • If, e.g. absence of data should be processed normally (or in another way than just catching exception) then we should try-catch all the operations that could throw the exception and process it separately in catch.
  • We should know the internals of ExceptionHandler

There are many any pros and contras in every approach. I listed only general.

So as usual, decision depends on the circumstances but the best approaches are: NullValue and ExceptionHandledException. In any case we should clearly define what is error and define the strategy on the application level.

Wednesday, December 19, 2007

Feature review

All we know about such technic as code review. We do it frequently and become more and more happy from one code review to the next.
But I never met such a technic as "feature review". 
The idea is to ask developers from time to time to tell about the feature he/she implemented. As detail as possible. And check this implementation for architecture and design cleaness.

I'll try it on the nearest project, I hope.  And then report the results.