Ivan Krivyakov's Blog

Premature optimization is the root of all evil

September 1, 2010

RedGate SQL Source Control

Another tool I tried today. The idea is very cool, but I don’t like the fact that after I “link” the database I suddenly get gazillion changes to commit. I would think that “linking” means submitting current state to the DB.

Also, it is not clear how to get rid of the users and roles information, I don’t want it in source control.

RedGate SQL Compare

As per this survey, RedGate SQL Compare is one of the best SQL comparison tools on the market. I downloaded a trial today. It works fast, produces safe synchronization scripts wrapped in transaction, and is generally cool.

I did, however, stumble upon a stored procedure that it marked as “different”, although it could not show a single difference between two databases. Applying synchronization script once did not help, I need to apply it twice.

August 31, 2010

Some anti-patterns I am experiencing first hand

I am working on a rather interesting WPF project, which “implements” so many anti-patterns I had to blog about it. The most interesting thing about this project is that it was written by some of the best and smartest programmers I know, so the anti-patterns stem not so much from incompetence, but from general conditions these programmers were forced to face and maybe general lazyness and go-with-the-flow.

1. Prototype-turned-project. The code is simply not production quality. Logging is non-existent, errors are swallowed (as in “try {...} catch {}“), user facing messages have form of exception traces without headers and icons, database tables don’t have indexes, and so on, and so forth.

I was told that initially the customer gave the programmers a long list of features and a very short deadline (“demand the impossible if you want to get the maximum”). The results were good functionally, but code quality suffered. Of course, this is only one side of the story.

2. Cut-and-paste code. Well, you know what I am talking about. When you have SourceFilterButton and SourceFilterButtonA, and everything in code has a regular version and an “A” version that differ ever so sligtly, you have a case of cut-and-paste programming.

3. Using generic DataSets all over the place. This definitely takes the Object-Relational Mapping issues out of the way, because there are no objects. But then everything is just a glorified array, and the dependencies on data are implicit. E.g. by looking at

void ProcessScenario( DataRow dtScenario );

it is impossible to tell what columns this method expects to see in dtScenario and what types they should be. This dependency is implicit, and implicit dependencies are evil, because they are broken easily. This code also assumes that all information about a scenario can be coded in a single data row. If scenario becomes something more involved, e.g. it now includes an array of sub-scenarios with their own settings, this code will have to be heavily modified.

Also, as DataTable and DataRow become prevalent parameter types, they start to be used as a means of communication between different parts of the code, without ever going to the database:

void ProcessScenario( DataRow row )
{
    int id = (int)row["ID"];
    double amount = (double)row["AMOUNT"];
    ...
}

void CallProcessScenario( double amount )
{
    DataRow row = scenarioTable.NewRow();
    row["ID"] = myId;
    row["AMOUNT"] = amount;
    ProcessScenario(row);
}

void ProcessScenario( DataRow scenario );

4. Mixed business and presentation logic.

It is mauvais ton to pass data between two business logic units through UI. This makes writing unit tests impossible:

moviesGrid.DataContext = SomeTable;
...
void LookupMovieById(string id)
{
    DataTable movies = (DataTable)moviesGrid.DataContext;
    ...
}

The movies table should be stored in a model object and UI should not be involved:

class Model
{
    public DataTable Movies { get; private set; }

    public void LookupMovieById( string id )
    {
         .... Movies ...
    }
}

class MyView
{
    Model _model;
    ...
    moviesGrid.DataContext = _model.Movies;
    ...
    _model.LookupMovieById(...);
}

5. Pseudo Hungarian notation and abbreviations in variable names. Names like dtCurrVect are evil. currentVector is better, currentPriceHistory is better still.

6. Big classes using #regions Whenever you feel like you need to add a “#region” to your class, it probably has become too big. It should be split into smaller classes. I’ve seen a class responsible for three totally different (albeit) related screens, handling both business and presentation logic for all. Figuring out what depends on what was a nightmare.

7. Mixing data and UI concerns is evil and makes business logic impossible to unit test. The data must be calculated in a manner totally segregated from UI, and then, if necessary, assigned as a data source to the UI object. WPF is property based, so exposing data sources as properties allows to use bindings in XAML and generally move closer to nirvana. E.g.

void Bind( DataGrid grid, string filter )
{
   BindImpl(grid, fitler, field);
}

void BindImpl( DataGrid grid, string filter, string field )
{
   grid.ItemsSource = new DataView(... filter, ... field);
}

Bind(gird, "foo=3");

is refactored to

DataView GetData(string filter )
{
   return GetDataImpl(filter, field);
}

DataView GetDataImpl( string filter, string field )
{
   return new DataView(...);
}

grid.ItemsSource = GetData("foo=3");

This way obtaining the data (business logic) is clearly separated from assigning this data to the grid (presentation).

8. Keeping logic in stored procedures. Stored procedures are written in another language, they are difficult to debug, difficult to put in source control, difficult to refactor, and generally they belong to antoher world several light years away. If you need server-side processing, write a layer on top of your database (a web service perhaps?) and do it there. In my book stored procedures are warranted only in case of extreme performance problems, when they save tons of data going back and forth between the database and the web server.

In the course of this project, a significant piece of logic was moved from C# to a stored procedure (because it seemed more efficient that way), and then back, when we needed to add something a database cannot handle, like solving an equation using binary search. Each movement between C# and stored procedure required a lot of work and created a number of bugs.

CONCLUSION. Never, ever let your prototypes to become product. If there is a remote chance of this happening, treat your prototype as the real thing, or you will be sorry later. Whenever a sales person approaches you asking to write "a little throw-away demo" know that they are most likely lying. They will never tell the customer this is a throwaway, and if they succeed in selling that demo, the customer will assume it's already a product, and will demand new features, that you will be pressed to deliver ASAP. So, you have a good chance to get stuck with that "throw-away demo" for a long time.

August 24, 2010

Can’t have a binding to binding

Let’s say we want to display a list of countries, and depending on the user input we want to show either the capital city, population, or the language spoken in the country alongside the country name, like in the application below:

Dynamic binding screen shot

The only way to achieve that is to change binding in code. You cannot have something like

<Binding Path="{Binding SelectedField}" />

because Path is not a dependency property. :(

August 13, 2010

WPF: Merged dictionary parser depends on XML attribute order

Does attribute order in XAML matter? It should not, but sometimes it does. The following XAML compiles, but blows up at runtime with “Item has already been added” exception, both in .NET 3.5 and .NET 4.0:

<Window x:Class="MergedDictionaryKeyPosition.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
  <Window.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary>
                <Style TargetType="Button" x:Key="foo" />
                <Style TargetType="Button" x:Key="bar" />
            </ResourceDictionary>
        </ResourceDictionary.MergedDictionaries> 
   </ResourceDictionary>
  </Window.Resources>

  <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="Hello" />
</Window>

What’s wrong with it? [read more...]

August 12, 2010

ClickOnce Publisher WTF

Today ClickOnce publisher came up with this message:
“The application platform does not match the existing application on the server. Do you want to overwrite it?”

What is the platform on the server? What am I replacing it with? This would be one line of code to add this information. But alas, I am left in the dark about it. Someone saved 5 minutes while coding. It costs hundreds of programmings hours of grief.

August 8, 2010

Database proramming rant

After a long while I am back to dealing with databases directly from ADO.NET. Guys, this is ridiculous. Any serious library designed like that would be heckled. This is what I found (or rediscovered) in the course of one day:

  • if your SqlConnection uses SQL Server local transaction, you must manually transfer the transaction to the SqlCommands you use. If you don’t, you get InvalidOperationException.

    ExecuteNonQuery requires the command to have a transaction when the connection assigned to the command is in a pending local transaction. The Transaction property of the command has not been initialized.

    You are on your own in determining what transaction that is: SqlConnection has this information, but it won’t tell you. More details here.

  • If you have a typed DataSet with a number of tables connected by relationship, there is no easy way to fill it from the database all at once. E.g. if I have customers and orders, there is no way to get “all orders for customers with State=’OK’” into the dataset. If you write a JOIN query, it will create one table, and the dataset won’t convert it into multiple tables. You can use OleDB proprietary SHAPE queries, but a) this is not standard SQL, and b) you get some weird table names, so I could not make it to work as well.

    So, you can build a relational structure in memory, but you cannot copy data from DB. The best you can do is filling the tables one by one. Ridiculous.

  • SqlDataAdapter won’t automatically initialize insert, update, and delete commands when given the SELECT command. You must use SqlCommandBuilder object, which implicitly modifies the underlying adapter. Looks very weird.

    If their point was separation of concerns, then why the command builder cannot do it without the data adapter? Just take command text and return SqlCommand. More often than not, I do want the commands built if that’s possible. I would either have the adapter build the commands by default (which can be turned off if not desired), or at least have some adapter factory object.

  • If you use SqlDataAdapter to add new rows with identity columns, there is no way to get resulting identity values back. The only thing I found short of writing SQL by hand is to build the insert command, steal its text, append something like “; SELECT SCOPE_IDENTITY();” to it, and then execute it by hand, bypassing the adapter.
  • Bottom line: ouch. So much time spent on problems that simply should not be there in a decently designed system.

July 6, 2010

VS 2008 unit test host cannot run tests in one thread

Our UI code is single threaded and UI classes use some shared static data. They work just fine, but the unit tests sometimes fail. Investigation led to threading issues. Visual Studio unconditionally runs tests in multiple threads simultaneously, and apparently there is no way to tell it not to do that.

http://social.msdn.microsoft.com/Forums/en-US/vstswebtest/thread/4cdd4668-d99c-4699-8e1c-b775498593e7

July 1, 2010

WPF: Is clone of Freezable frozen?

WPF defines a Freezable type that is a base class for “almost immutable” objects. They can be setup in read/write mode and then “frozen” which makes them immutable and thread safe.

Freezables are also cloneable. If I make a clone of a Freezable, will it be frozen? Fortunately, it won’t, so I can modify the clone at will, and then freeze it if necessary. Here’s the passing unit test that proves that:


   [TestMethod]
   public void ClonedFreezableIsNotFrozen()
   {
      var brush = new SolidColorBrush(Colors.Red);
      brush.Freeze();
      var clone = brush.Clone();
      Assert.IsFalse(clone.IsFrozen);
   }

June 29, 2010

XSLT and Microsoft.NET

While working on XML serializers I wandered into the XSLT land. It turned out that XSLT support in .NET is not stellar. Well, you may already know that, but it is new to me. First, only XSLT 1.0 is supported. It is useful for simple stuff, but even an iteration over a list of known values is difficult. There are two classes for XSLT in .NET: an obsolete class XsltTransform and a newer XsltCompiledTransform. Both of them are XSLT 1.0, the latter been allegedly faster and more secure (read: more items disabled). E.g. you cannot use document() function by default. Overall, I am disappointed. I wanted to use XSLT for simple things like show summary and results of XML serialization calls, and it turns out I have to use XSLT 2.0 (distinct-values) or non-standard stuff like node-set for even the simplest things.