Software Is Hardwork

ISimplicityAffinative: The endless pursuit of anti-complexity.
The technology-centric blog of D. P. Bullington.

Email D. P. Bullington View D. P. Bullington\ Get Software Is Hardwork code on CodePlex

Blog Post(s)

Opinion: The Mind of an Elite Software Engineer
Friday, July 31, 2009

I have found myself many times involved in the debate over what it takes to be an elite software engineer. Some argue it is the education, others argue it is the experience, yet other argue it is <insert whatever>.

I firmly believe that with all other things being equal, an elite software engineer possess two distinct mental qualities: abstractions over concretions and relativeness over absoluteness. So, regardless of whether a person has a CS/CIMS/whatever degree and/or decades of experience, the ability to see abstractions and think relative is a key to solving complex problems using hardware and software. In essence, the brain must be wired for this type of reasoning. I also believe that someone who is wired this way that pursues an applicable education such as mathematics, computer science, or engineering will be better positioned to ascend to eliteness versus someone without the brain wiring due to the relationship between the mental ability and the academic material. This also implies that one can be elite without a formal education if they can think in the manner needed to excel in the field.

Charlottesville .NET User Group: Debugging on the Windows Platform (including .NET Framework 4.0)
Saturday, July 25, 2009

I presented "Debugging on the Windows Platform (including .NET Framework 4.0)" at the Charlottesville .NET User Group this past Thursday. It went quite well and I had a nice number of attendees to the talk. Good questions and even an encore demo as well!

The PDF conversion of the slide deck can be had here:
Debugging on the Windows Platform (including .NET Framework 4.0).pdf

The sample application demonstrated during the talk can be had here:
WinDBG Memory Leak Demo.zip
(Be sure to open in Visual Studio 2010, convert solution, and set to .NET 4.0 framework target.)

MP3 podcast:
Debugging on the Windows Platform (including .NET Framework 4.0) (ChoDNUG 2009-07-23).mp3

Thanks to all those who organized the affair and to all those who attended my talk.

Thoughts on Scrum + PMP Hybrid Projects
Wednesday, July 22, 2009

I have been an advocate for and successfully implemented Scrum in various local organizations from private companies, county government to state agencies. I find that resistance is normal and you have to have management buy-in or you can easily find yourself in a quagmire. I am also a firm believer in adhering to the Ken Schwaber pure Scrum; deviations or tweaking usually indicates a preexisting pain point in the organization which MUST be corrected (i.e. do not bend the process framework to hide the pain point rather eliminate the pain point).

I have also been successful in blending Scrum and PMP. Scrum and PMP does not have to be mutually exclusive. I recommend the following Scrum + PMP balance. Day to day engineering/development activities are managed using Scrum whereas the overall project and strategic vision is managed in PMP-land. This serves to provide the correct level of abstraction in the management chain. A PMP project manager should not worry about the minor details in the trenches; rather, they care about aggregate numbers for the project plan. If your project plan has hundreds of lines, then you probably have the wrong level of detail. Scum in the trenches also allows for the team to focus on continuously refined estimated time to completion rather than relying on and committing to exhausting and inaccurate project plan estimates created in a vacuum on high.

Software Is Hardwork Library 1.4.1.22921 Released
Tuesday, July 14, 2009

I just released a new version of the Software Is Hardwork Library. This release contains many major and minor changes. Major highlights include:

  • Core
    • Removed Fact`1, IPersistenceObjectFactory, PersistenceObjectFactory, Rule`1, RuleMethodAttribute, and Violation`1, Widgets\*
          AsmInfo, CommandLineException, CommandLineParameter, (I)ListItem et. al, Pager, ProgramBase, Tokenizer from Core.
    • Added XmlFilePersistenceObject`1.cs to Core.
    • Refactored remaining Core\Utility classes to be interface-based.
    • TransparentProxyFactory`1 renamed to ProxyFactory`1; no more remoting specific code.
    • Move InvokeOnObject and InvokeOnDisposable to new abstract class ClientDynamicInvoker in Core.
    • Added DependencyManager and supporting types for a simple dependency injection solution.
  • Database
    • Rename IDatabase to ITableDatabase.
    • Rename IDatabaseEx to IObjectDatabase.
    • DynamicDatabaseClient now inherits ClientDynamicInvoker instead of implementing IInvokeDynamic.
    • IObjectDatabase methods returning IEnumerable`1 now returns IList`1.
    • Removed GenericConnectionFactory`1 in favor of TypeConnectionFactory.GetFor<TConnection>().
    • Moved IConnectionDatabaseFactory and AdoNetConnectionDatabaseFactory to AdoNetImpl namespace.
  • SerivceModelClient
    • DynamicServiceClient now inherits ClientDynamicInvoker instead of implementing IInvokeDynamic.
  • Testing Extensions
    • Add CoverageExclusionAttribute to TestingExtensions.
  • All
    • Custom built NMock2 library for debugging symbol/source support.
    • Updated Resharper 4.5 code style.
    • Changed file names with backtick to tilde to circumvent VS.NET debugger bug.
    • All classes with major depenencies use DependencyManager.
    • Removed src_exp directory and all contents.

This release encompasses quite a lot of work and I am proud to bring it to the developer community. I plan on enhancing this library as time progresses.

NOTE: At this point, I consider many APIs to be feature complete. Due to time constraints, I reserve the right to significantly reduce the API size and scope to fit my interests moving forward. If an API is missing in one release, always feel free to revert to the last release and/or create your own custom release as the sum of the releases. This is the glory of open source!

The Right Way to Impersonate Credentials in .NET
Monday, July 6, 2009

I recently discussed the wrong way to impersonate credentials in .NET. All of the code examples I have encountered have introduced a fatal design flaw: restoring an impersonated principal when impersonating yet another principal as in ASP.NET with impersonate=true. The following illustrates correct code based on my current understanding.

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Principal;

namespace SoftwareIsHardwork.Samples
{
    public class ImpersonationScope : IDisposable
    {
        #region Constructors/Destructors

        public ImpersonationScope(string userName, string domainName, string password, LogonType logonType, LogonProvider logonProvider)
        {
            IntPtr logonToken = IntPtr.Zero;
            IntPtr logonTokenDuplicate = IntPtr.Zero;

            Debug.WriteLine("Enter impersonation scope");

            if ((object)userName == null)
                throw new ArgumentNullException("userName");

            if ((object)domainName == null)
                throw new ArgumentNullException("domainName");

            if ((object)password == null)
                throw new ArgumentNullException("password");

            if (userName == "")
                throw new ArgumentOutOfRangeException("userName");

            if (domainName == "")
                throw new ArgumentOutOfRangeException("domainName");

            if (password == "")
                throw new ArgumentOutOfRangeException("password");

            try
            {
                Debug.WriteLine("Incoming identity: " + WindowsIdentity.GetCurrent().Name);

                this.processWindowsImpersonationContext = WindowsIdentity.Impersonate(IntPtr.Zero);

                Debug.WriteLine("Process-impersonated identity: " + WindowsIdentity.GetCurrent().Name);

                //if (Win32NativeMethods.RevertToSelf())
                {
                    if (LogonUser(userName,
                                  domainName,
                                  password,
                                  (int)logonType,
                                  (int)logonProvider,
                                  ref logonToken) != 0)
                    {
                        if (DuplicateToken(logonToken, (int)ImpersonationLevel.SecurityImpersonation, ref logonTokenDuplicate) != 0)
                        {
                            this.impersonatedWindowsIdentity = new WindowsIdentity(logonTokenDuplicate);
                            this.threadWindowsImpersonationContext = this.impersonatedWindowsIdentity.Impersonate();

                            Debug.WriteLine("Thread-impersonated identity: " + WindowsIdentity.GetCurrent().Name);
                        }
                        else
                            throw new Win32Exception(Marshal.GetLastWin32Error());
                    }
                    else
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                }
            }
            catch
            {
                this.Dispose();
                throw;
            }
            finally
            {
                if (logonToken != IntPtr.Zero)
                {
                    CloseHandle(logonToken);
                    logonToken = IntPtr.Zero;
                }

                if (logonTokenDuplicate != IntPtr.Zero)
                {
                    CloseHandle(logonTokenDuplicate);
                    logonTokenDuplicate = IntPtr.Zero;
                }

                Debug.WriteLine("Leave constructor");
            }
        }

        #endregion

        #region Fields/Constants

        private readonly WindowsIdentity impersonatedWindowsIdentity;
        private readonly WindowsImpersonationContext processWindowsImpersonationContext;
        private readonly WindowsImpersonationContext threadWindowsImpersonationContext;
        private bool disposed;

        #endregion

        #region Methods/Operators

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        private static extern bool CloseHandle(IntPtr handle);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern int DuplicateToken(
            IntPtr hToken,
            int impersonationLevel,
            ref IntPtr hNewToken);

        [DllImport("advapi32.dll", SetLastError = true)]
        private static extern int LogonUser(
            string lpszUserName,
            string lpszDomain,
            string lpszPassword,
            int dwLogonType,
            int dwLogonProvider,
            ref IntPtr phToken);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern bool RevertToSelf();

        public void Dispose()
        {
            if (this.disposed)
                return;

            try
            {
                Debug.WriteLine("Thread-impersonated identity: " + WindowsIdentity.GetCurrent().Name);

                if ((object)this.threadWindowsImpersonationContext != null)
                {
                    this.threadWindowsImpersonationContext.Undo();
                    this.threadWindowsImpersonationContext.Dispose();
                }

                if ((object)this.impersonatedWindowsIdentity != null)
                    this.impersonatedWindowsIdentity.Dispose();

                Debug.WriteLine("Process-impersonated identity: " + WindowsIdentity.GetCurrent().Name);

                if ((object)this.processWindowsImpersonationContext != null)
                {
                    this.processWindowsImpersonationContext.Undo();
                    this.processWindowsImpersonationContext.Dispose();
                }

                Debug.WriteLine("Outgoing identity: " + WindowsIdentity.GetCurrent().Name);
            }
            finally
            {
                this.disposed = true;
                GC.SuppressFinalize(this);

                Debug.WriteLine("Leave impersonation scope");
            }
        }

        #endregion

        #region Classes/Structs/Interfaces/Enums/Delegates

        public enum ImpersonationLevel
        {
            SecurityAnonymous = 0,
            SecurityIdentification = 1,
            SecurityImpersonation = 2,
            SecurityDelegation = 3
        }

        public enum LogonProvider
        {
            LOGON32_PROVIDER_DEFAULT = 0,
            LOGON32_PROVIDER_WINNT35 = 1,
            LOGON32_PROVIDER_WINNT40 = 2,
            LOGON32_PROVIDER_WINNT50 = 3
        }

        public enum LogonType
        {
            LOGON32_LOGON_INTERACTIVE = 2,
            LOGON32_LOGON_NETWORK = 3,
            LOGON32_LOGON_BATCH = 4,
            LOGON32_LOGON_SERVICE = 5,
            LOGON32_LOGON_UNLOCK = 7,
            LOGON32_LOGON_NETWORK_CLEARTEXT = 8, // Win2K or higher
            LOGON32_LOGON_NEW_CREDENTIALS = 9 // Win2K or higher
        }

        #endregion
    }
}

Sample usage scenario:

using (scope = new ImpersonationScope(username, domain, password, ImpersonationScope.LogonType.LOGON32_LOGON_INTERACTIVE, ImpersonationScope.LogonProvider.LOGON32_PROVIDER_DEFAULT))
{
  // code under impersonation
}

Your Organization's Version Control System is a Production Environment
Thursday, July 2, 2009

If you use version control, work item tracking, defect tracking, project management, or any other system which stores data related to software development activities, you must be consider these systems production environments, and treat them as such. Even if only developers access these systems, they should be subject to the same maintenance and scrutiny as your LOB money makers. Failure to heed this advice can and will cost your organization money and time eventually - not if but when.

Speaking Enagements

  • 11/18/2010 | Charlottesville .NET Users Group | Charlottesville, VA | Topic TBD
  • 09/14/2010 | Hampton Roads .NET Users Group | Cheaspeake, VA | Topic TBD
  • 07/01/2010 | Richmond .NET Users Group | Richmond, VA | Topic TBD
  • (past) 12/08/2009 | Hampton Roads .NET Users Group | Cheaspeake, VA | SharePoint Antithesis - A Case Study in Pragmatic Software Architecture and Engineering Processes
  • (past) 10/04/2009 | Richmond Code Camp 2009.2 | Richmond, VA | Soothing the Pain Points: Data Access, Validation, Rules, UI, Presentation, et. al
  • (past) 07/23/2009 | Charlottesville .NET Users Group | Charlottesville, VA | Debugging on the Windows Platform
  • (past) 05/23/2008 | NoVa CodeCamp 2009.01 | Reston, VA | Going Proxy-less - The WCF Proxy Factory
  • (past) 04/25/2009 | Richmond Code Camp 2009.1 | Richmond, VA | Software Programmer to Software Engineer: Concepts to Span the Divide
  • (past) 02/05/2009 | Richmond .NET Users Group | Richmond, VA | Debugging on the Windows Platform
  • (past) 10/04/2008 | Richmond Code Camp 2008.2 | Richmond, VA | Going Proxy-less - The WCF Proxy Factory

Blog Archive

Post Labels

.NET (64) .NETv4.0 (3) ACID (1) ActiveDirectory (1) ADF (2) Affiliate (1) Agile (6) AJAX (1) Allocator (3) Analysis (1) AOP (4) ASP.NET (6) ASP.NET MVC (1) Assembly (2) BadIdeaPile (1) BagOfBolts (5) Blogger (1) Books (2) BuildMgmt (8) C# (46) ChoDNUG (1) CLR (1) CLRv4.0 (2) CMP (1) CMS (2) CodeCamp (2) COM (1) Conversation (1) Coverage (1) CUI (1) Database (2) DDD (1) DeadFxs (1) Debugging (9) Design (4) DevAuto (3) DevCfg (1) Development (118) DI (6) DiffMerge (1) Domain (1) DTfW (2) EclipseIDE (1) ECM (1) EntityFramework (1) Estimating (1) FileShare (1) Frameworks (7) GAC (2) Google (1) Hardware (2) HRNUG (1) Humor (6) IIS (4) ILDASM (1) Impersonation (2) InstallError (1) IoC (6) KingTodd (1) LinkedIn (1) LINQtoSQL (2) MarketingHype (1) MBUnit (1) Mentoring (22) Metadata (1) Microsoft (7) MOSS2007 (5) MSBuild (2) MSIL (4) MSSCCI (2) NAnt (2) NCore (2) NCover (1) NDatabase (4) NetUse (1) NHibernate (2) NoVaCodeCamp (2) NTSD/CDB (2) NUnit (1) Observation (2) Office (2) OOD (7) OOP (6) OpenSource (14) Opinion (19) Personal (3) PMP (1) Polymorphism (1) PowerPoint (1) PowerShell (2) Presentation (3) Process (4) ProjectManagement (2) PublicKeyToken (1) QA (2) RDNUG (1) Reflection (2) Registry (2) Resharper (1) Reversing (2) RichmondCodeCamp (5) SCM (11) Scrum (5) Security (2) Series (3) Server2008 (4) ServicePack (1) SES (7) SharePoint (7) Silverlight (1) SoC (3) Software (49) SoftwareIsHardwork (17) Speaking (7) SQL (2) SSO (2) StrongName (2) Suite2008 (9) Suite2010 (1) SwEng (19) TechBlunder (1) Testing (14) Thread (3) Tools (8) Troubleshooting (10) Twitter (3) Types (2) UAC (1) UIP (1) Vault (2) VB6 (1) VC (1) Vista (3) VisualStudio (15) VSIP (2) VSTS (1) WCF (4) Web (4) WebForms (1) Win32 (3) WinDBG (3) WindowsIdentity (3) WinForms (1) WIT (1) Workhorse (1) WoW64 (1) WPF (1) WSS3 (2) x64 (2) x86 (2) xUnit (1)

Disclaimer

© D. P. Bullington, all rights reserved. Everything posted on this blog is my personal opinion and does not represent the views of my employer nor serves to infringe on the sovereignty of any nation.