What I did on 2005
Seems that there is a tendency to summarize all sorts of things at the end of the year, and this is one place that a Blog really help. Here is my end of year summary:
- I found Boo (And the light, too)
- I published my first OSS project, NHibernate Query Analyzer
- Got scared shitless
- Learned to use Subversion
- I found and posted a lot of my fanfic for the Wheel of Time
- Answered a nice quiz from Hanselman
- Found the prefect gift for a girl I know.
- Got into testing UI
- Went head on against a bus, and won
- Gave up on testing UI
- Thought about Free Software Support
- Got myself a fresh install of Windows
- Search for Peace, didn't find it
- Got into trouble with NMock
- I read a lot of books
- Read even more books
- Caught Microsoft cleaning up Windows - And I've the proof!
- I got into trouble because of an idiot with a desire for cola.
- Started to play with Dynamic Proxy, and broke .Net
- Started to work on Rhino Mocks
- I released Rhino Mocks
- Read my referrals, threw up, wrote a blog post about it
- Surprised by my code, in a good way
- Got excited because a patch of mine was accepted in an OSS project
- Got some exercise
- "Enjoy" being on Road 6 for 6 hours
- Started digging MonoRail
- Wrote Brail, a Boo ViewEngine for MonoRail
- I got out of the army! Talk about significant changes.
- Did some work on extentions for Boo
- I released a new version of NQA, this time with a logo
- Had fun writing a boo view for reflector
- Found the best utility for multi monitors users
- Kept on improving Rhino Mocks
- Got myself an iRiver
- Joined the Castle Team
- Discovered Mondays
- Got so excited with C# 3.0 that I stayed up until 2 AM reading the spec - Damn, but I'm a geek.
- I got a job (hm, no blog entry for that, strange...)
- Go angry with VS.Net and TDD - Won't be the last time, I bet
- Wrote NHibernate.Generics so I could work with a great ORM on .Net 2.0
- Read Knife Of Dreams
- Had some fun using the new features on C# 2.0
- Even more fun with static reflection
- Wrote my first trigger - I wrote a lot more SQL since then
- Fought against VS.Net, lost
- Didn't have fun with ASP.Net & View State
- Ranting on ASP.Net
- Still losing to ASP.Net
- Got loads more RAM
- Talked a bit about my project
- Was at the launch
- Released a project with some functionality that I'm always using
- Started to really dig SQL
- Verified mutex correctness using mocks
- Got older
I also posted 822 posts this year, which average to ~70 posts a month, Wow!
Looking back at the last year, so much has happened that I didn't write about in the blog. Part of it is classified, part of it is personal, but it was good year.
"There is no such thing as an atheist in a foxhole." -- Army Sergant
"Hospital: Where they wake you up to give you a sleeping pill." -- Definate Facts
"Diagnostics are the programs that run when nothing else will." -- Tech Support Slogan
"Money couldnt buy friends, but you get a better class of enemy." -- Spike Milligan
Nasty Hard drive
I think that I trucked down most of my computer issues. I'm looking into the event log, and I can see tons of "This device has a bad cluster" errors.
Experience has thought me that this usually mean that the HD's death is imminent, so now I need to get a new HD, and move Windows (which I just installed on the bad HD, naturally) to the new one. Any suggestions of how to do this? I want to do this exactly once, so I'm not very willing to buy Ghost or friends.
Stories from a Job Interview: Part 1
In
a job interview I was asked to pull a list of records from a database and save
them to XML. The data was hierarchical in nature, of course. The code I produce
looked a bit like this:
Dictionary<int, XmlNode> connections
= new Dictionary<int, XmlNode>();
XmlDocument xdoc = new XmlDocument();
XmlNode root =
xdoc.CreateRootNode("Names");
using(IDbConnection
con = GetConnection())
{
using(IDbCommand command =
con.CreateCommand())
{
command.CommandText
= "select id, parent id,
name from Foo order by parent id;"
IDataReader
reader = command.ExecuteReader();
while(reader.Read())
{
int
id = reader.GetInt(0);
int
parent = reader.GetInt(1);
string name =
reader.GetString(2);
XmlNode node;
if(parent == 0)
node = root.CreateChild("Name");
else
node = connections[parent].CreateChild("Name");
node.Text =
name;
node.Attributes.Add("id",
id.ToString());
connections.Add(id, node);
}
}
}
xdoc.Save("results.xml");
I
believe that the purpose was to check if I know how to use recursion, but it
never occurred to me to use it in a case like this. The code above uses a
single database query and a single pass on the dictionary. It is, I believe, as
efficient as you can get without really
trying. The funny thing was that the interviewers tried to get me to use recursion (without saying it), but I literally
couldn't understand what they meant until they said it.
What a developer should know
After
reading Joel, and writing my response to that, I started to think about all the
things that a typical developer should know in order to produce a working
application. The list isn't in any particular order, and I'm focusing it the
business / application developer:
- Data
Structures
- Complexity
- Cost of
operations (local vs. remote)
- Designing
usable classes*
- SQL
- XML
- ACID
- Basic
Design Patterns:
- Strategy
- Decorator
- Regular
Expressions
- Data
Modeling
- KISS
- TDD
- Building
DAL
- Change
Management (SCCS)
Anything
to add that you think is essential?
*
Reusable classes are another
matter all together
More on repositories and delegates
I
like delegates, maybe to the point where I use them too much. I talked about my
Repository and that is allowed me to access various sources without caring what
the object is, or what is being done with it. Here is a possible implementation
of a Finder, which is a read only repository. This code also shows a new
pattern that I began to use lately, which is to put delegates in dictionaries,
and then invoke them, I find that this is a very powerful way to specialize
handling of functionality without much effort.
public
class Finder
{
static
IDictionary<Type, Func<object,
Type, int>>
finders;
static Finder()
{
finders = new Dictionary<Type, Func<object, int>>(new IsInstanceOfEqualizer());
finders.Add(typeof(ActiveRecordBase), delegate(Type type, int id)
{
//Get item from the database
return
ActiveRecordBase.FindByPrimaryKey(type, id);
});
finders.Add(typeof(Employee),
delegate(Type type, int id)
{
//Get the user from Active Directory and
wrap it in an employee instance
return new
Employee(ActiveDirectoryWrapper.GetUserWithId(id));
});
finders.Add(typeof(Enum),
delegate(Type type, int id)
{
//would be converted to the enum value by
Find
return id;
});
}
public T Find(int id)
{
return (T)finders[typeof(T)](typeof(T), id);
}
}
In
the case, either the object knows how to save itself (Active Record), or it
doesn't need to be saved, so I didn't need to implement a full blown repository
(in which case I would've written an interface an each of those would be a
class implementing the interface). In my real project, I ended up with the
repository-as-a-generic-interface approach, but the one above is a very real
possibility for all those that use a real
Active Record model (I needed more, so I modified it quite a bit).
Why
is this good for? Well, consider other
generic code, which can use this Finder object without needing to know what it
does (think about security, logging, simple UI, etC).
My Thoughts about Joel On Java
It
seems that Joel's article about Java in the Universities has made quite a bit
of noise. I think that I will add my two cents to the mix.
Two
things pissed me about the article. The first was the claim that CS should weed
the bad from the good, and the second was his treatment for OOP (agonizing over
has-a & is-a is so not OO).
I
completely disagree with the claim that CS* classes should function as
discriminators between good and mediocre programmers. That is his problem, as a potential employer, to
weed out the great from the mediocre. And if he can't do that in about a week,
regardless of technology or project that they use, then the fault is with him,
not with the graduate. Being proud because you were up until 4:00 AM chasing a
null pointer dereference and broken stack is not
the sign of a productive developer. I wrote all the linked lists and
hash tables that I ever intend to write. Hell, I even spent some time writing a
sparse matrix in C++ that was multi dimensional and efficient. I see zero need in them outside of the class
room.
I
will walk out of a job interview
where the test is being able to write a linked list in C or C++. I have done so
before where the questions where at about this level. You want me to deal with
pointers, give me a job that requires
that I will deal with them. That has better not be a bug tracking software in
ASP 3.0 (what Joel sells).
The
second part, about OO design being "spending countless hours rewriting
your code to rejiggle your object hierarchy, or you fret about faux 'problems'
like has-a vs. is-a" is just bull. I'm programming since I was ~14 years
old or so (if you don't count making a turtle dance in Logo), I started in
Pascal & VB 3.0, I later moved to C & C++, and then to C#. The last
time I thought about has-a vs. is-a was when I was learning C++ and was very new to OO. Since then, I didn't touch
this stuff, and I produce good OO code. Most of it is online, and you can check
it out.
Then
there is the whole premise of the article, which seems to be that you need to find
a Segmentation fault [sic] and fix
it in order to be Real Programmer.
Been there, done that, boring. I
consider good design much better
than knowing how to handle naked pointers. You know what, show me a good C++
coder that still go on to do
that, when all the best practices for C++ are full of RAII and safe pointer
wrappers.
Now,
that said, he does have some points that I agree with. Recursion is a good,
clean, way to solve a certain set of problems, and understanding pointers is
very helpful in understanding how computers think. And understanding functional
programming is very good for being able to write clean code later on.
* I'm
currently studying for a CS degree (just started), but I know about 85% of what
the degree will teach me because I wanted to learn and a university wasn't a
possibility at the time. I've a job, which I like, and I got it because I like
what I'm doing, not because I had a degree or a certification.
Lot more SQL Fun
While I need to read some ugly code,
I think that I'm learning SQL in leaps and bounds. Right now I gave a shot to
the OUTPUT clause in 2005, and it is just great.
All Hail The Unit Test
Just listen to this song, it may be not the
greatest musical in the history of mankind, but it is very funny nonetheless.
What I want to see next...
Brad Abrams talks
about a new method in the CLR [ ReadAllLines() ], and the comments list
several useful stuff and some wishes.
My wish for the new year is to be
able to declaratively set a dictionary. What do I mean by that?
int[] values = { 1, 2, 3, 4,
5, 6 };
But just try to do that for
dictionaries:
Dictionary<string, int>
values = CreateDictionary();
private
static Dictionary<string, int>
CreateDictionary()
{
Dictionary<string,
int> values = new
Dictionary<string,
int>();
values.Add("one", 1);
values.Add("two", 2);
return values;
}
And this is the best thing that I
could come up with! Other languages has initializers for dictionaries. This is
something that I use constantly (very easy to setup a relationship between
behaviors, for instance), and it's annoying me every time.
Silly Answers, Silly Buggers
I just saw this,
and I nearly ruined a perfectly good keyboard. Those answers are so… stupid.
But I fully believe that actual people answered them in response to actual
questions in interviews. I distinctly remember walking out of an interview
knowing that I'm not willing to work for those guys, based on the questions
that they asked me. (My philosophy is that I want the interview to be hard,
I want to make sure that I work with people who know more than I do, and I want
to be sure that I'll need effort to keep up with them.)
In the spirit of Groucho Marx: "I
wouldn't want to belong to any club that would accept me as a member.", I
wouldn't want to work in a place where the work is too easy or the standards
are too lax. What is the point, then?
Movie Review: The Lion, The Witch and the Wardrobe
This is, without a single doubt, the
best movie rendition that I've ever seen for any book. I'm
talking about near 1:1 similarities between them. After being disappointed by the
cut scenes in Harry Potter #4, this movie just made my day. I recognized everything,
and I couldn't find a missing piece in the story. Everything was there, and the
changes that were made were very small and reasonable (a living fly instead of
a living one, Lucy falling asleep, Edward betraying the goat-man (sorry, I've no
idea how he is spelled in English), etc).
Excellent!
The battle scene is simply
wonderful, at the same level or better than any of the LotR scenes.
Best quote in the MSFT vs. GOOG fight
I got to hand it to Scoble,
this quote is the best one I've seen so far in the Microsoft vs. Google fight:
Do you count your 20% time out of an
ordinary 40-hour-workweek? Or out of your 80-hour superweek?
It's hard to stop me from talking...
Or so I have been told.
So, while I'm installing all the
highly essential applications and configure Windows properly (running Windows
Update now, which takes a while), I might as well spend some time talking about
other stuff. My computer is down since Sunday, but only now I could get the
time to do something about it. So, I'm having a wonderful time catching
up on my feeds, I've ~400 messages to read, which is a bummer. I managed to
keep up with my personal email, but not with the stuff that reached Gmail, so
I'll have to look into that later. Oh, and 50 of those posts are Scoble's.
Spooky.
Can someone please tell me
why I have to reboot in order to install Windows Update?
I'll probably not finish it today, I
now downloads the service pack, which would take forever and then a little bit
more. That would teach me to install from an original CD.
Something to fill the silence
So, I've been quite in the last
couple of days since I work where I don't have internet connection that I can
easily use, and my home computer finally decided to kiss the pavement and
dropped dead.
I'm pretty sure that the problem is
that I used a SATA HD for this, since most of the problems with it started
then. Seems to me that my BIOS is a bit freakish about SATA HD as a boot
device, and the Windows installer needed a bloody floppy drive before it would
recognize it.
I tried to fix it using the recovery
console, but I couldn't fix it in five minutes, which mean that I could probably
fix it in five hours, but that would take a lot more effort than I need. I'm
currently installing Windows on an IDE drive, so hopefully I'll be able to
restore most of my stuff quickly. Of the three applications that I use the
most, Outlook & RSS Bandit can easily be set to their previous state, and
my VS.Net installation isn't customized to any significant degree.
My sole worry is that I would have a
hard time porting my SpamBayes settings, but that should be easy enough, considering
that it is just flat files.
SqlClr and anonymous delegates
Okay, I'm playing around with SqlClr (doing runtime DDL stuff, mainly), and I discovered that SqlClr and anonymous delegates don't play along very well. The issue is that code like this:
CallWithAction(delegate(DateTime dt) { return dt; } );Is actually translated to something like this:
if(ClassName.<> HiddenFieldName == null)
ClassName.<> HiddenFieldName = new SomeDelegate(HiddenMethodName);
CallWithAction(ClassName.<> HiddenFieldName);
And that causes problem with the SqlClr, since the method is trying to store into a static field, which doesn't seem to be allowed on the safe level (which I really don't want to pass.)
It doesn't happen if the anonymous method uses local variables, since then the compiler generate a completely new class. Just a little gotcha that I would've never solved without Reflector.
Reflection & Locale
Seems like I made a mistake in the previous post. The problem with the Turkish I wasn't supposed to be solved on the Reflection API level, but earlier than that. The issue seem to be the string transformation done on a property name (for instance, if I want NHibernate to use the field and not the name) rahter than what I pass to GetField() and deriatives) where NHibernate didn't took into account that lowering the case of a character may result in a different letter on other locales. The issue was already fixed on NHibernate CVS, and I'm feeling stupid for crying wolf.
GetField & Turkish Locale
I've just got an email about an interesting problem with NHibernate. After searching for a little while, I came up with the conclution that the problem is in the framework, and I can't see an easy solution for it.
First, let's start by explaining Turkish locale & its unique interpretation of the humble i letter. This MSDN article does it best, so I'll let them do the job:
(\u0130), which is the capital version of i. Similarly, in Turkish, there is a lowercase "i without a dot," or
(\u0131), which capitalizes to I. This behavior occurs in the Azeri culture ("az") as well. How does it has anything to do with NHibernate? Well, consider this code:
This code will fail to return anything if the locale is set to Turkish. And the problem is worse because there doesn't seem to be a way to pass an InvariantCulture or Ordinal to the GetField method. The only solution that I can see now if to get all the fields on the method and iterate over them one by one, making a culture insensitive comparision.
Please tell me that I'm missing something, since this seems to indicate that any Reflection code will likely break if you're using the Turkish locale.
Oh, and that is the behavior for both .Net 1.0 & .Net 2.0
Picking a database... and staying with it.
I just read this post from an ex-googler, talking about how they tried to move from MySQL to another (presumbely Enterprise. Most likely DB2 or Oracle), and failed. I'll gloss over the fact that they implement such a critical system over a database with no trasaction support (and the comments about "it is easy to add on the application level" that made me cringe so hard that for a moment I looked like a fat bagel).
I want to talk about migrating a single application from one database to another. This is not something that you see done often when you're talking about Line of Business application. Especially not in-house one. But, and this is important, it's both possible and straight-forward in most cases if (and only if) you know something about layering and seperated the database from the rest of your application properly.
If my recent ActiveRecord & NHibernate would ever need to support anything beyond SQL Server, here are the list of steps that I would need to do:
- Create an equivalent schema for the other database (most probably automatically via some tool).
- Research on how the connection string looks like and put it in the config file.
- Re-write a single trigger, which is done in T-SQL for efficently.
- Run the tests against the new database.
Total time that this should take is two days, and I'm including in that the time that it will take me to install the database (even if it's an Oracle) and then learn its SQL deriative.
Now, that is not to say that I might get into places where the application relies on some SQL spesific behavior (identity columns, for instance), or something similar, but those should be isolated incidents. The application itself should move without anything major happening. You know, if I didn't have NHibernate, I would have had to re-write all the queries from scratch, and that might have added a week or so if I had really complex queries (I honestly don't know, NHibernate handles it all). But the application would still not know that anything had happened. The one caveat that may happen is if I needed to port it to something like MySQL 4.0, which doesn't support Transactions, Nested Queries, etc.
This is ABC in application design. The inability to move from one database to the other means that your application relies on way too much on database spesific stuff. There may be reasons for this, but I think that saying something like: "You get what you pay for, and with free you get much more..." is bullshit.
NHibernate Generics & EntityList - Update
Okay, the code is in the Subversion repository, but I'm not ready to release it yet. I've a shameful confession to make first:
I never used an IList with NHibernate (or ActiveRecord) before, so I'm not really sure whatever my code makes good sense or not. And, in addition to that, I haven't had the time to test it propertly. I would appriciate it if someone who had used it before could take it for a spin and tell me what they think the bad points are.
ReSharper & VS.Net: Kaboom
I'm running ReSharper #213, and it's aweful. Exceptions are all over the place. The problem is that it is so feature packed that I have a hard time living without it. I just had an instance where doing a refactoring on R# caused the entire IDE to vanish.
It's the hardware fault, honest!
As a software developer, I tend to assume that any excuse that blame the harder is an excuse. But I just got two stories that are completely related to hardware to disprove myself.
A few weeks ago I shoved another 1GB RAM into my computer, and all was well, until I started to get random application failures and a BSOD from Windows. Completely random, completely unexpected. And that is after running seemlessly for over three years without really noticing that th OS existed. Turned out that I needed to play with the positioning of the RAM sticks on my board, and now it seems to be working.
The other thing just happened, I was having bad connectivity issues since just about forever, and today the technician found what the problem was, the connecting wires led to a concret bore, which was full of water... You can imagine what happened next.
Song search
This post is for the readers from Israel, I just listened to a great song in the radio, but I didn't catch its name, and I can only remember two lines:
את כותבת שורות קצרות,
אני כותב לך מגילות
I heard it on Galgalatz, and I would like the name of the song and the singers.
String Comparison Performance
During the Tel Aviv Launch I had an argument with Justin about the performance of string comparisons. The issue was whatever it is good to use str == "" or str.Length == 0, and the meriths of string.IsNullOrEmpty(str) in .Net 2.0.
Since Stefano just posted a comparison in VB.Net, I thought I would make the same check on C# (since VB.Net uses a compatability layer for string comparison). I merely ported Stefano's code:
DateTime start = DateTime.Now;
string str = "";
for (int i = 0; i < 1000000000; i++)
{
if(str == "")
// if (str.Length == 0)
// if (str == string.Empty)
// if (string.IsNullOrEmpty(str))
{
;
}
}
TimeSpan elapsed = DateTime.Now - start;
Console.WriteLine(elapsed.TotalMilliseconds);
The results?
str == "": 11671.875
str.Length == 0: 3984.375
str == string.Empty: 22265.625
string.IsNullOrEmpty(str): 9703.125
I'm not sure what is the reason for the big different between comparing to "" and comparing the string.Empty. An interesting experiment that I did gave the following result:
object
.ReferenceEquals("", str) is trueobject
.ReferenceEquals(string.Empty, str) is falseNo idea what this means, though.
From my point of view, if a billion iterations are needed to even see the changes, it doesn't matter which you choose anyway. Just to give you a hint, a call to str=="" will cost you 0.00001 milli-seconds. You'll need to find a physicist to tell you how to call this amount of time, and even then, he will look at you strangely ever after.
More on .Old
While discussing the afore-mentioned "system" of keeping track of changes with a friend, she mentioned (she used to deal with intrusion detection for web apps) that she broke several system by systematically trying "Page.aspx.old", "Page.aspx.tmp", "Page2.aspx", etc for all the pages in the application. The booty was usually the page source, and in most cases, that came along with the full (unencrypted, naturally) connection string, including the "sa" password.
What was your experiance?
.Old, .Tmp, .Bak - The Source Control From Hell
Imagine the following file listing:
do_stuff.old do_stuff.tmp do_stff.sh1
do_stuff.bak do_stuff.sh.jhon so_dtuff.sh
do_stuff.sh.2 do_stuff.sh tmp_dostuff.sh
do_stuff2.sh do_stuff2.new
do_stuff3.old do_stuff2.newer
do_stuff2.sql do_stuffie.sql.old
do_stuff.sql do_stuff.sql.dont-run
Quick, which file is the correct one? Now multiply that by ten, then add at least three different types of scripts, a truly random directory structure, file names that were written by someone with only half a keyboard and that was taxed per letter, and you may see what I did today. Oh, and just for kicks, spread the responsibilities randomly between shell scripts, sql scripts and stored procedures.
Did I mention a case senstivie file system yet?