CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Peter's Gekko

public Blog MyNotepad : Imho { }

May 2006 - Posts

  • Contact me over here

    I'm in the process of handling all my own email. Today I switched and just wish I had known in advance of all the hurdles. Going to be great blog fodder when it's all ironed out. In case you can't reach me this address does work: Peter@PetersGekko.net

    It's also the updated website with an improved publications index.

  • I inherited a database which contains sprocs (and a lot of other BL)

    Last week another rant on stored procs in databases passed by. A lot on it has been said over and over again but still I would like to add my 2 eurocents. Recently I inherited a database which contained a lot of sprocs and other coded logic. So I was forced into some more real world experience. The thing I would like to state in advance is: "It's not about stored procedures but about T-SQL in general". This is not about TDD either but, for different reasons, I will end up thinking not to positively about (some) sprocs either.

    First of al I have to mention that neither time, resources, budget or culture of the customer had any room for a good thorough re-grounding of the project towards OR-mapping or TDD. The project was a classical 2-tier Delphi SQL server 2000 CS application which we had to turn into an ASP.NET application. We were a two person team: me and an application manager with a historical (and good!) working knowledge of T-SQL. An OR-mapper was beyond the horizon; when it came test-driven the main thing we missed mostly in the end was regression testing: "are all event-handlers still attached to the button's", "do the database and the code still match" or even worse "are we talking to the right database". A little more on that later.

    The first concern was to get the data separated from the (ASP.NET) user interface. A lot of the documentation was in the form of (Delphi) source code, the separation of the layers was not always too good. As a start I wrapped the database in an assembly which defined a limited number of xsd schemas whose definitions were steered by the need of the application and not the physical structure of the database. The data was sent in and out of the assembly by passing datasets. Inside the assembly I could play with my SQL and the sql found in the database.

    When battling the database 3 forms of T-SQL coded logic were found:

    Views

    A view is a selection of rows and columns from one ore more database tables. The views defined provided a clear way to start working with the database. They define a set of data. SQL is very good at this, before there was linq there is nothing which beats a SELECT statement with a couple of JOINS. It's a .net 1.1 project so linq is out of the question. To write a view I prefer using a visual tool like sql server's query builder. A picture beats a thousand words and clicking the checkboxes of a column is faster and less error prone than writing out the full column name.

    But views have one enormous disadvantage: they do not support parameters. Our system has a lot of user defined selections; it's not unusual for a user to do a selection on two or three columns out of a list of eight. These are not ad-hoq queries; it's a basic requirement. This would require eight parameters to the view (which is not possible) and a check for a null value on every parameter (which would add needless complexity to the query. In comes the dynamically generated sql. To get best of all worlds I ended up using sqlAdapters to get a nice design time experience and generate the dynamic sql from code which uses the adapters command text and adds parameters where required. Something like this, which operates on a dataAdapter named StudieOnderdelenSelectie

    StringBuilder bc = new StringBuilder();

     

    if (selParms.opleiding > 0)

    {

        StudieOnderdelenSelectie.SelectCommand.Parameters.Add("@Opleiding", selParms.opleiding);

        bc.Append(string.Format(" AND idOpleiding = @Opleiding"));

    }

     

    if (DBoperations.checkStringInput(selParms.studieOnderdeel))

    {

        StudieOnderdelenSelectie.SelectCommand.Parameters.Add("@StudieOnderdeel", selParms.studieOnderdeel + "%");

        bc.Append(string.Format(" AND (StudieOnderdeel LIKE @StudieOnderdeel)"));

    }

    if (selParms.jaargang > -1)

    {

        StudieOnderdelenSelectie.SelectCommand.Parameters.Add("@Jaargang", selParms.jaargang);

        bc.Append(string.Format(" AND jaargang = @Jaargang"));

    }

    if (selParms.periode > -1)

    {

        StudieOnderdelenSelectie.SelectCommand.Parameters.Add("@Periode", selParms.periode);

        bc.Append(string.Format(" AND periode = @Periode"));

    }

    if (selParms.idAfdeling > -1)

    {

        StudieOnderdelenSelectie.SelectCommand.Parameters.Add("@idAfdeling", selParms.idAfdeling);

        bc.Append(string.Format(" AND idAfdeling = @idAfdeling"));

    }

     

    sortOrder = "StudieOnderdeel";

     

    bc.Append(string.Format(" ORDER BY {0}", sortOrder));

    StudieOnderdelenSelectie.SelectCommand.CommandText+= bc.ToString();

    This code can be applied only once on a  sqlAdapter. It works in a web based environment where the adapter is per definition recreated on every roundtrip. In a winforms app this is different. Another thing to watch is the the ORDER BY part. It always has to come last. If you set it at design time you'll have to parse the adapters sql text to find the right place to inject (pun not intended) your sql.

    I'm not proud of this code but it provides a very workable scenario.

    Stored procedures

    The moment you start working with parameters in a sql server tool like the enterprise manager, query analyzer or the like you enter the world of stored procedures. In my view there a three kind of stored procs. One is a view with parameters. All the sql included does is construct a set of data to return. Again this is sql at its best. As the previous part should have made clear I don't like this functionality as part of the database. Give me a view or a table and my code will construct the parameters as desired.

    The second kind of stored procs updates sets of data, things like

    UPDATE RoosterActiviteitDocent SET idRoosterActiviteit = @idRoosterActiviteit, idPersoneel = @idPersoneel WHERE (idRoosterActiviteitDocent = @Original_idRoosterActiviteitDocent) AND (idPersoneel = @Original_idPersoneel) AND (idRoosterActiviteit = @Original_idRoosterActiviteit); SELECT idRoosterActiviteitDocent, idRoosterActiviteit, idPersoneel FROM RoosterActiviteitDocent WHERE (idRoosterActiviteitDocent = @idRoosterActiviteitDocent)

    Again you can have this code as stored procs in your database but you can also generate the sql from code. Something your favorite OR-mapper or even VS can do it for you. The example above was built by the sqlAdapater wizard.

    The third kind of stored procs is where sql imho shows a very ugly face. It's not sql which defines a set of data but starts traversing on its own. To take a snippet

    ....
     open
    IDAFDELING_CURS
    fetch next from
    IDAFDELING_CURS
    into
    @AIDAFDELING

    while (@@fetch_status = 0)
    begin
    declare IDJRBDGAFD_CURS cursor
    for select
    IDJRBDGAFD,
    BEDRAG
    from
    JRBDGAFD
    where
    IDCURSUSJAAR = @AIDCURSUSJAAROUD and
    IDAFDELING = @AIDAFDELING;

    open
    IDJRBDGAFD_CURS
    fetch next from
    ..
     

    Here it's sql as a general programming language. Needless to say a language as C# (or vb.net, Delphi, etc) has far more and better programming and debugging possibilities. These stored procs are a point of pain in the application. They do quite important things but, like al code, contain bugs. Bugs which are very hard to find and fix. Some of the sprocs do take a lot of time to complete which is an extra problem in the new asp.net version of the application; the former windows CS app would just show an hourglass for quite some time. But, provided you don't take action, a web request has several places to time out.

    Triggers

    Triggers go off when data in the database is changed. Inside a trigger you can write almost any sql you desire. Included all of the horrors I mentioned in the stored proc part. And perhaps even worse. For instance it is possible to start a new transaction inside a trigger. What will happen if the transaction inside the trigger commits but the transaction which fired the trigger fails? This is without a doubt hidden somewhere inside the docs but I even don't want to think about it. Our system does not do that much inside its triggers. No traceable problems yet. Thank goodness as triggers are even harder to debug.

    My conclusions

    As the story should have made clear I'm not that happy with any coded logic in our database at all; most of it can be done far better in C# from a layer in the application. In his posts Eric has mentioned some strong points in favor of putting it in the database nevertheless. This is my view on these

    • Maintainability. With a DB server this is an issue in general. The tools to write, debug and organize code in a database completely pale in comparison with Visual Studio. The less code in the database, the better. And I am a very happy user of  RedGate's sql Compare to compare and update anything in the database.
    • Security. SqlServer has a very fine grained role based security system which can be applied down to the column level. Why hide that in a view? What if some admin creates another view without the restriction? That's not possible when the security was set on the table itself.
    • A division of responsibilities. Just like Jeremy I could not agree less on this. Involving the DBA and all other IT staff as early and much as possible only helps to get your project up and running. We may have some problems with database coded logic but these completely pale by the problems we're facing with the IT pro staff. These problems boil down to a lack of involvement on their side; they try to handle the project (which spans multiple servers in the network) as a help-desk ticket and refuse any involvement deeper than the "next, next, finish" level. Even checking whether the app connects to the right database can be a problem... My co-worker, who has to handle the far more difficult database stuff, is very involved and dedicated. In my view that has saved the project from becoming a nightmare. After all it's the man not the technology.

    My future

    For new functionality we needed some complex data manipulation which included things like splitting a column into an arbitrary number of new columns. The classical approach would have been to write a complex stored proc which would create a temporary table in the database and fiddle with that. Instead I wrote (visually designed :)) a straightforward SQL select statement to fill a dataset. And handled all the column and row manipulation in plain C# working with the dataset.

    Such a relief...

  • Daddy, the TV doesn't boot !

    That's what my, 7 year old and gadget freak, son Cas shouted to me last weekend. It would have made sense in case we had a media center, but  the failing device was an old featureless 30-channel creature; to switch from DVD to video requires changing cables. It got weirder when the only remedy to get it working again was much like a cold reboot: switch off, pull the plug, wait ten seconds and start over in reverse direction.

    Cas has some more completely software centric sayings. To turn of the light he doesn't push but click the switch.

    It's a whole different generation coming up :)

  • A better refresh button for asp.net pages

    Yesterday I wrote a little post on a refresh button for asp.net pages. It worked but had jump through some hoops. To simulate a refresh it posted back to the original page which in turn redirected itself to itself. Which is a waste of resources. As Simone pointed out it should simpler; like a straight link out of the browser. He's right. I will use a server side hyperlink as that gives me the possibility to fiddle with its properties on the server.

    This refresh button works just like the back button,  this one sets it's url to that of the page itself.

    [ToolboxData("<{0}:MyRefreshLink runat=server></{0}:MyRefreshLink>")]

    public class MyRefreshLink : HyperLink

    {

     

        protected override void OnLoad(EventArgs e)

        {

            if (!Page.IsPostBack)

                base.NavigateUrl = Page.Request.Url.ToString();

            base.OnLoad(e);

        }

     

        [Browsable(false)]

        public new string NavigateUrl

        {

            get

            {

                return base.NavigateUrl;

            }

        }

    }

    In the back button post are instruction how to use the control in your projects.

    Hope you'll like this one better.

  • A refresh button for asp.net pages

    Your browser has a back, forward and refresh button. Some time ago I wrote a little post on a back button to include on your own asp.net pages. According to the feedback you liked that one. Here I would like to share a refresh button. Quite simple and it works well! Although not as simple as the better version which resulted from the feedback on this one,

    You work with this code just like the back-button. This is the code

    using System;

    using System.Collections.Generic;

    using System.Web.UI;

    using System.Web.UI.WebControls;

    using System.ComponentModel;

     

    namespace WebControlLibrary

    {

       /// <summary>

        /// Summary description for MyRefreshButton.

        /// </summary>

        [ToolboxData("<{0}:MyRefreshButton runat=server></{0}:MyRefreshButton>")]

        public class MyRefreshButton : System.Web.UI.WebControls.LinkButton

        {

            protected override void OnClick(EventArgs e)

            {

                base.OnClick(e);

                Page.Response.Redirect(Page.Request.Url.ToString(), true);

            }

     

        }

    Also this one is a descendent of the linkbutton. When it's clicked it redirects the response to the url of the page itself. Which will start a new series of roundtrips. Your page will have it's initial state again.

    The actual behavior is not quite the same as that of the browser's refresh buttonn

    • Before issuing the redirect any click handlers are invoked in the base.OnClick(). In there you could do some things to save work.
    • Due to the way the page lifecycle works pageload and other eventhandlers will be executed before the redirect. Using the browser button these will not fire. The page prerender will not fire.

    The better version does not have this extra behavior.

    Hope you like it

  • It's the man, not the methodology

    Lately there has been quite a lot of discussion on "Agile" versus "Waterfall"  methodology. Taking some steps back I want to add my 2 eurocents.

    What is methodology? To quote Wikipedia :Methodology is defined as (1) "a body of methods, rules, and postulates employed by a discipline", (2) "a particular procedure or set of procedures", or (3) "the analysis of the principles or procedures of inquiry in a particular field". A methodology describes is the way  you are going to realize your software system: what are the parts, what tools will you use and in what order will you work.

    The Waterfall methodology is a historical one. In the beginning days of computing computing resources were very scarce. Everything, including every line of code, was first simulated by hand. When I started in IT waterfall methodology was the thing you had to learn to join in any project. These days every developer has the resources to try and run countless variations in code and design on his own desktop. So the historical origin of waterfall no longer applies.

    Waterfall has to be done right by the people upstream. When they fail it's up to you to either row upstream and return the mess they have created or find a way out of it yourself. In my remembrance are two projects. In both cases I was handed an impressive pile of paperwork. Impressive in size but not always in content. The detail in which even the most trivial things were described were enough to beat every grain of imagination out of the person who had to implement it. In both cases the worst was kept to the end: the designer had no time left to describe the system's final modules. In these some really complicated matters were handled which involved pretty complex business rules. One application was a savings system. How to search and edit the address of a participant had been described in detail, but there was not a single line how to consolidate the savings at the end of the year. The other system  checked working hours against legislation. What the main menu of the application should look like was described three (!) times. But how to check working hours against the complex rules of the law was, due to to a lack of time (budget), open to my own interpretation of the text of the law.

    In both projects an appeal was made to my ability to improvise. As I am no financial expert nor a lawyer I bypassed the designer and went straight to the end user themselves. We set up a trial and error schedule of regular meetings and frequent updates. Step by step we managed to realize usable systems.

    For the savings system I worked with someone who had worked for the company all her life, liked her job and was very keen on learning. Despite the complex flow of money we got it up and running within time and budget. For the legislation system I worked with people who had been working for their employer too long, were looking forward to their retirement and did not want to learn anything new. I had to drag every rule out of them, try to translate their jargon into mine and double check over and over again they did not say "yes" just  to make me stop asking. My patience had a hard time but eventually we completed the project. Mainly because we were allowed extra time and budget.

    Both projects started as a traditional waterfall but in the completion we did a lot of things which would sound pretty "agile" these days. Agile is based on best practices learned in the past. But the main thing I learned was that it's not the methodology which determined the success but the people behind it. It's up to us developers to adapt to change, even having been beaten unconscious by dumb design. It's up to the end users to show real involvement with the project. When somebody does a bad job in "waterfall", the designer doing half work, it will not always show up immediately. When somebody does not participate well in "agile" your alarm bells will go of the first day.

    In the core of agile development lies testing. To have good tests takes dedicated people as well. You may have a very good testing framework but when there is no-one around to tell whether the result of the test is a pass or failure that test is just as useless as the big paper pile of upfront design.

    A lot of people don't really have a methodology. They do have a set of best practices and rule of thumb but nothing formalized. I'm one of them. This story is not intended as a "How I found agile" confession. Nothing wrong with a well designed set of specs. But lots and lots agile practices are based on hard learned experiences, also by me. The main thing is that whatever way you work, you have to do it good. You want to design every detail up-front ?  Make it a good design. Which might be, due to a variety of reasons,  difficult or even impossible. Agile appeals as a way out but it is no silver bullet either. It does take even more dedicated people, not just the developer but also the end users. To make it works takes human beings: it's the (wo-) man and not the methodology, technology,  tool or whatever else

More Posts