Tuesday, November 29, 2011

Best Software Writing - More than money

I sent these excerpts to all on my team and many more developers and developer managers at work.


The whole chapter is VERY insightful on understanding what drives top developer talent.

 

Edisons
That's not a new idea. Fred Brooks wrote about it in 1974,[] and the study he quoted was published in 1968. But I think he underestimated the variation between programmers. He wrote about productivity in lines of code: the best programmers can solve a given problem in a tenth of the time. But what if the problem isn't given? In programming, as in many fields, the hard part isn't solving problems, but deciding what problems to solve. Imagination is hard to measure, but in practice it dominates the kind of productivity that's measured in lines of code.Productivity varies in any field, but there are few in which it varies so much. The variation between programmers is so great that it becomes a difference in kind. I don't think this is something intrinsic to programming, though. In every field, technology magnifies differences in productivity. I think what's happening in programming is just that we have a lot of technological leverage. But in every field the lever is getting longer, so the variation we see is something that more and more fields will see as time goes on. And the success of companies, and countries, will depend increasingly on how they deal with it.If variation in productivity increases with technology, then the contribution of the most productive individuals will not only be disproportionately large but will actually grow with time. When you reach the point where 90% of a group's output is created by 1% of its members, you lose big if something (whether Viking raids, or central planning) drags their productivity down to the average.If we want to get the most out of them, we need to understand these especially productive people. What motivates them? What do they need to do their jobs? How do you recognize them? How do you get them to come and work for you? And then of course there's the question, how do you become one?

 

More than Money
I know a handful of super-hackers, so I sat down and thought about what they have in common. Their defining quality is probably that they really love to program. Ordinary programmers write code to pay the bills. Great hackers think of it as something they do for fun, and which they're delighted to find people will pay them for.Great programmers are sometimes said to be indifferent to money. This isn't quite true. It is true that all they really care about is doing interesting work. But if you make enough money, you get to work on whatever you want, and for that reason hackers are attracted by the idea of making really large amounts of money. But as long as they still have to show up for work every day, they care more about what they do there than how much they get paid for it.Economically, this is a fact of the greatest importance, because it means you don't have to pay great hackers anything like what they're worth. A great programmer might be ten or a hundred times as productive as an ordinary one, but he'll consider himself lucky to get paid three times as much. As I'll explain later, this is partly because great hackers don't know how good they are. But it's also because money is not the main thing they want.What do hackers want? Like all craftsmen, hackers like good tools. In fact, that's an understatement. Good hackers find it unbearable to use bad tools. They'll simply refuse to work on projects with the wrong infrastructure.

 

I've found that people who are great at something are not so much convinced of their own greatness as mystified at why everyone else seems so incompetent.

 

Excerpts taken from The Best Software writing I: Selected and Introduced by Joel Spoelsky Page 97-106 – (a collection of writing’s Joel gathered from other writers) 

Monday, October 24, 2011

Composition Root

I'm reading Dependency Injection in .Net by Mark Seemann

In response to http://blog.ploeh.dk/2011/07/28/CompositionRoot.aspx

I'm only up to reading mid-way through your chapter on doing it right (and jumped to the asp.net webforms composition root after reading this blog post), but here is more of my reasoning.

The catch comes when you look at the behavior, and you realize that there is hardly any behavior on these objects, making them little more than bags of getters and setters. Indeed often these models come with design rules that say that you are not to put any domain logic in the the domain objects. AnemicDomain Models - Martin Fowler


It becomes a 'real' domain model when it contains all (or most) of the behaviour that makes up the business domain (note I'm emphasising business logic, not UI or other orthogonal concerns). Anemic Domain Models - Stack overflow

I don't feel that this is headed into an Anemic domain model as the domain model assembly would contain all behaviors specific to the domain.

  Designs that share very little state or, even better, have no state at all tend to be less prone to hard to analyze bugs and easier to repurpose when requirements change. Blog article - makes sense but i could be missing multiple boats here.

The domain would have zero state, and would depend on interfaces not DTOs. This would make test-ability and analysis simple.

 Motivation for DTOs in the interfaces layer: presentation and persistence could all share the DTOs rather than having them duplicated in either place.
Barring that perceived gain, then the shared layer across all would just be interfaces.

 The UI could depend on interfaces only, but the same assembly would contain DTOs that the presentation layer and any persistence could share without having to be duplicated/rewritten. So the domain is completely persistence and presentation ignorant.

Wednesday, October 19, 2011

Routing except webforms requests

I have a legacy webforms (.aspx) project that I'm sliding routing and MVC3 into. I needed a route that would not prevent the default page from being handled by IIS, but would allow all other controller style routing.  How do you make a regex that only fails uri's that have .aspx or .axd in them?

Then I thought well I still don't want anything that doesn't look like an mvc route (things that end in .foo or .fooo)  Sounds like a crazy negative regex.
Here's the regular expression:

^(.(?!\.[a-zA-Z0-9]{3,}))*$


Match anything that doesn't look like a file extension 


And here's the routeAdd in global.asax


static void RegisterRoutes(RouteCollection routes)
  {

     routes.MapRoute("mvc", "{controller}/{action}/{id}",defaults: new{action="index",id=""}, constraints:new{controller=@"^(.(?!\.[a-zA-Z0-9]{3,}))*$"});

  }

Thursday, September 29, 2011

Microsoft is embracing extensibility... using Stackoverflow.com for forums, and uservoice for VS feedback!


Where are the MSDN forums?
We have decided to migrate our forums to stackoverflow.com in order to better build a community around Pex and Moles. Questions about Pex should be tagged with 'Pex' and Moles with 'Moles'...

Monday, September 19, 2011

Some F# early learning and reference

I'm translating my bulk code detector from c# to f#, to learn f#. It's a linqpad c# program that recurses a directory tree organizing code

  • by
    • highest line count 
    • highest line count by directory 
    • highest line count by base filename (the stuff before the .) 
  • includes 
    • non-whitespace count 
    • potential magic numbers count 
    • " count


//path returns string
let path :string= 
  let userPath=Util.ReadLine("SourceDirectory?",@"D:\projects\")
  let exists=System.IO.Directory.Exists(userPath)
  if not(exists) then //guard clause
    raise(DirectoryNotFoundException(userPath))
  userPath
  
let doTestFileExclude = false

//fileExclude= Func<string,bool> a=>
let fileExclude  (a:string):bool = 
  a.EndsWith("designer.cs",StringComparison.CurrentCultureIgnoreCase)||
  a.StartsWith("jquery-",StringComparison.CurrentCultureIgnoreCase)||
  a.StartsWith("AssemblyInfo");
  
let pathExclude (a:string) :bool =
  a.Contains(@"\Database\")||
  a.Contains("Service References")||
  a.Contains("Web References") ||
  a.Contains("PackageTmp") ||
  a.StartsWith(@"~\Web\Scripts\Mvc3")

//record, class, struct, or discriminated union?  
type  CountSettings = {
  Path: string
  Patterns: IEnumerable<string>
  FileExclude: string -> bool
  PathExclude: string-> bool
  }
//instance of above type
let currentSettings:CountSettings=  {
  Path=path
  Patterns=["*.cs";"*.js"]
  FileExclude=fileExclude
  PathExclude=pathExclude
  }

//demonstrating access modifier  
let private testFileExclude() =
  let testCases = ["test";"test.designer.cs";"test.Designer.cs"]
  let mapped = testCases |>
    List.map(fun (fn:string) ->
      (fn,currentSettings.FileExclude(fn))
    )
  mapped.Dump("testFileExclude done")
  
if doTestFileExclude then
  do testFileExclude()

//set cwd (not a functional call, imperative?)
System.Environment.CurrentDirectory=currentSettings.Path
//public ~IEnumerable<T> visitDir(string dir,T1 dirFilter, T2 patterns, T3 fileFilter)
let rec visitAll (dir:string) patterns=seq{
  for pattern in patterns do
    yield! Directory.EnumerateFiles(dir,pattern)
  for subdir in Directory.EnumerateDirectories(dir) do
    yield! visitAll subdir patterns
  }
  
visitAll currentSettings.Path currentSettings.Patterns 
  |> Seq.length 
  |> fun x->x.Dump("LengthAll")


let rec visitDir (dir:string) dirFilter patterns fileFilter=
  seq{
  for pattern in patterns do
    for file in Directory.EnumerateFiles(dir,pattern) do
      if not(fileFilter(file)) then
        yield file
  for subdir in Directory.EnumerateDirectories(dir) do
    if not(dirFilter(subdir)) then
      yield! visitDir subdir dirFilter patterns fileFilter
  }
  
let visitDirResult= 
  visitDir currentSettings.Path currentSettings.PathExclude
    currentSettings.Patterns
      currentSettings.FileExclude
visitDirResult |> Seq.length |> fun x->x.Dump("visitDirLength")
visitDirResult |> fun x ->x.Dump("visitDirResult")

//Extension method on string
type System.String with
  member x.Right(index) = x.Substring(x.Length - index)

Tuesday, September 6, 2011

Local NuGet Feed on network drive

This was so much simpler than I imagined. I followed this article from Hanselman.


  1. Get the NuGet.exe command line here. Put it in the %path% or somewhere.
  2. Create a directory for your package - I created mine on the network share directly
  3. on the command line in your new folder nuget.exe spec
    1. Depends on your nuget.exe being in the %path%
  4. edit any fields in the new Package.nuspec file.
  5. If you have assemblies
    1. Add a lib folder
      1. Add assemblies inside
  6. If you have other content
    1. Add a content folder
      1. Add files inside
  7. If you have transforms
    1. Add filename.transform inside the content folder
      1. For example web.config.transform
  8. nuget.exe pack package.nuspec
Package created!

Now add that location in your Vs2010  Tools->LibraryPackageManager->PackageManagerSettings
In Package sources add the source, and name it. TADA!

Friday, June 24, 2011

Database Unit Tests - Config Transforms

I wanted to have a configuration for the other environments to run the same tests.


  1. started out adding the sit configuration to the solution and the test project.
  2. I added the following to my Db.Tests.csproj:
    1. top property group under projectguid:
      1. <ProjectConfigFileName>App.Config</ProjectConfigFileName>
    2. and just below outputType:
      1. <OutputExtension Condition="'$(OutputExtension)' == '' ">dll</OutputExtension>
    3. then in the item group with app.config:
      1. <Content Include="App.Sit.config">      <DependentUpon>app.Config</DependentUpon>    </Content>
    4. finally just before /Project tag:



<Import Condition="'$(Configuration)' == 'Sit'" Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
  <Target Condition="'$(Configuration)' == 'Sit'" Name="PostTransformAppConfig" AfterTargets="TransformWebConfig">
    <Copy Condition="Exists('$(TransformWebConfigIntermediateLocation)\transformed\App.config')" SourceFiles="$(TransformWebConfigIntermediateLocation)\transformed\App.config" DestinationFiles="$(OutputPath)\$(AssemblyName).$(OutputExtension).config" />
    <Copy Condition="Exists('$(TransformWebConfigIntermediateLocation)\transformed\App.config')" SourceFiles="$(TransformWebConfigIntermediateLocation)\transformed\App.config" DestinationFiles="$(OutputPath)\$(AssemblyName).vshost.$(OutputExtension).config" />
  </Target>
  <Target Condition="'$(Configuration)' == 'Sit'" Name="PostTransformAppConfig" AfterTargets="Build">
    <CallTarget Targets="TransformWebConfig" />
    <Copy Condition="Exists('$(TransformWebConfigIntermediateLocation)\transformed\App.config')" SourceFiles="$(TransformWebConfigIntermediateLocation)\transformed\App.config" DestinationFiles="$(OutputPath)\$(AssemblyName).$(OutputExtension).config" />
    <Copy Condition="Exists('$(TransformWebConfigIntermediateLocation)\transformed\App.config')" SourceFiles="$(TransformWebConfigIntermediateLocation)\transformed\App.config" DestinationFiles="$(OutputPath)\$(AssemblyName).vshost.$(OutputExtension).config" />
  </Target>



Here's my app.sit.config transform file:

<ExecutionContext xdt:Transform="Replace" Provider="System.Data.SqlClient" ConnectionString="Data Source=SitServer;Initial Catalog=Init1_SIT;Integrated Security=True;Pooling=False"
        CommandTimeout="30" />
    <PrivilegedContext xdt:Transform="Replace" Provider="System.Data.SqlClient" ConnectionString="Data Source=SitServer;Initial Catalog=Init1_SIT;Integrated Security=True;Pooling=False"
          CommandTimeout="30" />



Based on

Wednesday, June 1, 2011

Workflow quirk: cannot access this inline location reference

Activity '{0}' cannot access this inline location reference because it is only valid for activity '{1}'. Only the activity which obtained the inline location reference is allowed to use it.

Inside my assign activity:
' foundfiles is IEnumerable(of String)
foundFiles.Where(Function(file As String) FileNameBlacklist.Any(Function(blacklistItem) System.IO.Path.GetFileName(file).StartsWith(blacklistItem)) = False)

Not sure if this or the subsequent access was failing, however changing it to this fixed it:

foundFiles.Where(Function(file As String) FileNameBlacklist.Any(Function(blacklistItem) System.IO.Path.GetFileName(file).StartsWith(blacklistItem)) = False).ToList().AsEnumerable

Tuesday, May 31, 2011

Mashup: Team Foundation Server's API and Microsoft Active Directory

I wanted to know the userID and name of anyone that checked out a file in the last 2 months for edit on a specific path inside Tfs. Some of this code was tested to work fine on Tfs2010, but no guarantees.

So it's a nice little bit of code to connect to tfs, get the changes and then pull the names in from active directory with a max of 1 attempt per distinct userID.


Tuesday, May 24, 2011

.wdproj fails to copy down .refresh binaries

So I have recently been put on a team that utilizes web site projects and hooking up build automation.

Apparently the default target for copying down .dll.refresh files does in
C:\Program Files\MSBuild\Microsoft\WebDeployment\v10.0
this for its copy inside the _ResolveReferences target:

 <Copy 
      SourceFiles="@(References->'%(FullPath)')" 
      DestinationFolder="$(_FullSourceWebDir)\Bin\" 
      Condition="!Exists('%(References.Identity)')" 
      ContinueOnError="true"
      SkipUnchangedFiles="true"
      Retries="$(CopyRetryCount)"
      RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"/>

and References.Identity resolves to the source identity, not the target identity. So if the source exists it will not copy.

To work around it, and in case in some other usages for this target need this functionality I added a custom beforebuild override in my .wdproj file:

<Target Name="BeforeBuild">
  <Message Text="Doing custom BeforeBuild" />
<Copy 
      SourceFiles="@(References->'%(FullPath)')" 
      DestinationFolder="$(_FullSourceWebDir)\Bin\" 
      ContinueOnError="true"
      SkipUnchangedFiles="true"
      Retries="$(CopyRetryCount)"
      RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"/>
</Target>

Thursday, May 12, 2011

Workflow 4 Default types to designer initialization

Dependency Injection way overboard?

I've been reflectoring, googling, stackoverflowing for weeks and just now stumbled upon the attribute injector code that runs to give ForEachActivity and SequenceActivity a designer.

Why weren't these attributes placed on the classes themselves? I have no idea.

Point your reflector at System.Activities.Core.Presentation in %windir%\Microsoft.NET\Framework\(4 something)



It's in 



System.Activities.Core.Presentation.DesignerMetadata.Register();
//Sneak peak
{
  AttributeTableBuilder builder = new AttributeTableBuilder();
  builder.AddCustomAttributes(typeof(ActivityAction),
    new Attribute[] { new EditorReuseAttribute(false) });
  SequenceDesigner.RegisterMetadata(builder);
  ForEachDesigner.RegisterMetadata(builder);
}

Tuesday, May 10, 2011

Tfs2010 string collection build argument snags

So it's great that you can use custom types, or more advanced types in Tfs 2010 workflow builds than you could in MSBuild tasks. However the editor/designer support is severely lacking. If you want an editor or designer that everyone can open up and even see what's set there, a custom assembly or vsix package has to be run on every machine that would need to be able to see or edit that argument. Even for something as basic as List<string>

After weeks of posting, forums, research etc... And trying this post it turns out that the legacy string array is what functions.

I wanted to

  • Provide defaults in the template, so that the consumer could just leave it if they didn't want anything more specific.
  • Allow for full customizations, adding, editing, removing.
  • Visibility of what's set for anyone looking at the build definition, not just people with a special assembly loaded.
But if you have tried the others they may have saved to the tfs database and cause your attempts to edit or view them to fail as if the type you are now trying isn't working. Here's a list of things I tried:
  • Microsoft.TeamFoundation.Build.Workflow.Activities.StringList
  • System.Collections.Specialized.StringDictionary
    • creating my own custom editor and adding it to the metadata
  • System.Collections.Generic.IList<string>
  • System.Collections.Generic.List<string>
As it turned out, I have no idea how many of these may have worked had the edit attempts I made not saved into the tfs database. 

Once I finally changed the variable name and tried String[] Array. All of the sudden, everything worked just fine. Alternatively, clicking refresh in team explorer -> Edit Build Definition -> Process tab -> Show details arrow -> click refresh is supposed to work. I wound up renaming the variable. 
So I went back to try all the types I listed and a few more... and the first 3 worked:

  • Microsoft.TeamFoundation.Build.Workflow.Activities.StringList
    • No custom editor specified
    • Microsoft.TeamFoundation.Build.Controls.WpfStringListEditor
  • String[] Array
Entirely or partially failed to function:
  • System.Collections.Specialized.StringDictionary
  • IList<string>
  • List<string>
  • IDictionary<string>
  • Dictionary<string>
  • Microsoft.TeamFoundation.Client.KeyValueOfStringString
  • KeyValuePair<string,string>[]

 What I want is a dictionary<string,string> but I'm getting pretty sure there's no support for it outside of a custom package deployed to all machines that want to view the arguments or edit them.

Copying a Tfs2010 Build template into same project

So, if you want to have a project where you work on TFS 2010 workflow build templates, and decide you want to conceptually branch a template into 2 parts based on an existing.  Copy, Paste, done?

Nope. If your project is set up as mine is with Build Action: XamlAppDef and Custom Tool MsBuild:Compile,
now there's a namespace/class conflict.



You get something like this



2 changes are needed. Right click the template and view code.
The first line that looks like



Which are the two points that need to be renamed. a sample rename would be:



Now your template compiles.

Thursday, May 5, 2011

My first Rx Attempt revisited

I have recently rediscovered my custom code analysis rules which included one that no longer compiles. The Rx team has made sweeping and breaking changes to the structure and namespaces in Rx. How difficult was the code update? 2 references removed, 1 added, and a single MethodName changed.

I cleaned up the code, and discovered many improvements along the way.
I do wish I could find a cleaner way to do this:

var whenMethodsFound = Observable.FromEventPattern<NotifyCollectionChangedEventHandler, NotifyCollectionChangedEventArgs>
 act => foundMethods.CollectionChanged += act,
  act => foundMethods.CollectionChanged -= act);

Idea:
Add a mapping extension in extension method class
Great for simple on the go, but manual for every class you want to do this with.

Which would look like this

public static IObservable<IEvent<PageEventArgs>> GetPublishingPageEvent(this DataFactory dataFactory)
   {
       return Observable.FromEvent((EventHandler<PageEventArgs> h) => new PageEventHandler(h), 
                                h => dataFactory.PublishingPage += h, 
                                h => dataFactory.PublishingPage -= h);
  }


Wednesday, May 4, 2011

ObjectDumper extended

This should be functionally equivalent to Microsoft's version just my own refactorings to support extensibility: No behavior should be different.


using System;
using System.IO;
using System.Collections;
using System.Reflection;

namespace Utilities
{
/// 
/// From Microsoft's http://archive.msdn.microsoft.com/cs2008samples/
/// modified for extensibility
/// 
public class ObjectDumper
{

/// 
/// StaticWrite
/// 
/// public static void Write(object element)
{
Write(element, 0);
}
protected static TextWriter DefaultWriter=Console.Out;
/// 
/// Static Write
/// 
/// /// public static void Write(object element, int depth)
{
Write(element, depth, DefaultWriter);
}
/// 
/// Static Write
/// 
/// /// /// public static void Write(object element, int depth, TextWriter log)
{
var dumper = new ObjectDumper(depth) {_writer = log};
dumper.WriteObject(null, element);
}


private TextWriter _writer;
int _pos;
int _level;
readonly int _depth;

protected ObjectDumper(int depth)
{
_depth = depth;
}
protected ObjectDumper(int depth, TextWriter log):this(depth)
{
_writer = log;
}
/// 
/// MethodWrite
/// 
/// protected void WriteString(string s)
{
if (s != null)
{
_writer.Write(s);
_pos += s.Length;
}
}

protected virtual void WriteIndent()
{
for (int i = 0; i < _level; i++) _writer.Write("  ");
        }

        protected void WriteLine()
        {
            _writer.WriteLine();
            _pos = 0;
        }
        
        protected virtual void WriteTab()
        {
            WriteString("  ");
            while (_pos % 8 != 0) WriteString(" ");
        }
        protected  void DescendIfDepthAllows(Action doIfDescend)
        {
            if (_level < _depth)
            {
                _level++;
                doIfDescend();
                _level--;
               
            }
        }

        protected virtual  void WriteObject(string prefix, object element)
        {
            if (element == null || element is ValueType || element is string)
            {
                WriteIndent();
                WriteString(prefix);
                WriteValue(element);
                WriteLine();
            }
            else
            {
                var enumerableElement = element as IEnumerable;
                if (enumerableElement != null)
                {
                    WriteEnumerable(prefix, enumerableElement);
                }
                else
                {
                    WriteWithReflection(element, prefix);
                }
            }
        }

        protected virtual void WriteWithReflection(object element, string prefix)
        {
            MemberInfo[] members = element.GetType().GetMembers(BindingFlags.Public | BindingFlags.Instance);
            WriteIndent();
            WriteString(prefix);
            bool propWritten = false;
            foreach (MemberInfo m in members)
            {
                var f = m as FieldInfo;
                var p = m as PropertyInfo;
                if (f != null || p != null)
                {
                    if (propWritten)
                    {
                        WriteTab();
                    }
                    else
                    {
                        propWritten = true;
                    }
                    WriteString(m.Name);
                    WriteString("=");
                    Type t = f != null ? f.FieldType : p.PropertyType;
                    
                    if (t.IsValueType || t == typeof(string))
                    {
                         WriteValue(GetValue(element, m, f, p)); 
                    }
                    else
                    {
                        WriteString(typeof (IEnumerable).IsAssignableFrom(t) ? "..." : "{ }");
                    }
                }
            }
            if (propWritten) WriteLine();
            WriteReflectionChildren(element, members);
        }
        protected virtual object GetValue(object element, MemberInfo m, FieldInfo f, PropertyInfo p)
        {
           return f != null ? f.GetValue(element) : p.GetValue(element, null);
        }
        

        protected void WriteReflectionChildren(object element, MemberInfo[] members)
        {
            if (_level < _depth)
            {
                foreach (MemberInfo m in members)
                {
                    var f = m as FieldInfo;
                    var p = m as PropertyInfo;
                    if (f != null || p != null)
                    {
                        Type t = f != null ? f.FieldType : p.PropertyType;
                        if (!(t.IsValueType || t == typeof(string)))
                        {
                            
                            object value =GetValue(element,m,f,p);
                            if (value != null)
                            {
                                _level++;
                                WriteObject(m.Name + ": ", value);
                                _level--;
                            }
                        }
                    }
                }
            }
        }

        protected virtual void WriteEnumerable(string prefix, IEnumerable enumerableElement)
        {
            foreach (object item in enumerableElement)
            {
                if (item is IEnumerable && !(item is string))
                {
                    WriteIndent();
                    WriteString(prefix);
                    WriteString("...");
                    WriteLine();
                    if (_level < _depth)
                    {
                        _level++;
                        WriteObject(prefix, item);
                        _level--;
                    }
                }
                else
                {
                    WriteObject(prefix, item);
                }
            }
        }
        
        protected virtual void WriteValue(object o)
        {
            if (o == null)
            {
                WriteString("null");
            }
            else if (o is DateTime)
            {
                WriteString(((DateTime)o).ToShortDateString());
            }
            else if (o is ValueType || o is string)
            {
                WriteString(o.ToString());
            }
            else if (o is IEnumerable)
            {
                WriteString("...");
            }
            else
            {
                WriteString("{ }");
            }
        }

       
    }
}

Note that this code currently throws an exception if the object passed into it is a Type, for example:

var type=typeof(string);
ObjectDumper.Write(type);


Throws: TargetInvocationException: Exception has been thrown by the target of an invocation. So... the refactoring commenced and the derived class that handles types, and also KeyValuePairs


Monday, May 2, 2011

An ActivityDesigner for InvokeAction

Building off of An ActivityDesigner for InvokeAction

The only changes needed to make it work for InvokeAction was in the Xaml

< WrapPanel name="ArgumentWrapPanel">
and the OnModelItemChanged override:

 //set ETB expression type
            var generics = invokeActionObj.GetType().GetGenericArguments();
            if (generics.Length > 0)
            {
                this.ArgumentETB.ExpressionType = generics[0];
            }
            else
            {
                this.ArgumentETB.IsEnabled = false;
                this.ArgumentETB.Expression = null;
                this.ArgumentWrapPanel.Visibility = System.Windows.Visibility.Collapsed;

            }

Thursday, April 21, 2011

Command line shortcuts

for service starting stopping or even remote event viewing...shortcuts

I made a batch file that does this


set /p compname=Enter the computer name:
start mmc compmgmt.msc /computer:\\%compname%
set compname=

The original had c:\windows\system32\compmgmt.msc but on my system it doesn't appear to be needed
you can replace compmgmt.msc with services.msc or eventvwr.msc

Also to pipe into notepad:


set /p compname=Enter the computer name:
sc \\%compname% query type= service | find "SERVICE_" > %temp%\tmpsvc.txt
start notepad %temp%\tmpsvc.txt
ping -n 2 127.0.0.1
del %temp%\tmpsvc.txt
set compname=


the ping is there because the delete would fire much faster than the notepad starting up, so it's a sleep hack.

Monday, March 21, 2011

EF4 + ESQL for not supported options

So say you want to support wildcard searches against a SQL db. Yes this is probably horrible performance wise, but... useful or as an example how to do ESQL against an EF4 context.

Linqpad against my EF4 context:



  internal IEnumerable<IPlayerFull> SearchForPlayer(string playerNameLike, byte? universeId)
        {

var q= from p in q.Players.Where(p => p.UniverseId == universeId) 
.Where("it.Name like @Name"new ObjectParameter[] { new ObjectParameter("Name", playerNameLike) })
.Where(p => p.UniverseId == universeId)
       orderby p.Name
      select p;
 return q;
bizarre eh? EF4 note, not related to ESQL:

Monday, March 14, 2011

Class organization

I am putting together a theory of  class code readability organization with the assertions that


  • Classes consistently organized are easier to read and understand
  • Fields should be private
  • Consistent internal state is preferable to passing around invalid objects that can communicate they are invalid (immutability vs IDataErrorInfo)
This layout is my hypothesis of what a good consistent layout would be:

  1. private fields
  2. constructor(s)
  3. Initializers and wiring
    1. for example event wiring
  4. non-public properties
  5. public operations
  6. public properties
  7. explicit event plumbing
    1. For example designer auto-generated event handlers
  8. Other plumbing or utilities
As with any theory or concept, the main ways to learn from it are 

  • to communicate it out for feedback 
    • other people's viewpoints can help you find your blind spots
    • you can become aware of situations where the idea or solution doesn't fit and why
  • apply it
  • look at it with a critical eye for places or reasons that it works well and places it doesn't
    • keep an open mind that one size does not fit all
  • solicit feedback for applications of the idea
    • other people can better see past your blind spots
    • explaining it helps keep or find perspective
    • any critical thinking or discussion is likely to be beneficial to all involved parties

Monday, January 31, 2011

Long pages no more named anchors... link someone to a specific part?

I've wanted to do this so many times.... Link someone to a specific part or section of a long web page and had no idea it was possible. It's become a hidden feature since in the old days people used named anchors (< a href="#anchorname">Browser anchor link text. This was easy to right click and select copy location or copy shortcut, etc..

I don't think there's a UI based shorthand any longer but apparently:

example showing usage (with the source I found this information)

http://w3fools.com/#html_links