Well, that depends.
Primarily on the assumptions you make on the interface you are implementing.
Let me explain:
I am working on a medium scale framework project that, among other things, deals with many different storage modules that implement CRUD like operations.
So consider this type:
interface IDataAccess
{
void Insert(string id, object item);
object Get(string id);
}
A typical implementation could be something like:
class DAL1 : IDataAccess
{
public void Insert(string id, object item)
{
// Insertion logic
}
public object Get(string id)
{
// Retrieval logic
return result;
}
}
So it happens, not all storage types in my system actually support insertion, so I have another implementation like this:
class DAL2 : IDataAccess
{
public void Insert(string id, object item)
{
throw new NotSupportedException(
"This module does not support insertion.");
}
public object Get(string id)
{
// Retrieval logic
return result;
}
}
For the sake of simplicity, we decided not to segregate the Insert and Get methods into different interfaces. As a result, implementers that do not support one of the operations simply throw a very informative and responsible exception.
Prima faci, this is a reasonable design, so what is the problem?
How about a crude violation of the Liskov Substitution Principle?
To state is rather bluntly, the principle says that if type B inherits type A then any place that handles A's will handle B's in the exact same manner.
As an analogy, think of a local coffee-shop that is used to serving coffee to the local gentry. One day, the prime minister enters the shop.
The LSP presents a very strong demand in this situation:
A costumer, folk or gentry, should never expect a business to treat her in a special manner, in accordance to her position in the social hierarchy.
Thus, the prime minister who adheres to the LSP, knows that he is expected to behave like the most common costumer, all other distinguishing features are irrelevant and must not be made visible.
So back to our discussion:
Recall that I am building a framework. This means that I define the primary interfaces, and I also write "Out of the box" constructs that use them. The actual implementation will be determined by my clients (think of the IComparable interface in the .Net framework(.
What happens if my framework has code like this:
void HandleInsertion(IDataAccess a, string id, object item)
{
a.Insert(id, item);
}
Clearly, if called with a concrete instance of DAL1, will work just fine, however if passed an instance of DAL2 suddenly it behaves differently- it throws an exception.
The technical solution to this problem is trivial:
void HandleInsertion(IDataAccess a, string id, object item)
{
try
{
a.Insert(id, item);
}
catch (NotSupportedException ex)
{
// absorb the exception, maybe log a warning
}
}
Well, at this point we should either be Mad or Confused.
Clearly the violator of the LSP is the implementer! I gave her an interface, and here she goes throwing those exceptions! Why should I change my infrastructure code just because she decided that she doesn't feel like implementing one of the methods?!
This argument hides a fundamental fallacy that many developers (including yours truly) often overlook.
When we define an interface, apart from specifying the name of the methods that we wish implementers to have, we must provide guidance for their implementation and usage. What are the expected preconditions of calling a method? What are the expected behaviors of the method upon erroneous situations?
This kind of guidance is a part of the interface as much as any of the interface's properties or methods.
Many of us stop thinking about the interface after we finish typing the last method signature.
The reason we had to add a try-catch block that absorbs the NotSupportedException around the insert method is because there was no specification that said that all members must be implemented. Thus, the violation of the LSP was not the fault of the implementers, but of the architects of the Interface, who failed to describe it completely, thus allowing leakage of implementation details to the code of the framework.
Following the LSP is all about following expectations. If I am deriving a class or an interface, not only must I implement all abstract and interface methods, but also consider and follow all the constraints that appear in the documentation of those methods.
Then, and then only can I be absolutely sure that my derived type can be passed along to code that handles types it derives from, and not break anything.
Conversely, the writer of the interface must provide for proper documentation.
Unfortunately, nowadays it is either impossible or impractical to encode things like pre-and post conditions in method names thus- they must be most accurately specified in the ancestor's message to its children.
A great example that demonstrates this is the documentation of object.Equals: It consists almost entirely of restrictions on how the method may be overridden and thus it describes what the clients may expect.
To summarize:
The Liskov Substitution Principle:
1. Prevents breaking code when derived types are passed to it
2. It thus a good practice
3. Cannot be practiced without careful and precise documentation of object behavior
As a Jungle adventurer, when most of the time you are busy with cutting ropes and vines which one of the following tools (in the absence of a machete, bear with me) would you prefer?
And which interface do you think best suits the task of enumerating a sequence?

I would usually pick candidate #1 in both cases. It is simple, it gets the job done and it does not burden me with unnecessary features.
However, this metaphor does not extend to a couple of subtle and far more important issues.
In this post, I will argue that if requirements permit, it is absolutely essential to prefer handling a sequence of elements through the looking glass of the IEnumerable interface.
First, a quick overview of the essence of each interface:
1. IEnumerable allows you to (1) Give each item special treatment by enumerating the sequence (2) Treat a sequence as an immutable bag of items.
2. ICollection (is IEnumerable) adds the (1) Functionality of adding and removing items and (2) The notion of the sequence being finite.
3. IList (is ICollection) adds the functionality of (1) Accessing and item by its index and (2) Inserting an item at a specific location in the sequence.
Based on the above overview, what information does the following code bear?
interface IFoo { ICollection<int> M(IList<int> list); }
Observation 1: Method M receives an IList. It probably contains code like
‘list[i] =’ or ‘list.RemoveAt(j);’ It has the ability to add or remove items from
the input parameter list.
Observation 2: Method M returns an ICollection. The client can Count the
number of items in the return value, moreover, it probably Adds or Removes
items from the return value.
These observations place a very large burden on the client as well as on the
server (the implementer of IFoo):
- Does the client rely on the structural integrity of list (structural, as opposed to the integrity of the individual items in the collection)? Method M is free to wreck havoc on it’s input. It can remove or add items at will, it can even Clear it altogether. The client of M has to account for these scenarios.
- Same question, but from the server perspective: Does the structure of the return value represent a manifestation of an internal state? and if so, how does the implementer of IFoo should deal with unexpected changes to that state from outside?!
All these are important questions considering the signature of the method and must be accounted for. However, often the reality is much simpler. In fact (mind, this is a gross generalization based on my experience) most of the times both the input and the output will be subject to projection or a some kind of filtering that does not involve structural changes to the sequence itself. For example, replace the name ‘M’ with ‘Filter’ and immediately a Linq ‘Where’ clause pops to mind.
Sure, the birth of a sequence usually involves iterative growth (= ICollection.Add()) of a concrete instance of a List<T>. My point is that (often) later on, there is no growth or reduction.
That means we can and should use the IEnumerable interface to handle sequences when no mutation or indexing semantics are required! It is read-only and hence, immutable. This enables you to :
1. Fulfill the basic requirement of handling a sequence
2. Remove ‘Noise’ from the consumer of the code (you or your client) in
the form of methods that will (or should) never be used on input or
output.
2. Express the intention of the code in the most restrictive way. This
will facilitate Predictable behavior and prevent bugs caused by
misuse.
In my opinion the IEnumerable interface is one of the greatest inventions of C# designers.
As a side note, I believe that the sole reason for the proliferation of List<T> is simply because there are no concrete Enumerable or Collection types. The simplest type one can actually instantiate is a List<T>, So it is convenient to continue referring to it as such. It is easier to write:
var l = new List<int>();
Instead of:
IEnumerable<int> l = new List<int>();
On a later post, I will write about why it is generally a bad idea to pass a list to method.This is it for now, Let me know what you think. Bye!
Once, during a code review session, me and my reviewer encountered a method I wrote that looked something like:
void Foo(int[] i, string s)
{
#region Validate Input
if (i == null)
{
throw new ArgumentNullException("i");
}
if (s == null)
{
throw new ArgumentNullException("s");
}
#endregion
// rest of code..
}"What's up with the region?!" He said. "It's great that you want to hide uninteresting input validation
from the reader, but why don't just put it in a helper method? Regions are primarily used by code
generators and maybe for grouping related functions in a class, not for this..."
Indeed, his claim sounds reasonable. So what is the difference between:
void Foo(int[] i, string s)
{
Validate Input
// rest of code.. }
And:
void Foo(int[] i, string s)
{
// Refactored the region into a method.
ValidateInput(i, s);
// rest of code.. }
Before I go on, mind that the issue here is very subtle, and there is no absolute answer.
Moreover, this is just an example for a more general situation when you want to make
an abstraction out of a peice of code.
Both approaches are good and highly depend on personal style.
That said, there is a good reason to prefer the former upon the latter.
Why do methods exist? Recall your very first lesson of computers (at school? at the university?):
some pieces of code have a similar structure and very only by certain parameters. Introduction
of methods allows you to Reuse the same code in different places, thus preventing code duplication.
But methods have one more very important purpose: they abstract the details of implementation
away from the reader of the code. Thus, by properly naming a method, not only you promote reuse
but you make your code easier to understand!
Hypothetical methods such as GetStudents, PerformLogin, MultiplyVectors, ValidateInput state
very clearly what is going on inside them and what is their designation. They allow you to
concentrate on the essence of your business logic by hiding the myriad details that are related to those actions.
So now we established that methods are used for:
1. Code reuse
2. Hiding implementation details
Let's consider the example above. There is no doubt that the input validation should be hidden.
It is simply more pleasant to look at the code that way. In fact, both region and method accomplish
it perfectly, but if the validation logic is not relevant to any other method in the class, refactoring it
to the ValidateInput method fails to meet the code reuse designation, thus diminishing the
justification for its existence.
What I am saying is, that in your day to day work, consider using regions instead of helper
methods; the latter mostly just clatter your class and the former satisfy the need for hiding
details just fine.
What do you think? What kind of subtle coding dilemmas did you encounter?
Stay tuned for more!
"You can't stay in your corner of the forest, waiting for others to come to you; you have to go to them sometimes."
Winnie the Pooh
So here I am.
My name is Vitaliy Pisarev, I Live in Israel.
I studied my first degree in Communication Systems Engineering, and the best thing that came out of it is that I found out I got a lot more excited by writing a Huffman Encoder/Decoder in Java than by Sniffing the network or exploring sliding window protocols. What can I say- I am in love!
I believe in Software Engineering (What DO I Mean by 'Believe', you wonder..) and I have a strong love for the dirty task of actually writing code. I also believe that nowadays, Coding is the single most unjustly abandoned skill. This is what drove me to start this blog.
Over a few years, You and I drooled over the huge advances in programming languages (C# and friends), dev tools (Visual Studio, Resharper, NDepend), IPC platforms (WCF) etc.
On this stage however, I intend to give a lot of attention to all the little (and not so little) things that got left out, such as correct leveraging of data structures, paradigms of functional programming, clarity and maintainability of code, day-today programming mistakes, human interaction between team members, the importance of great developers, psychological espects of being a developer and many other things that are pushing from inside my head to get out.
At all times, I will be pleased to hear your comments and feedback, after all, I am here to learn new things as much as you are.
Welcome J
p.s
Going to work on prettier theme and bio soon.