2009-12-01

Oracle Horror Morning

First, I need to say that the database I've primarily used for the last decade is MS SQL Server.


I needed to write a simple function like so:


is_holiday(in_code in varchar2, in_year in integer, in_month in integer, in_day in integer)


that returns a boolean.


First, I wrote a few tests like these:



select is_holiday('xyz', 2006, 8, 1) from dual;   -- false 
select is_holiday('xyz', 2009, 11, 1) from dual;  -- true 

When I ran the tests after implementing the function I got the following messages:




SQL Error: ORA-06552: PL/SQL: Statement ignored
ORA-06553: PLS-382: expression is of wrong type
I later learned that this is because booleans aren't allowed inside SQL like that. A sort of misguiding and not very helpful error message IMHO.

On my quest of finding a solution, I also tried named params like so:

select is_holiday(in_sm_center_code => 'xyz', in_year => 2006, in_month => 8, in_day => 1) from dual;

That gave me the horror:


ORA-00907: missing right parenthesis
What?!?




Once again, PL/SQL programs differ from the SQL statements like that, where the params can't be named, but must be in positional form.


Why not simply state that in the error dialog box?


Thanks to this blog: oraclequirks.blogspot.com, I got my head around these issues and solved the task at hand.

2009-11-24

More on TDD and BDD, but this time I link to interesting resources from ThoughtWorks

Here are two interesting slide shows from ThoughtWorks that closely relates to what I wrote regarding executable acceptance tests (stories) some time ago:


Acceptance Test Driven Development (ATDD)


Acceptance Testing vs. Unit Testing: A Developer’s Perspective


I think these two resources make a good theoretical starting point for the "Why ATDD?" question.


Don't just look at the slides as slide shows, since there's a lot of great stuff in the comments.

2009-11-02

“Programming as you know it just died”

The above was stated by Juval Löwy during today’s workshop at øredev entitled “Service-Orientation, WCF, and You”.

Just like every .Net class conceptually is a COM-object, Juval argued that with the challenges we as biz app architects/developers face today, every (.Net) class should be a (WCF) service.
The main reason is that basically all complex plumbing such as security, concurrency, logging, fault tolerance, and so forth is given to you for free.
The learning curve is however mammoth, and is best compared with going from procedural to object-oriented programming.

When interpreting all the signs from MS, Intel, and others, Juval means that it is clear that service-orientation is the next paradigm shift that will replace .Net.
The analogy is ATL, which made it it easy to follow the good practice of making your C++ class a COM one. Then .Net came along were this wasn’t framework-based. Now we have WCF making it possible to make every .Net class a service by utilizing a framework.
The financial figures also indicates this being the main focus of MS. Juval claims that the cost of WCF is some 150% of what went into the CLR.

All in all, this was an extremely mind-exercising day that left me with the feeling of seeing the world of programming with a new pair of eyes from now on.
I guess I’ll have to read Juval’s WCF book when the 3rd edition is out… ;-)


UPDATE Feb 11 2010:
1. There's a recent DotNetRocks show with Juval, where he explains all of this.

2. There's now a "rough cut" edition of the book available.

2009-10-15

Same old tale (about code quality and technical dept)

Yesterday, we had yet another great Agile Skåne meeting at Green Lion Inn in Malmö.

One of the members is right now experiencing how much bad code can hurt you.

His new employer went to the lowest bidder without any quality control for many years, and have ended up with a total mess, prohibiting them to add features their competitors offer, and hence can’t improve their market share.

How come this serious mistake is made over and over again? After all it’s common knowledge that quality makes you fast and able to respond to change in the long run. (I know, we’re irrational human beings…)

I don’t know if it’s true, but I want it to be:

“Quality is the best business plan.” – Pixar’s John Lasseter

At least, you can’t blame Pixar for not being successful…

More on the subject:

Fowler recently wrote an interesting piece on technical dept: http://martinfowler.com/bliki/TechnicalDebtQuadrant.html

There’s a book on the subject of not acting according to what’s known to work:
”The Knowing-Doing Gap” (ISBN 1422163520), which I haven’t read.

2009-10-07

Decreased changeability when TDD:ing, and a possible solution

Yesterday, we had a great alt.net øresund meeting at BestBrains in København. Sune held a great presentation about TDD, its pros, and cons. Actually, despite being a TDD fan and user, Sune is very insightful and realizes that TDD isn’t a silver bullet. It could actually decrease your changeability if done wrong for example.

I’ve personally experienced some of the pains Sune described and that we discussed during the open space session that followed. Actually, previously the very same day Martin N Jensen and I tried to start attacking some of them by complementing our TDD efforts with a BDD way of defining higher level requirements in the form of stories and scenarios.

During the bicycle/train ride home, i thought some more about these issues. Only two days before I had to fix a lot of tests that utilized mocking/stubbing when an API changed that didn’t affect the system behavior in any way. That got me thinking – what the frak am I doing?!? No business value in that activity…

My not-IRL-tested idea goes something like this:

You have two sets of unit tests.

  • Stable BDD tests that drives the SUT (System Under Test) by only looking at the highest level of state (i.e. the database), performs an action, and then verifies the resulting state/output on the highest possible level. These tests corresponds one-to-one with the requirements if using stories as requirements
  • Instable “classic” TDD tests that drives the design of the inner workings (classes and their interactions, individual methods, etc.) of the SUT

My idea definitely requires UFD (UpFront Design) more according to the lean way of developing software as opposed to some agile start-immediately approaches.

If you start with a set of fairly stable stories, and implement them as BDD tests in one way or another (we’re using StoryQ at the moment), you consider these tests as stable meaning it should require some thinking before changing them.

The much more fragile TDD tests are considered something that could be thrown away (likely in parallel with writing new ones), or rewritten if still needed, when the inner workings are refactored (e.g. when replacing Castle Active Record with Frog.Net Sune, or in my case when removing specialized repositories in favor of one generic the other day).

I feel that if I have my stories implemented as executable acceptance tests, then I would really get

  • true confidence when undertaking big refactorings
  • tests that could actually be read and understood by peers, and possibly some other stakeholders
  • regression test suite that verifies the SUT’s behavior, i.e. that the stakeholders get what’s agreed upon

As a potential benefit I also get extremely readable status reports of every story on e.g. the build server every time an ok commit is made. This is a huge benefit IMHO since it allows you to remove the possible need for a complex task tracking system but still gives your PM (and all others) complete real-time status, allowing you to work with a whiteboard and post-its as a kanban board.

2009-10-02

Programmatically configure Log4net with two rolling file appenders

public static class LogBootstrapper
{
    public static void Bootstrap()
    {
        RootLogger.AddAppender(CreateRollingFileAppender(Level.All));
        RootLogger.AddAppender(CreateRollingFileAppender(Level.Info));
        RootLogger.Repository.Configured = true;
    }

    private static Logger RootLogger
    {
        get { return ((Hierarchy)LogManager.GetRepository()).Root; }
    }

    private static RollingFileAppender CreateRollingFileAppender(Level level)
    {
        var usingFileName = string.Format("logs\\MyProject_{0}-{1}-{2}_{3}.log",
        DateTime.Today.Year, DateTime.Today.Month, DateTime.Today.Day, level.Name);
        var layout = new PatternLayout("[%level] %message%newline");
        var rollingFileAppender = new RollingFileAppender
        {
            Layout = layout,
            AppendToFile = true,
            RollingStyle = RollingFileAppender.RollingMode.Date,
            File = usingFileName,
            ImmediateFlush = true,
            Threshold = level
        };
        rollingFileAppender.ActivateOptions();

        return rollingFileAppender;
    }
}

Beats XML config IMHO.

2009-09-24

Great Lean/Kanban Post

... with a big extra plus for letting me know about "Pirate Metrics" for the first time:
http://raibledesigns.com/rd/entry/lean_teams_doing_more_with

Trying out Sharp Tests Ex with NUnit 2.5

/*before*/ Assert.That(logHandlersCount, Is.EqualTo(1));



/*after*/ logHandlersCount.Should().Be.EqualTo(1);




Even better readability :-)

More on Sharp Tests Ex here: http://sharptestex.codeplex.com/Wiki/View.aspx?title=SyntaxMainPage

2009-09-18

A NUnit Custom Constraint together with a String Extension Method

[Test]

public void WhenMyStringPropertyIsEmptyThenMyEntityMustBeInvalid()

{

var myEntity = new Entity { MyStringProperty = string.Empty };


Assert.That(myEntity, "MyStringProperty".IsIncludedInBrokenRules());

}


IsIncludedInBrokenRules() is an extension method that returns an instance of a class that inherits Constraint.

2009-09-08

SQLite - works on my machine ;-)

I have this new and shiny HP Z600 (x64) at work.

Recently I started using SQLite in-memory for unit testing NHibernate persistence logic.

When committing, my dear colleague with an older x86 machine got problems...

I reproduced the problem on my machine by setting the build target to x86 in VS08.

Just change to the 32-bit version of SQLite did the trick.

2009-09-02

Linq Group By

 

        [Test]

        public void CanAggregateIdAndValue()

        {

            var idValuePairs = new List<IdValuePair>

                                   {

                                       new IdValuePair(1, 1),

                                       new IdValuePair(1, 2),

                                       new IdValuePair(1, 3),

                                       new IdValuePair(2, 1),

                                       new IdValuePair(2, 2),

                                       new IdValuePair(3, 1),

                                       new IdValuePair(4, 1),

                                       new IdValuePair(4, 2)

                                   };

 

            var expectedAggregatedIdValuePairs = new List<IdValuePair>

                                   {

                                       new IdValuePair(1, 6),

                                       new IdValuePair(2, 3),

                                       new IdValuePair(3, 1),

                                       new IdValuePair(4, 3)

                                   };

 

            var aggregatedIdValuePairs = Aggregate(idValuePairs);

 

            Assert.IsTrue(expectedAggregatedIdValuePairs.SequenceEqual(aggregatedIdValuePairs));

        }

 

        private static IEnumerable<IdValuePair> Aggregate(IEnumerable<IdValuePair> idValuePairs)

        {

            // imperative OO

            /*var map = new Dictionary<int, int>();

 

            foreach (var idValuePair in idValuePairs)

            {

                if (map.Keys.Contains(idValuePair.Key))

                {

                    map[idValuePair.Key] += idValuePair.Value;

                }

                else

                {

                    map[idValuePair.Key] = idValuePair.Value;

                }

            }

 

            foreach (var aggregatedIdValuePair in map)

            {

                yield return aggregatedIdValuePair;

            }*/

 

            // declarative linq

            return (from ivp in idValuePairs

                   group ivp by ivp.Key into aggregateGroup

                   select new IdValuePair(aggregateGroup.Key, aggregateGroup.Sum(x => x.Value)));

        }

2009-08-20

Send to [blog] from GReader - had to try this

A flurry of features for feed readers: "

Since our last big launch, we've been thinking about ways to help our users better share, discover, and consume content in Reader. Today, I'm happy to announce several new features that we hope will further improve the way you use Reader.



Send to...


Send to menuWe've made it easier to share posts you like to Blogger, Twitter, Facebook, and more, with our new 'Send to' feature. (Incidentally, Blogger is celebrating its tenth birthday this month, and we're hoping our friends there will like this little birthday present.)

Just head over to the settings page, and enable the services you want to use. If your favorite service isn't listed (and you're feeling extra geeky), you can create your own 'Send to' link with a URL template.




Send to tab on the settings page



To share an item on one of your sites, simply click the 'Send to' button and choose your service. If you're into keyboard shortcuts, 'shift-t' will do the same.



Feeds from people you follow


When we added following, we tried to make it easier to find and follow people who share similar interests. Now we've gone even further, and made it possible for you to subscribe directly to the blogs, photos, or Twitter updates that anyone you're following has included on their Google profile.




Feeds from Mihai



To quickly subscribe to these sites, click the 'From people you follow' tab on the 'Browse for stuff' page.



More control for mark all as read

Mark all as read menuWe know people can be overwhelmed by too many unread items, and sometimes only want to see recent posts. The 'Mark all as read' button now has a menu that lets you choose to only mark items as read if they're older than your specified time frame. A tip of the hat to Nick Bradbury who pioneered this 'panic button' feature.



Finally, a few small tweaks in this release:



  • When you expand an item in comment view, you now get the full set of actions, enabling you to share, like, and star items without leaving comment view.

  • We added a 'Feeds' start-page option for the iPhone/Android/Pre mobile interface, so you can see a list of your subscriptions when you sign in.

  • There is now an option to show notes when embedding your shared items on other pages as clips.



As always, if you have feedback, please head over to our help group, Twitter, or Get Satisfaction.



"

2009-07-29

string.RemoveRegex(pattern)

[Test]

public void ShouldRemoveRegex()

{

   const string stringWithListNumbers = "This is a #9: string with #10: list numbers.";

 

    Assert.AreEqual("This is a  string with  list numbers.", stringWithListNumbers.RemoveRegex("#[0-9]*:"));

}

 

 

public static string RemoveRegex(this string arg, string pattern)

{

    var tagRegex = new Regex(pattern);

 

    return tagRegex.Replace(arg, string.Empty);

}

string.Remove(string toReplace)

/// <summary>

/// Alias for 'ReplaceWithEmpty'

/// </summary>

public static string Remove(this string arg, string toReplace)

{

    return arg.ReplaceWithEmpty(toReplace);

}

2009-07-21

string.ReplaceWithEmpty(string toReplace)

[Test]
public void ShouldReplaceWithEmpty()
{
const string arg = "This is a string";

Assert.AreEqual("This is a", arg.ReplaceWithEmpty(" string"));
}

public static string ReplaceWithEmpty(this string arg, string toReplace)
{
return arg.Replace(toReplace, string.Empty);
}

2009-06-30

Alt.Net Oresund Meeting at ITU 25th of June

We weren't that many people, but in return Martin N Jensen held a great presentation showing the new features of NUnit and how they compare to MbUnit and xUnit.Net.

I definitely learned a few new tricks that I'm eager to put to practice.

These include
  • BDD style constraints (improved readability)
  • Theories (specifications that run several combinations of input)
  • Generic test fixtures (run the same test for chosen implementations of an interface)
I've worked with MbUnit for about a year now, and before that MSTest for several years.

From 2001 to sometime 2005, I however used NUnit, and with the new additions and a new employer, maybe we'll see each other again soon.

I haven't fully grasped the theory concept, but will look into it. This seems like a good place to start: Theories in Practice: Easy-to-Write Specifications that Catch Bugs

A new employer? After having three really good offers to consider, I finally made up my mind this weekend. I will start working with the very same Martin N Jensen, and the other guys at BankInvest this autumn. I'm very excited, and eager to produce great financial software with great people.

2009-06-16

Fired

"Getting Fired Can Be A Positive Career Move

[...] It means that the job isn't right for you.

I have been fired five times, and each time my career took a step forward. [...]"

- Paul Arden in It's Not How Good You Are, It's How Good You Want To Be


"Fired? It's the Best Thing That Can Happen To You.

[...] You hated your situation anyway.

You must begin again.

It's a wonderful opportunity for you.

Literally, they let you go."
- Paul Arden in Whatever You Think, Think the Opposite.


More about these books from a far more famous programmer than me can be read here: http://www.codinghorror.com/blog/archives/001177.html

2009-06-11

What's a "renaissance developer"?

Since I claim to be a "renaissance developer", I think a link to what that means to me is suitable: The Renaissance Developer

At the JAOO conference 2006, the same thing was called "helstøbt udvikler".