Saturday, June 29, 2013

I find myself overriding ToString() a lot...

I've noticed that I like to override the ToString() method very often. For me this very normal to do, but I don't see my colleagues doing it often.

For me, the benefits are:
- Quicker debugging
- Quick and informative logging

Here's an example I set up. Below i'll put the code of a tiny domain I set up with an invoice and some invoice lines. After overriding the ToString() method, there is a whole bunch of moments where that comes in handy. 

Debugging

Since the ToString() override can be used at any time, it's even more powerfull than the DebuggerDisplayAttribute.

Let's put a breakpoint somewhere in the code, see how I can debug this. There's the System.Diagnostics.Debug.Writeline of course:

See that the invoice information is just there with 1 line of code. Let's look at some more debugging tools we got in VS. There's the immediate window:


And there's the watch:


And some other Quick Watch screens:


Logging

Quickly get all of the relevant information in your log - by just calling ToString()'ing your instance to the log:


You are using Common.Logging right?

Code

It's really easy, here's the code for all of this stuff:


// --------------------------------------------------------------------------------------------------------------------
// 
//   
// 
// 
//   The program.
// 
// --------------------------------------------------------------------------------------------------------------------

namespace ConsoleApplication1
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    /// 
    /// The program.
    /// 
    internal class Program
    {
        #region Methods

        /// 
        /// The generate random invoice.
        /// 
        /// 
        /// The .
        /// 
        private static Invoice GenerateRandomInvoice()
        {
            var random = new Random();

            var invoice = new Invoice(1, DateTime.Now);
            invoice.InvoiceoLines.Add(new InvoiceoLine("Computer", 899.00m));
            invoice.InvoiceoLines.Add(new InvoiceoLine("Printers", 49.99m));
            invoice.InvoiceoLines.Add(new InvoiceoLine("Paper", 12.50m));
            invoice.InvoiceoLines.Add(new InvoiceoLine("Some more computer supplies", 12.50m));
            invoice.InvoiceoLines.Add(new InvoiceoLine("Other stuff", 12.50m));
            int numLines = random.Next(10);
            for (int i = 0; i < numLines; i++)
            {
                invoice.InvoiceoLines.Add(new InvoiceoLine("Product id " + random.Next(100), random.Next(10000) / 100m));
            }

            return invoice;
        }

        /// 
        /// The main.
        /// 
        /// 
        /// The args.
        /// 
        private static void Main(string[] args)
        {
            Invoice invoice = GenerateRandomInvoice();

            Common.Logging.LogManager.GetCurrentClassLogger().Info(invoice);
            Console.ReadLine();
        }

        #endregion
    }

    /// 
    /// The invoice.
    /// 
    internal class Invoice
    {
        #region Constructors and Destructors

        /// 
        /// Initializes a new instance of the  class.
        /// 
        public Invoice()
        {
            this.InvoiceoLines = new List();
        }

        /// 
        /// Initializes a new instance of the  class.
        /// 
        /// 
        /// The id.
        /// 
        /// 
        /// The date.
        /// 
        public Invoice(int id, DateTime date)
            : this()
        {
            this.Date = date;
            this.Id = id;
        }

        #endregion

        #region Public Properties

        /// 
        /// Gets or sets the date.
        /// 
        public DateTime Date { get; set; }

        /// 
        /// Gets or sets the id.
        /// 
        public int Id { get; set; }

        /// 
        /// Gets the invoice total.
        /// 
        public decimal InvoiceTotal
        {
            get
            {
                return this.InvoiceoLines.Aggregate(0, (current, invoiceoLine) => (int)(current + invoiceoLine.Amount));
            }
        }

        /// 
        /// Gets or sets the invoiceo lines.
        /// 
        public ICollection InvoiceoLines { get; set; }

        #endregion

        #region Public Methods and Operators

        /// 
        /// The to string.
        /// 
        /// 
        /// The .
        /// 
        public override string ToString()
        {
            var result = new StringBuilder();
            result.AppendLine(string.Format("Invoice - Id:{0} Date:{1}", this.Id, this.Date.ToShortDateString()));
            result.AppendLine("----------------------------------");
            this.InvoiceoLines.ToList().ForEach(line => result.AppendLine(line.ToString()));
            result.AppendLine("----------------------------------");
            result.AppendLine(string.Format("{0}\t\tUSD {1:0.00}", "Total:".ToLength(15), this.InvoiceTotal));
            return result.ToString();
        }

        #endregion
    }

    /// 
    /// The invoiceo line.
    /// 
    internal class InvoiceoLine
    {
        #region Constructors and Destructors

        /// 
        /// Initializes a new instance of the  class.
        /// 
        /// 
        /// The product.
        /// 
        /// 
        /// The amount.
        /// 
        public InvoiceoLine(string product, decimal amount)
        {
            this.Product = product;
            this.Amount = amount;
        }

        #endregion

        #region Public Properties

        /// 
        /// Gets or sets the amount.
        /// 
        public decimal Amount { get; set; }

        /// 
        /// Gets or sets the product.
        /// 
        public string Product { get; set; }

        #endregion

        #region Public Methods and Operators

        /// 
        /// The to string.
        /// 
        /// 
        /// The .
        /// 
        public override string ToString()
        {
            return string.Format("{0}\t\tUSD {1:0.00}", this.Product.ToLength(15), this.Amount);
        }

        #endregion
    }

    /// 
    /// The string extensions.
    /// 
    public static class StringExtensions
    {
        #region Public Methods and Operators

        /// 
        /// The to length.
        /// 
        /// 
        /// The input.
        /// 
        /// 
        /// The desired length.
        /// 
        /// 
        /// The .
        /// 
        public static string ToLength(this string input, int desiredLength)
        {
            if (string.IsNullOrEmpty(input) || input.Length < desiredLength)
            {
                string result = string.Empty + input;
                var postfix = new string(' ', desiredLength - result.Length);
                return result + postfix;
            }

            return input.Substring(0, desiredLength - 3) + "...";
        }

        #endregion
    }
}

Saturday, June 15, 2013

Nice... Running TFS 2012 on my home server

At the office we're using TFS 2012 and I'm starting to like it. Coming from TeamCityJIRA with GreenHopper and Subversion Edge, it took me a little time getting used to it. Since our office upgraded to TFS 2012 some colleagues came up to me with stories like 'did you know that in tfs2012 you can do so and so ...' and in my mind I thought 'so ... you're saying it wasn't available before?'. In a lot of ways TFS still has a long way to go and I'm sceptical it will ever reach the JIRA or GreenHopper level, but it is a pretty decent tool that I'm delighted to work with.

Burndowns, issue drag&dropping, those are some examples of stories everyone's excited about, that I had been using for more than 2 years in JIRA.

Anyway - I've got it running on my HP DL380 now:
Administrative tasks for the TFS environment are done using the TFS Administrative application on the server itself:


But most of the other stuff can be administrated using the web-interface:



So, I'm all set now to get started!





What people are googling ... right now

Saturday, June 8, 2013

Tip: Don't use LogManager.GetCurrentClassLogger() when using interception

So this cost me an hour. I had some code that ran perfectly under unit tests. However, in the live application ( that uses Unity with Interception ), I had NullReferenceExceptions when instantiating some of the classes when calling the logger. Turns out, when using interception, it's not a good idea to GetCurrentClassLogger(). That will cause your code to break. Use GetLogger() instead.

Thursday, June 6, 2013

Interview Series: "What is a Windows Service and how does its lifecycle differ from a "standard" EXE?"

I came across a post on Scott Hanselman's website titled 'What Great .NET Developers Ought To Know (More .NET Interview Questions)' and the list of questions really caught my interest. So, I've decided to try and answer all of the questions. I'll probably have to look up a bunch, and some of the questions aren't really applicable to my field of work, but still - I'm expecting to learn quite a bit.


"What is a Windows Service and how does its lifecycle differ from a "standard" EXE?"

A windows service is a program that runs in the background, whereas a program runs mostly in the foreground. Again - go over to WikiPedia for more details. There are other differences as well: the way you start it, the way you install it etc.
Both can be created using Visual Studio 'file > new project' and there's not a whole lot to it. And - addressing the lifecycle part of the question: a service normally runs when windows starts and stop when windows shuts down. The application lifecycle however is normally controlled by the user, that can either start or stop it at will.

So when to opt for a service and not for an application? Well, when you need just that kind of behavior as described above. Something that always runs on the background and needs little or no user input. 

For example: I was working on a bookkeeping application in my former job. We needed to send out tax declarations to the authorities. We found a really cheap application that did just that - read from a pick-up folder and send it to the tax authorities. So - we decided to write a service that queried the database for declarations flagged to be sent out, every n minutes, and copy them to the pick-up location of the application.
This service started immediately when the machine booted, so it continued as the machine came back up.

Since the service was important however - we did ask our full service hosting provider to monitor the service state using nagios. As soon as that service went down, we would get a phone call. If the service is important to you - consider having that done!

Monday, June 3, 2013

Interview Series: "Describe the difference between a Thread and a Process?"

I came across a post on Scott Hanselman's website titled 'What Great .NET Developers Ought To Know (More .NET Interview Questions)' and the list of questions really caught my interest. So, I've decided to try and answer all of the questions. I'll probably have to look up a bunch, and some of the questions aren't really applicable to my field of work, but still - I'm expecting to learn quite a bit.


"Describe the difference between a Thread and a Process?"

A process is an instance of an application, which can run n-threads (depending on the OS). A thread being 'smallest sequence of programmed instructions that can be managed independently by an operating system scheduler'. For more detailed information, use the links below or use Google.

In terms of .NET namespaces, the processes are inside System.Diagnostics whereas the threading stuff is under System.Threading. I never really got why process is inside the diagnostics namespace, so If you know - place a comment.

A lot has changed in the .NET framework related to threading quite recently. In .NET 4 - the 'task' keyword was introduced and in 4.5 the 'async' and 'await' keywords were added to that. This is of course because processors are getting more and more cores. A nice video for getting up to speed with task/async/await is this one on YouTube:


One of the interesting points made in the video is that async does not mean multi-threaded. That was in eye-opener to me. What he also points out that if you have 8 cores and don't use multiple-threads, you're only using an eigth of the processor capacity at most.

Links:
WikiPedia
ProgrammerInterview.com