My friend Rich just posted on his blog about 4 openings. At my company (McKesson Automation), we have a bunch of openings that we are having a hell of a time trying to fill. I wouldn't say its the Roaring 90's again, but it seems to be a pretty good time to be a developer in Pittsburgh.
If you work with Microsoft technology, as a developer, QA, or sysadmin, contact me if you want to know more...
One of my fellow developers is making the transition from VB6/ASP/COM+, and moving into the .Net world (he's be chained to a product that hadn't been scheduled for upgrade, but now it finally is). He's been asking some good questions. Here's one I'd like to share…
Question:
Are there any string truncation methods in C# that remove a number of characters or substring from the end of a string? I've been playing with TrimEnd and it seems to ignore anything I try. My purpose is that I have built a string dynamically (SQL statement) in a loop and I need to remove the last "UNION ALL" keyword I add.
Answer:
The biggest problem is that the string functions in .Net to do not replace the string you are working on – instead they return the resulting string. This is behavior is more flexible, but entirely different from the way things used to work in VB6, thus leading to confusion. Here is a snippet that will do what you are looking for:
string crap =
"SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL";
crap = crap.Remove(crap.LastIndexOf("UNION ALL"));
Another thing, though, if you are building a really big string, you might want to consider using the StringBuilder class. The way I'd get around the extra UNION ALL is to not write it in the first place – create a bool, check to see if it's true in your loop, and if it is, write the UNION ALL before the rest of the stuff you were going to write in the loop. Then, if it isn't true, set it true, so that the next time through you'll get the proper UNION ALL written:
string[] selects = {"select 1", "select 2", "select 3"};
StringBuilder builder = new StringBuilder();
for(int i=0; i<selects.Length; i++)
{
if (builder.Length > 0)
{
builder.Append(" UNION ALL ");
}
builder.Append(selects[i]);
}
Console.WriteLine(builder);
Actually, I cheated on the bool – I just used the fact that the StringBuilder would be empty. But it's basically the same thing…
Sure, the documentation leads you to believe you can use them. The mapping files even support it. But once you try and add a new item to a collection of objects that has a composite key, it breaks down. It doesn't give you an error - it politely lets you think the collection saved. But go check the database - the records aren't there.
I took a quick look in the code (not enough to say with any certainty I can even spell NHibernate correctly, mind you), and I can't see any way for NHibernate to know that the objects in the collection aren't saved. I did read in the help file that you can use an Interceptor to figure it out, but that seems to be a lot of pain for little gain. So, while reading in the collection works, and I assume updates would, inserting just ain't happening. Fortunately, I was able to convince our DBA to change the tables, but not until I lost most of the day trying to figure out how to make it work.
If anybody knows a solution, I'd love to hear it. Otherwise, let me stand as a warning to you. Hopefully the time you save will be your own.
My friend Rich Dudley asked via a comment on my last post for some advice on database version control...
Well, I don't really have any good advice for database source control - our former head DBA swears by VSS, and the remaining ones haven't had time to come up for air an re-evaluate. (What does that tell you about our former DBA?)
However, after thinking about it a little, here's what I'd probably try:
Have each table in its own script, create a build that executes each one in sequence, and keep them versioned that way, and you can do the same for views and stored procedures (hopefully you have no triggers :)). You probably need to define a convention as to which side you'd keep the foreign keys, to avoid conflicts. I'd recommend on the "parent" table - that way you can easily find out what tables depend upon it.
As far as that build part goes, if you don't have one already, I know there are NAnt tasks you could use, and there is probably an MSBuild task or two (if not, its really easy to create one). The pain part is keeping track of the dependencies. Seems like a task that is screaming for a quick and dirty tool. :)
Anyone else have any advice to add, or see any obvious holes in my suggestions?
I have spent my whole career wearing multiple hats, probably mostly because of ADD or something. I do tend to get bored if I'm not doing a wide variety of things, no matter what the reason. I've been lead developer, technical support, network engineer, database administrator, product manager, business analyst, build manager, installation developer, and probably other roles. I'm not saying this for the ego stroking, but to point out that there are real world examples of generalizing specialists, and I firmly agree that it is a good thing.
Lately I've been doing a lot of installation, build, and source control work. It fits in well with my other role of leading/mentoring, because it can be interrupted fairly easily (unlike, say, trying to figure out the subleties of fixing some problems with getting NHibernate and our crappy legacy data model to play together nicely, which is the work I probably should be doing - fortunately, there are some very talented people on the team dealing with that problem (although I do get sucked in to that, too) so I can focus on helping everyone else). Since I've been reading and exploring agile development, I've come across a lot of very good resources, which I either have shared or plan to share via this blog. We've finally hit the point where the rubber hits the road - our team has embarked on using Scrum (not very well at the moment - I thought you could just implement it little by little, and while its helping keep things on track than the chaos we used to have, it isn't giving us the full benefit it could - we're working now to correct that...). Anyway, enough mental masturbation context setting...
One really awesome resource for Scrum, beyond the usual suspects, is Henrik Kniberg. His latest article on agile version control is exceptional. I had been contemplating branching for every story, and merging the story branch back into the trunk, in order to keep the trunk releasable. It aligns with one version control practice I have read about of a branch per feature, but a story is finer grained than that definition of feature, so trying to maintain that would have been a nightmare. Henrik's method is to have a branch for each Scrum team, and then merging finished stories into the trunk, which seems like MUCH less trouble. The one complication is trying to figure out what files should be merged into the trunk. I think we can accomplish this by using StarTeam Change Requests to manage what check-ins belong to each story, and migrating change requests up to the trunk.
One other thing that will make this us do is ensure that stories are independent, and our code is properly broken into classes with a single responsibility each. Otherwise, this will still be hard to manage. But that "pain" will decrease over time, as we get better at writing GOOD user stories and GOOD object-oriented code.
I propose a constitutional admendment, to the Grand Developer's Code of Conduct:
The use Foo, Bar, and any other derivation of the ancient WWII term FUBAR is hereby prohibited from all demostrations, presentations, demo code, conversations, thoughts, and other emanations issued forth from a developer. A "Developer", in this context, is anyone who enages in any activity that results in the possibility of computer code being produced.
That joke isn't funny anymore. Its annoying and immature. What's wrong with using X, Y, and Z as sample variables? Or pet's names? Or anything else? Why not a little originality for a change? Scott Hanselman - I'm looking at you!
I just took a 2-day Certified Scrum Master class from Innovel taught by Mark Pushinsky. I guess that makes me a certified Scrum Master, although I have to say it was the least rigorous certification I've obtained to date - all you had to do was attend class and participate.
We have been dabbling in Scrum for my current project, through my decision to utilize a Scrum-like approach, and with my boss's support (he has been pushing for iterative development since before I got there, so he's happy to let me guinea pig it). Now that we've been playing with it, and because the training class was available in Pittsburgh (no travel costs!), it seemed like a good time to move beyond learning from the books and web sites, and pretending, and get some actual training on the topic. I have to say, having sat through a lot of crummy training, and some good training, and having taught some classes myself (I used to be an MCT back in the VB 6-SQL 7.0 days), that Mark is a very good instructor, and I found the training to be valuable. At no point did I find my eyelids sinking.
Seriously, though, it was good to have been through the training. I found some things that we aren't doing that we should be doing, and some things that we are doing wrong. The one key take-away: if you are going to try out Scrum, even if you don't bother getting training (and you probably can fake it well enough just by following along with a book or web site (reviews of some of the resources I've used will be coming soon), you really should pick a project, and do ALL of Scrum. Not just a few things to get you going. Not everything but the 2 things you don't like. All of it. And then evaluate from there. Mark gave this advice, and having not done that on the project, I can definitely see how what we are doing isn't going to give us the same value as if we had done it right.
Just read a short article in Fast Company about "Heroic Checklists". Seems they aren't just for burger flippers anymore (which of course you knew). As a lead developer, I find myself mentoring and coaching more and more, and I can really see the value in providing checklists as a way to quickly help someone grasp the basics. Here are some checklists I'm planning to push out to my team (and use myself):
Check-In
- Check out anything that has changed
- Run the build on your machine
- Fix any problems
- Check-In your code
- Check CruiseControl every couple minutes until the build runs successfully
If you break the build, fix it
Is It Done?
- Resharper flags no issues
- Double-check Coding Standards followed
- Unit tests written and pass, and cover 50-80% of all non-UI code
Able to demo to anyone, even on someone else's machine
Any other checklist suggestions?
You're adding a new event to you class, and it needs to pass some data contained in an object. You need to create a class that derives from EventArgs to pass that data, right? It isn't always so cut and dried.
Generally, adding an EventArgs class is overkill. It's another class to maintain, which means another file to deal with, and another set of tests to possibly create (although very minor - so minor most people won't write them). It violates the Third Law of Software Development: "A developer must reduce their code to the smallest size possible", since there is a way you can write less code - use a delegate.
If you need to pass a lot of different objects to the event (which is probably a sign of a different problem), then by all means, create a new EventArgs class - it will probably be easier to maintain. But if you are only passing one or two objects, why not just use a delegate instead?
Here's a ridiculously contrived sample to show you how this works. Create a Windows Forms C# project, and add a TextBox and a Timer, and away we go:
using System;
using System.Windows.Forms;
namespace EventDelegateSample
{
public delegate void SomethingHappenedHandler(object sender,
EventDataStuff stuff);
public class SuperController
{
public event SomethingHappenedHandler SomethingHappened;
public void FireEvent(string data)
{
if (SomethingHappened != null)
{
SomethingHappened(this,
new EventDataStuff(data));
}
}
}
public partial class DemoForm : Form
{
private SuperController _Controller;
private Random _RandomNumberGenerator;
public DemoForm()
{
InitializeComponent();
_Controller = new SuperController();
_Controller.SomethingHappened += Controller_SomethingHappened;
_RandomNumberGenerator = new Random();
}
private void Controller_SomethingHappened(object sender,
EventDataStuff stuff)
{
textBox1.Text += string.Format("From:{0} -> {1}\r\n",
sender.GetType().FullName,
stuff.Stuff);
}
private void timer1_Tick(object sender,
EventArgs e)
{
_Controller.FireEvent(_RandomNumberGenerator.Next().ToString());
}
}
public class EventDataStuff
{
private string _Stuff;
public EventDataStuff(string stuff)
{
_Stuff = stuff;
}
public string Stuff
{
get { return _Stuff; }
set { _Stuff = value; }
}
}
}
|