How to work with the SVN diff even if the file has suffered a CTRL-K-D

by andrei 20. November 2008 06:50

This option will ignore the effects of CTRL-K-D (auto-format in Visual Studio), and show you the real changes in that file:

image

You can configure the setting by doing any diff, and choosing View -> Settings -> Ignore all whitespaces.

 

 

Enjoy programming!

 

Doing selects over database tables even when they are in a transaction

by andrei 20. November 2008 06:36

Did this ever happen to you?

 

You are debugging, and you are in a transaction, and you want to check something in one of the tables. You try a select:

select * from Something

but it does not work: it will freeze because it's waiting for the transaction to end.

 

Here is the solution:

select * from Something with(nolock)

 

This will tell SQL Server that you are not interested in participating in the locking contest, and it will give you the information even if the transaction has a lock over that table.

 

 

Enjoy programming!

 

Be aware of how much you can handle at any given moment, and don't go over that

by andrei 15. November 2008 23:58

This is a more recent lesson, it took me a long time to understand it and even more time to accept it: a team can handle a certain quantity of work, anything above that quantity decreases the quality considerably. In the long run, the only thing that matters is quality.

 

After I started Akcedo, I began to take all kinds of projects in order to create relationships which would guarantee the cash flow of the company. To tell the truth, I was afraid and I panicked, but this is a story for another post.

What followed was a period of long work days, with a few noticeable situations of 20 hours of work per day. That's something to avoid. If you find yourself working 15-20 hours per day, stop and make a radical change. You will as amazed as I was to find out that you will lose nothing.

Even after I stopped working so much, I continued with a long period in which I didn't say no to any projects that were coming to us. I was so innocent, that I was even proud about it. Again, the truth is that I was afraid of what would happen if I said no. Accepting all projects sometimes created spikes, but initially it was ok. In time the quantity of work grew, and accepting all projects became harder and harder.

 

At one point circumstances made it so we couldn't continue like this. It was incredibly hard to change my inflexible way of thinking, but I had no choice. So I decided which clients / projects are most important to us, and how much work we can handle considering our priorities. After that, I started saying no to lower priorities.

In case you don't know about the Pareto principle, this is the time to find out. What happened is exactly what the principle states: we eliminated the factors which were not producing relevant results, and kept only the top producers. After this step we had considerably less problems to think about, and our results improved because we were able to focus on the things that mattered most.

For me, the only problem in applying it in the first place was the fear of uncertainty. This fear stopped me from doing many things for a long time, but now the more I experiment with overcoming it the more I realize that uncertainty is not something to be afraid of at all.

 

So, know how much you want of something (especially if it's about your job, your time or your life), and don't be afraid to say no in order to keep it the way you want it. In these situations your mind can't help you with logical solutions so it will keep you paralyzed, but you should trust your instinct.

 

If you liked this post, I encourage you to read "The 4-hour workweek".

 

 

Enjoy programming!

 

Appreciate and enjoy what you do

by andrei 15. November 2008 22:06

My father is a programmer. When I was only a little boy, he showed me what programming is: I remember learning a few things about algorithms, going to a small competition and winning (there was only one more participant at my age range, so I've just been lucky), going to a software camp, and so on. I enjoyed these things, so I guess at that point programming found a place inside my heart.

 

After a while I started doing other things, and I forgot that I like programming so much.

When I was still a student, I started learning about computer networks. Next step, I took a job as a technician for IT equipments (I was not an engineer yet). I was spending all day driving from client to client, installing and configuring networks, unsuccessfully trying to solve the problems that our low quality equipments had. It was not fun at all, and I was using my hands more than I was using my mind. I felt I was wasting my time, that I was limiting myself.

Of course, working in networking can be a wonderful experience. For me, it just wasn't the right place (company) and the right time.

 

I decided to make a change. I was thirsty to use my mind and creativity, and to stop experiencing limitations.

From the list of options, programming was the only one I knew something about. Unfortunately, because of the long break, I didn't have any of the necessary skills and I didn't know any of the emerging programming languages.

I decided to give it a try, anyway. I quit my job, and came back home for the summer vacation to learn a programming language. I chose C#.

2 months later I was ready to head back to Bucharest and start a new career. I didn't finish everything I wanted to learn, but the vacation was over and I had to get going.

Soon after arriving back in Bucharest, my luck showed again: after 1 or 2 interviews, I found a job as a junior C# developer. From that point on, I started programming for a living and never looked back.

 

Looking at it now, my first job had a very important role: I had to go through something limiting and unfulfilling, in order to learn to appreciate life and the opportunities it can offer. A few years passed since then, but almost each day I realize that I love what I do and I feel grateful.

Being able to enjoy and appreciate what you do is very important, but it's not easy because we always tend to want what we don't have. For me, the memory of my first job is a tool which helps me appreciate software development. I don't know what I would have done without it. In the past, problems were making me question a path and look for something else. Now I know that they are here only to help us learn and grow.

 

If you liked this post, I encourage you to read "The 4-hour workweek".

 

 

Enjoy programming!

 

Using Lucene .Net to index and search website content

by andrei 15. November 2008 03:49

Lucene is an elegant solution for adding content indexing and search in a .Net application.

 

After doing a few Google searches and also studying this excellent basic sample, I wrote a simple implementation which automatically indexes entities implementing ISearchable when they are saved, and offers a simple way to search the website content.

 

Here it is:

  • in the application infrastructure:
    • an interface and a general class implementing the interface:
public interface ISearchable
{
  string Identifier { get; }
  string Name { get; }
  string Details { get; }
  IEnumerable<ISearchable> GetSearchableList();
  string SearchType { get; }
}

class SearchableItem : ISearchable
{
  public string Identifier { get; set; }
  public string Name { get; set; }
  public string Details { get; set; }
  public string SearchType { get; set; }

  public IEnumerable<ISearchable> GetSearchableList()
  {
    yield return this;
  }
}
    • a few helper classes
public class ApplicationSetting
{
  public static string SearchIndexingDirectory
  {
    get
    {
      return ConfigurationManager.AppSettings["SearchIndexingDirectory"];
    }
  }
}
public class Constants
{
  public class Search
  {
    public const string SearchFieldDetailsDelimiter = " | ";
    public const string TagSearchIdentifier = "T";
  }

  public class Domain
  {
    public const int InvalidId = -1;
  }
}

SearchIndexingDirectory uses an application setting from web.config, but you can replace it with a variable or anything representing the path where you want Lucene to generate its index.

 

    • a search service:
public class SearchService
{
  private static bool _indexDirectoryExists;
  
  private void EnsureIndexExists ( string indexDirectory )
  {
    if (_indexDirectoryExists)
      return;

    if (!IndexReader.IndexExists ( indexDirectory ))
    {
      IndexWriter writer = new IndexWriter ( indexDirectory,
          new StandardAnalyzer ( ), true );
      writer.Close ( );

      _indexDirectoryExists = true;
    }
  }

  public void IndexData ( IEnumerable<ISearchable> listToIndex )
  {
    string indexDirectory = ApplicationSetting.SearchIndexingDirectory;
    EnsureIndexExists ( indexDirectory );

    IList<ISearchable> listWithoutDuplicates = new List<ISearchable>();
    foreach (ISearchable item in listToIndex)
    {
      if (listWithoutDuplicates.FirstOrDefault(p => p.Identifier == item.Identifier) == null)
        listWithoutDuplicates.Add(item);
    }

    IndexModifier modifier = new IndexModifier(indexDirectory, new StandardAnalyzer(), false);
    foreach(ISearchable item in listWithoutDuplicates)
    {
      Term term = new Term ( "id", item.Identifier );
      modifier.DeleteDocuments( term );
      InsertDoc ( modifier, item );
    }
    modifier.Optimize ( );
    modifier.Close ( );
  }

  private void InsertDoc ( IndexModifier modifier, ISearchable dataToIndex )
  {
    Document doc = new Document ( );

    doc.Add ( new Field ( "id", dataToIndex.Identifier, Field.Store.YES, Field.Index.UN_TOKENIZED ) );
    doc.Add ( new Field ( "name", dataToIndex.Name, Field.Store.YES, Field.Index.TOKENIZED ) );
    doc.Add ( new Field ( "details", dataToIndex.Details, Field.Store.YES, Field.Index.TOKENIZED ) );
    doc.Add ( new Field ( "type", dataToIndex.SearchType, Field.Store.YES, Field.Index.UN_TOKENIZED ) );

    modifier.AddDocument ( doc );
  }

  public static string PrepareSearchDetailsFieldFor ( params string[] values )
  {
    string ret = String.Empty;

    foreach(string str in values)
      ret += str + Constants.Search.SearchFieldDetailsDelimiter;

    return ret;
  }

  public IList<ISearchable> Search ( string searchString )
  {
    IList<ISearchable> ret = new List<ISearchable>();

    IndexSearcher searcher = new IndexSearcher(ApplicationSetting.SearchIndexingDirectory);

    QueryParser parser = new QueryParser("name", new StandardAnalyzer());

    string searchQuery = "(" + searchString + " OR (details: " + searchString + "))";

    Hits hitColl = searcher.Search(parser.Parse(searchQuery));
    for (int i = 0; i < hitColl.Length ( ); i++)
    {
      Document doc = hitColl.Doc(i);
      ret.Add ( new SearchableItem { Details = doc.Get ( "details" ), Identifier = doc.Get ( "id" ), Name = doc.Get ( "name" ), SearchType = doc.Get ( "type" ) } );
    }

    searcher.Close();

    return ret;
  }

  public static string[] SeparateDetailsFrom(string details)
  {
    return details.Split(new[] {Constants.Search.SearchFieldDetailsDelimiter},
                         StringSplitOptions.RemoveEmptyEntries);
  }

  public static int RetrieveIdFromIdentifier(string input, string searchTypeIdentifier)
  {
    int ret;
    if (Int32.TryParse ( input.Replace( searchTypeIdentifier, "" ), out ret ))
      return ret;

    return Constants.Domain.InvalidId;
  }
}

 

    • a search type visitor, which will be used to select results of a certain type from a list of search results (this can be easily replaced with simple Linq selects):
internal class SearchTypeVisitor : IValueReturningVisitor<IList<ISearchable>,ISearchable>
{
  private readonly string _searchType;
  private readonly IList<ISearchable> _results = new List<ISearchable>();

  public SearchTypeVisitor(string searchType)
  {
    _searchType = searchType;
  }

  public void Visit(ISearchable item)
  {
    if (item.SearchType == _searchType)
      _results.Add(item);
  }

  public IList<ISearchable> GetResult()
  {
    return _results;
  }
}
  • in the Domain:
    • in the repository, when we save an entity we are also indexing the information:
public void Save ( EntityType entity )
{
  SessionHolder.Current.SaveOrUpdate(entity);

  ISearchable searchable = entity as ISearchable;
  if (searchable != null)
    _searchService.IndexData(searchable.GetSearchableList());
}

If you are using a BaseRepository or a generic repository, you will only need to write this once.

 

    • in the entities which should be searchable, we implement ISearchable:
public class Tag: ISearchable
{
  public virtual string Identifier
  {
    get { return Constants.Search.TagSearchIdentifier + Id; }
  }

  public virtual string Name
  {
    get { return TagName; }
  }

  public virtual string Details
  {
    get
    {
      return SearchService.PrepareSearchDetailsFieldFor(
        TagCount.ToString(),
        ((int) TagType).ToString()
        );
    }
  }

  public virtual IEnumerable<ISearchable> GetSearchableList ( )
  {
    yield return this;
  }

  public virtual string SearchType
  {
    get { return Constants.Search.TagSearchIdentifier; }
  }
}

 

If the entity is an aggregate containing subentities which should be indexed, we can also add those in GetSearchableList:

public virtual IEnumerable<ISearchable> GetSearchableList ( )
{
  yield return this;
  foreach (Subentity s in Subentities)
    yield return s;
}
    • we can also implement mappers, if we want to generate entities from the search results:
internal class TagFromSearchableMapper : IMapper<ISearchable, Tag>
{
  public Tag MapFrom ( ISearchable input )
  {
    string[] details = SearchService.SeparateDetailsFrom ( input.Details );

    int tagCount;
    Int32.TryParse ( details[0], out tagCount );

    return new Tag ( input.Name, (enumTagType)Enum.Parse ( typeof(enumTagType), details[1] ) )
             {
               TagCount = tagCount,
               Id =
                 SearchService.RetrieveIdFromIdentifier ( input.Identifier, Constants.Search.TagSearchIdentifier )
             };
  }
}

Otherwise, we will display the information directly from the list of search results.

 

  • in the application layer, a SearchTask which can return the result (a search data transfer object) when the user runs a search:
public class SearchTask
{
  readonly SearchService _searchService = new SearchService ( );

  public SearchDTO Search ( string text )
  {
    IList<ISearchable> searchResults = _searchService.Search(text);

    IEnumerable<Tag> tags =
      searchResults.GetResultOfVisitingAllItemsWith(new SearchTypeVisitor(Constants.Search.TagSearchIdentifier)).
        MapAllUsing(new TagFromSearchableMapper());

    return new SearchDTO
             {
               Tags = tags.ToList()
             };
  }
}
public class SearchDTO
{
  public IList<Tag> Tags { get; set; }
}

 

This class uses the SearchTypeVisitor to filter the tags, and maps the list of ISearchable instances into an IEnumerable<Tag> with the help of the TagFromSearchableMapper class.

GetResultOfVisitingAllItemsWith and MapAllUsing are extensions which help in applying a visitor or mapper to an entire list of items. To obtain the same result, just go over the list manually and apply the desired action on each of the items.

The SearchTask and the SearchDTO from this example are very simple, but they can contain more logic or information depending on the case.

 

  • in the UI, calls to the SearchTask will bring the desired information:
readonly SearchTask _searchTask = new SearchTask();
SearchDTO dto = _searchTask.Search(searchText);

 

 

This solution is only a starting point, and it can surely be improved.

One of the things which should change is the fact that the domain contains information about the search infrastructure, which is not a very good thing. A better place for this information are DTO classes in the application layer.

Maybe I will talk more about this in a future post.

 

 

Enjoy programming!

 

Base fluent repository

by andrei 15. November 2008 01:39

In some previous posts (here and here) I was describing some ideas related to fluent repositories.

 

Here is an idea to bring some of that functionality into a base repository, and obtain less repetitive code:

public class BaseRepository<EntityType, PKType, RepositoryType> where RepositoryType : class
{
  protected ICriteria _criteria;

  protected ISession Session
  {
    get
    {
      return SessionHolder.Current;
    }
  }

  public RepositoryType InitialiseCriteriaFor ( PKType id )
  {
    InitialiseCriteria();
    _criteria.Add(Restrictions.Eq("Id", id));

    return this as RepositoryType;
  }

  public RepositoryType InitialiseCriteria ( )
  {
    return InitialiseCriteria("");
  }

  public virtual RepositoryType InitialiseCriteria ( string alias )
  {
    if (IEnumerableExtensions.IsEmpty(alias))
      _criteria = Session.CreateCriteria(typeof(EntityType));
    else
    {
      _criteria = Session.CreateCriteria(typeof(EntityType), alias);
    }
    return this as RepositoryType;
  }

  private BaseRepository<EntityType, PKType, RepositoryType> OnlyActive ( )
  {
    IActivable activable = this as IActivable;

    if (activable == null) return this;

    _criteria.Add(Restrictions.Eq(activable.IsActiveField, true));
    return this;
  }

  private BaseRepository<EntityType, PKType, RepositoryType> Sorted ( )
  {
    ISortable sortable = this as ISortable;

    if (sortable == null) return this;

    _criteria.AddOrder(new Order(sortable.SortField, sortable.Ascending));
    return this;
  }

  public RepositoryType InitialiseListCriteria ( )
  {
    InitialiseCriteria();

    return OnlyActive().Sorted() as RepositoryType;
  }

  public EntityType LoadEntity ( )
  {
    return _criteria.UniqueResult<EntityType>();
  }

  public IList<EntityType> LoadList ( )
  {
    return _criteria.List<EntityType>();
  }

  public ICriteria GetCurrentCriteria ( )
  {
    return _criteria;
  }

  public RepositoryType ByIds ( IEnumerable<PKType> ids )
  {
    _criteria.Add(Restrictions.In("Id", (ICollection)ids));

    return this as RepositoryType;
  }

  public RepositoryType MaxResults ( int maxResults )
  {
    _criteria.SetMaxResults(maxResults);
    return this as RepositoryType;
  }

  public virtual bool Ascending
  {
    get
    {
      return true;
    }
  }
}

 

The generic signature contains the type of the repository, but the same result could be obtained with reflection and the parameter would dissapear. I am also using 2 sample interfaces, which bring default sorting and filtering behavior into the BaseRepository:

public interface ISortable
{
  string SortField { get; }
  bool Ascending { get; }
}
public interface IActivable
{
  string IsActiveField { get; }
}

 

Here is how a simple repository would look:

public class TagRepository: BaseRepository<Tag, int, TagRepository>, ISortable
{
  public TagRepository ByTagNames(IList<string> tags)
  {
    _criteria.Add(Restrictions.InG("TagName", tags));
    return this;
  }

  public string SortField
  {
    get { return "TagCount"; }
  }
}

 

and here is how it can be used:

IList<Tag> existingTags = _tagRepository.InitialiseListCriteria().ByTagNames(crtTagNames).LoadList();

This will load all tags which have a name from the given list, and sort them by TagCount.

 

The BaseRepository above contains a few more options, and others can easily be added.

 

 

Enjoy programming!

 

DDD

Dealing with information overload

by andrei 14. November 2008 20:02

"As to methods there may be a million and then some, but principles are few. The man who grasps principles can successfully select his own methods. The man who tries methods, ignoring principles, is sure to have trouble."
—RALPH WALDO EMERSON

 

Simply wonderful.

 

 

Enjoy programming!

 

Another DDD sample

by andrei 14. November 2008 19:56

Here is another DDD learning resource: http://timeandmoney.domainlanguage.com/.

 

 

Enjoy programming!

 

DDD

Don't leave the collation specified in your TSQL scripts

by andrei 14. November 2008 19:52

By default, SQL Server will generate scripts like this:

CREATE TABLE [dbo].[Questionnary](
    [QuestionnaryId] [int] IDENTITY(1,1) NOT NULL,
    [QuestionnaryName] [varchar](100) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
    [ActiveYN] [bit] NOT NULL,
    [UserId] [uniqueidentifier] NOT NULL,
    [RecordStamp] [datetime] NOT NULL,
PRIMARY KEY CLUSTERED 
(
    [QuestionnaryId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

 

This specifies the collation that should be used for the name field:

COLLATE SQL_Latin1_General_CP1_CI_AS

 

Some time ago I witnessed a situation in which collations created some serious problems between different database servers. Fortunately, this is quite rare so chances are that you will never run into such a situation.

 

A few days ago I encountered another interesting situation: for some reason, in one page the list of items was displayed in the wrong order. In all other pages the list was sorted correctly, and the only difference was that for this page the entries were sorted in the application code instead of the database.

A clue to the problem was the fact that the items contained special chars (like ', ., ", etc).

Here is how this particular situation has been solved.

 

Also, here is a bit of information about SQL collations extracted from here:

"Each SQL Server collation specifies three properties:

  • The sort order to use for Unicode data types (nchar, nvarchar, and ntext). A sort order defines the sequence in which characters are sorted, and the way characters are evaluated in comparison operations.
  • The sort order to use for non-Unicode character data types (char, varchar, and text)."

So, the SQL collation affects sorting. If you want to avoid some problems (including sorting problems), don't specify the collation.

In SQL Server Management Studio, you can change the default behavior for generating scripts from Tools -> Options -> Scripting:

image

 

 

Enjoy programming!

 

If it's not the simplest coding task, you should also test it

by andrei 14. November 2008 19:03

We are optimistic by nature, but sometimes we should just be professional.

 

Here is one situation I see repeating from time to time (to me, or my fellow developers). I have a coding task (small development, small bug, doesn't matter), and I know exactly what needs to be done in order to solve it. I know that functionality very well, I am familiar with that code, the confidence is high. I could make the change with my eyes closed, and it would solve the problem for sure.

I make the change, and for some reason I decide that nothing can go wrong and I don't need to test it. For me, some of these reasons are:

  • I have to get to something else quickly
  • I don't have enough patience to test it right now
  • the client needs this change right now

I quickly commit the change on SVN, move on and forget about it.

 

The result, a few hours or days later?

I can't believe it! I didn't realize that [something bad related to the change].

If I'm lucky, the person who observes the problem is someone from our testing team. Unfortunately, if I install the change directly on the production environment (due to client pressure) I can't be lucky.

But... if I'm lucky, the change does not break anything new. It just doesn't work, because it needs an additional change in order to work. Again, sometimes I am not lucky.

 

Here is why this happens: we are not computers, and we can't calculate all the implications in a situation unless it is very simple and without implications. Also, we sometimes forget things.

In software, actions generate effects. If you rely on your mind to control these effects, you will run into problems. In order to be efficient, you need to test the result in an objective way: the simplest (and usually slowest) method is to run the application and see what happened after the change, the sophisticated (and correct) method is to have automated tests.

So, unless you are changing the text in a label, resist the pressure / temptation and test the change before doing the commit.

 

 

Enjoy programming!

 

Powered by BlogEngine.NET 1.4.5.0