2010-12-11
Insourcing and responding to change
"Udviklingen er for nylig blevet insourcet igen efter nogle års outsourcing [...] Formålet med insourcingen af udviklingen er at sikre hurtigst mulig reaktion i forhold til både vores danske kædekunder og vores internationale ekspansion."
The ad can be viewed here: http://goo.gl/vFHpm
2010-11-24
The only people who like to hear that their code is bad, is people who's trying to get better
- I can show you how to be better.
- I don't want to be better. I want to keep sucking.
Let them keep sucking! The only people who like to hear that their code is bad, is people who's trying to get better. Those are the only people you wan't to associate with in the first place anyway.
[...] If you don't set yourself apart, you're going to work on mediocre projects. That'll screw you over. It kinda makes you stupid."
- Giles Bowkett in this.life() 1.0.4: Being Mean
2010-05-04
Coders at Work Speaking Words of Wisdom
It's a very interesting book, which I wholeheartedly recommend to anyone who cares about their profession as a software developer.
Below some words of wisdom from three of the interviewees:
Thompson: "My definition of fragile code is, suppose you want to add a feature — good code, there's one place where you add that feature and it fits; fragile code, you've got to touch ten places."
Siebel: "[…] people […] work long hours because we have this idea that we've got to get this product out the door and the way to do it is for everyone to work 80, 100 hours a week."
Thompson: "That generates burnout. […] external deadlines — generate stress."
Siebel: "[…] in terms of getting things done in the short term, does it work?"
Thompson: "Usually you're in a position where such a thing is continual."
Siebel: "Can you estimate how long it's going to take to write a given piece of code?"
Thompson: "[…] if you're doing it for production then usually there are other people involved and coordination — I can't estimate that."
– Ken Thompson, p. 467, 478 & 479
"[…] a design review double checks that the parts that he [the programmer] thought he had right he did have right and potentially give him some insight on the parts that he didn't. […] such an obvious good use of the senior talent doing the review."
– Bernie Cosell, p. 539
"[…] software required so much attention to detail. It filled that much of my brain to the exclusion of other stuff."
"I think it is always going to be true that a person who manages programmers should not expect it to be predictable."
– Donald Knuth, p. 572
2010-03-25
Merge (fka Upsert) Extension Method for IDictionary
[TestFixture] public class IDictionaryExtensionsTests { [Test] public void ShouldAddIfKeyDoesNotExists() { var dictionary = new Dictionary<string, int> { { "nøgle", 100 }, { "key", 200 } }; dictionary.Merge("nyckel", 300).Count.Should().Be.EqualTo(3); } [Test] public void ShouldUpdateIfKeyExists() { var dictionary = new Dictionary<string, int> { { "nøgle", 100 }, { "key", 200 } }; dictionary.Merge("nøgle", 400).Count.Should().Be.EqualTo(2); dictionary["nøgle"].Should().Be.EqualTo(400); } } /// <summary> /// Adds the key/value pair if the key doesn't exist, or updates the key with /// the supplied value if the key exists. /// <remarks> /// The name "Merge" is taken from SQL:2003 (f.k.a. "Upsert") /// <see cref="en.wikipedia.org/wiki/Merge_(SQL)"/> /// </remarks> /// </summary> public static class IDictionaryExtensions { public static IDictionary<TKey, TValue> Merge<TKey, TValue>(this IDictionary<TKey, TValue> thiz, TKey key, TValue value) { if (thiz.ContainsKey(key)) { thiz.Remove(key); } thiz.Add(key, value); return thiz; } }
2010-02-12
YAK - Yet Another Keyboard Navigator for Chrome
I implemented it as a user/Greasemonkey script, which will pass as an extension in Chrome.
YAK web site: http://yak.nfshost.com/
YAK @ userscripts.org: http://userscripts.org/scripts/show/68609
2010-02-10
Poor Man's Custom Types with C# Using Aliases
What I've just started doing in order to achieve the same level of readability, is using aliases like so:
using Birthday = DateTime;
using PersonId = Int32;
before the class declaration, but after the namespace declaration (so that one doesn't have to fully qualify the type names).
For complex generic types, the readability increases even more IMHO:
using StrangeDictionary = IDictionary<int, KeyValuePair<string, decimal>>;
/Martin
2009-12-01
Oracle Horror Morning
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
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-21
2009-11-02
“Programming as you know it just died”
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-21
"I often find that a nice design can come from just being really anal about getting rid of duplicated code"
Hear, hear!
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; } }
2009-10-01
Pragmatic Thinking and Learning: Refactor Your Wetware
2009-09-24
Great Lean/Kanban Post
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-23
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 ;-)
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.