Well, to me it is vastly disappointing. Back in January, I said that I thought Workflow 4.0 would be the most important feature of .NET 4.0. I was completely wrong. WF 4.0 will be a rather uneventful part of the .NET 4.0 release.
My initial projection was partly because .NET 4.0 will (thankfully) be a rather quiet release at core with only limited new language features so the competition was never all that steep. But it was also because the WF in the CTP represented an important change to Workflow. Microsoft screwed up WF 3.0 and 3.5. It was excessively complex for the marketplace. They implicitly acknowledged this when deciding to scrap the entire thing and start over with WF 4.0. While some people do have deployed applications, WF 3.0 and 3.5 could not be the ubiquitous WF I think we all need in our toolbox. I was hoping WF 4.0 would be that tool.
The bad news is that WF 4.0 probably won’t be. WF 4.0 suffers from two problems, one implied by the other. The first problem is that it has no state machine. At least it’s not in the beta and I have heard no contradictory announcement. The second is that if they could not even provide basic functional parity with WF 3.0/3.5 how could they possibly have had their development act together/sufficient resources/fill in the blank to produce a great 1.0 product. Remember, with the rewrite, WF 4.0 is really a 1.0 product.
I hope I’m wrong on the second part of this and that they’ve covered an adequate range of real world scenarios that it will at least be solid. And WF 4.0 will probably be an interesting tool in the core scenarios, particularly those around WCF integration. I’m not saying it’s useless by any means. I’m just saying it’s probably not going to change your world.
I’m still angry about the lack of a state machine. Certainly WF 3.0/3.5 state machines will still work as well as it ever has, and if you can manage deployment and avoid the layout being trashed by the IDE (hint, keep your layout files ready for restore from source control or edit them to find your lost states). But I’m angry because you and I can’t give our customers new products that just ignore half the scenarios for the old product. We can’t toss out all the work our customers have done (interop is present but limited). We just can’t do stuff like this!
I know the WF team has been working hard and that there are really smart people on the team. I don’t know what went wrong, but the problems with WF 4.0 became the problems of the early adopters, and shafting early adopters (especially when two years still involves “early adoption”) is very bad business.
In fairness, they offered a flowchart solution which will on paper accommodate some of the scenarios where state machines made sense. It’s just the wrong solution, and a horrible decision to do something new while ignoring previous functionality - state machine should have had a higher priority.
The vast majority of non-trivial workflow scenarios are best solved with a state machine. It’s based on a quick analysis. Theoretically all state machines can be expressed in flowchart terms and all flowcharts can be expressed as state machines. So in theory as long as you have either you’re covered. But it doesn’t quite work out that way. Business systems have non-trivial numbers of states. As the number of states increase, the number of legal paths between them increases. The theoretical increase is huge, but unimportant because many states are illegal. However, a sufficient number of legal states remain that as systems become more complex, the number of paths in a flowchart increases very fast. Paths are added more often than states (paths are the most common unexpected side cases). Thus, the system also remains more stable if the initial analysis is against states, not paths. Finally in many business systems, thinking of the problem in terms of states simplifies analysis.
The good news is that WF isn’t the only new thing in .NET 4.0 and in my next couple of posts, I’ll talk about what I now think are some of the most important features of the next release.
I got a Twitter on MEF resources, so I wanted to at least post the resources slide for my MEF/MAF talk. My big question, is what else do you want. Do you want more technie stuff on the core, more extensibility details, more stuff on the WPF editor, more on scenarios and value proposition, to know why I think composability is the most important thing since OOP/OOD (yep, I rank it above generics), or something else entirely? I think there's at least a half dozen people trying to get the right stuff out on this, but we don't need to shotgun this.
I actually modified this a bit if you were in the talks, but it’s a start – definitely not the final word:
• http://codebetter.com/blogs/glenn.block
• www.msmvps.com/blogs/kathleen
• Ask Kathleen, www.VisualStudioMagazine.com
• April 2009 for MEF/System.ComponentModel/Composition discussion
• April 2008 for MAF/System.AddIn discussion
• Hanselminutes: www.Hanselminutes.com
• #148 About MEF –Glenn Block
• #152 March 5, 2009 – Kathleen Dollard
• #147 VS 2010 WPF editor interview
• Also, good Bob Martin interview
• DotNetRocks: (me #436 April 9, 2009 -also, #304, 171, 121, 63)
• MEF download - www.codeplex.com/MEF
• MEF provider model and other interesting Andreas/TheCodeJunkie work www.codeplex.com/MEFcontrib
• PDC Videos
• TL49 (MEF-ify BabySmash)
• TL33 (Glenn Block) at PDC
• Pipeline Builder download: www.codeplex.com/clrAddin
• Kids, don’t try MAF without this
• Channel 9 video on MAF: Daniel Moth (search for System.AddIn)
It’s not up yet. You may have noticed. And if you downloaded what we’ve currently got up at AppVenture, you probably noticed that it was nothing like what I discussed on Hanselminutes or DotNetRocks.
Why is it delayed?
Primarily because I have had a very hard time drawing a line around what should and should not be in the tool. I’m still having a hard time of that, and the first version won’t include everything I want.
Also, MEF is a new paradigm. It’s been rough at times to learn to rethink and debug differently. This has caused a few redesigns along the way, and lots of consideration for things like the large number of assemblies. These are things I think need to be pretty close to correct in the first go round. This process would have been much more difficult without Glenn Block’s help, and I really appreciate his help and friendship.
I began many parts of this project in VB. I love VB. But the open source aspect of the future of this project will involve primarily C# coders. That’s the world around me. I am happy in C#, I just went fairly far down the VB path and had to do a lot of translation. When I release it, it will be mostly C#, with some remaining VB in parts I want to rewrite (the UI) and places where VB offers benefits (XML literals).
I’ve also run into a half dozen really nasty scenarios, both in my code and the framework that took a few days to resolve.
Parts of this have been raw research. What should such a tool look like? I’m convinced it’s by far the best way to generate code, but the devil’s in the details. I think it will make it easier for you and others that I worked though these details, although as I look back at the simplicity of many parts of the solution I have plenty of self-doubt that I just started out stupid.
All these things take time, a lot of time. And I try occasionally to have a life, although the people in it would certainly argue my capacity for setting this aside.
When? I hope next week.
The purpose of MEF is to hook up parts. Parts are indentified by string contracts.
MEF (and tools like it) empower fully composable systems. I use that term to describe a system in which the system no longer knows what is going on. What you write empowers an ecosystem specific to a problem domain it does not solve the problem.
In my case, MEF empowers a harness where processes, generally code generation templates, are run in a specific manner (such as with pre and post processing). I don’t care what your process does. At one level I don’t care about what services it needs or what metadata it uses (although in another post, I’ll explain why I actually do care, the harness definitely doesn’t care). This is a tremendously powerful environment for certain problems, precisely because it becomes an ecosystem solution, not a proscribed solution.
It is also a very different environment where we’re still working out the rules as an industry. One area where the rules shift is in assembly organization. There are always two core drivers for assembly (project) organization – deployment and isolation. How does this play out in a MEF system?
Let’s assume UI isolation. MEF systems generally solve a complex but finite problem. It makes sense for them to be class libraries that are distinct from any single user interface. In the code generation case, we know we will have a graphical UI and a command line. I suspect I’ll have a kind of sucky graphical UI and someone will make a pretty one and starting in 2010 embedding in Visual Studio becomes more realistic. That’s 2 in any single deployment - one of the UI’s and a class library that is the core of the system.
A core goal of a composable system is to replace direct references with indirect references. This means interactions will generally use interfaces which belong in their own library for isolation. These interfaces will generally have a default implementation. While technically these defaults could reside in either the interface or the core library directory, putting them in either location means they will always be available and you will have to work harder for the user to replace them. Thus I think four class libraries is the minimum complexity for a real world MEF solution.
Almost all fully composed systems should go to at least one additional set of assemblies. Fully composed assemblies contain interfaces which are directly referenced and used by the system core and interfaces that do not have this direct interaction. It’s software entropy if I force you to design an interface for extracted database metadata. I’ll give you one, although the core system could care less about it. For isolation and clarifying intent, I think separation is a better approach.
You could place the default implementations for indirect services (such as metadata extraction) into the same assembly as the default implementations for services directly referenced by the core. Nothing will break. But they will always be in the same catalog and export provider, requiring the complexity of selecting the correct one. Deployment is simpler if these are separate. I also think a parallel between implementation and interface assemblies makes the system overall easier to understand.
In some cases, including the code generation harness, there are specific sets of roles parts can play. A given use of the harness may use any combination of these. If the assemblies are partitioned across these boundaries, people setting up the MEF system can employ only those items they need. Among other things, this speeds the MEF discovery process. For example, in the code generator, there are a couple of categories of metadata, output, naming and miscellaneous services.
The specific roles the parts play is defined via the interface assemblies. If these assemblies are partitioned, programmers extending the system later reference the specific set of interfaces they want. With partitioned assemblies, they might need to reference more than one, but once referenced, the complexity of what the programmer sees is less (which could also be done with interfaces).
Let’s explore the role of the extending programmer a bit more. If there is no extending programmer (you or someone else) there is no point in a composable system. This extending programmer might be part of the original team, if the purpose of composition is simply flexibility in deployment, such as whether particular modules based on customer status. In many cases, including the generation harness, the system is really being created for the convenience of the extending programmer, and it is there scenarios that should drive the application design. You may be able to design your system so certain changes can be made without MEF knowledge (new templates in the code generation case) but the reason you’re using a composable system is to support programmers creating new parts.
This extending programmer works in their own assembly, which among other things allows you to issue updates to default assemblies without breaking their work. These assemblies reference interface assemblies. Is it easier for that programmer to select well partitioned interface assemblies and use them to better understand how the system works. If you partition your implementation assemblies to parallel the interfaces, deployment is simpler and if you fully implement an assembly, you can remove the default one.
There are a few blog posts including this by Chad Myers and this by Davy Brion that speak disparagingly about solutions with many projects. I do not actually agree with either post (because solutions are convenience only features and our architectures should not reflect Visual Studio bugs) but I do think they make some good points. And the fundamental agreement is that you should understand why you have a lot of projects if you do. In this case, it’s for isolation (a core tenant of MEF) and deployment. If you want only a couple of projects in your solution, you don’t want a composable system (although you might still use MEF for other reasons).
So much of what I do with technology turns out ten times harder than I think it should be that I’ll admit I walked very softly and fearful of the quicksand when I wanted to implement my own prioritization strategy for MEF parts. In the end, the MEF interaction was dirt simple.
For review, MEF has a prioritization strategy. When you are looking for parts, the first export provider that fulfills the request (contract and cardinality) ends the part search process (the GetExport(s) variation). However, the generation harness has more complex requirements that this allows.
To create an application, you’ll use a set of templates. Templates will have a specific purpose, such as a Select stored procedure. I’ll supply a default for this, but you may not like my default and will want to replace it.
I want to do this while maintaining complete ignorance in the template about what contracts you are working with. I can’t use the multiple export provider strategy because I want all the templates in all of the catalogs considered.
You also will probably want to replace metadata and service parts. This scenario is different because the template knows the specific contract. Because there is a specific contract request, the MEF native prioritization could potentially work, except that I want the simplicity of a single export provider to manage the templates and do not want multiple export providers/containers.
Parts, including templates, have a contract, which in MEF is a string. There will be many templates doing multiple jobs in the generation process. MEF just grabs everything that implements IProcessWrapper when it grabs templates. I want another level of selection.
All contracts involved in the prioritization strategy have an Id and a priority as MEF metadata. MEF metadata is just a dictionary of values so I can check whether an Id or priority exist in the export definition. I want to run only the highest priority template for each Id. An Id might be “SelectStoredProc” or some other descriptive name. For convenience I’ll supply constants for the common templates. My templates will have a priority of 0 and will only run if no other templates are available. I’ll include a different post about why I think we can all play nice with priorities and about how to override priorities, after I figure out how I’m going to do that.
To accomplish this…
I created a new aggregate catalog that derived from the MEF AggregateCatalog and override the GetExports method.
Imports System
Imports System.Linq
Imports System.ComponentModel.Composition
Imports System.Collections.Generic
Public Class PrioritizedPartCatalog
Inherits Hosting.AggregateCatalog
Public Overrides Function GetExports( _
ByVal definition As Primitives.ImportDefinition) _
As IEnumerable(Of TempTuple(Of Primitives.ComposablePartDefinition, Primitives.ExportDefinition))
[[ In case I confused the C# folks, VB has “partial namespaces” which means it tries to tack namespace pieces like “Primitives” onto the stated namespaces and applies a little more clarity to namespace organization. I could have alternatively imported System.ComponentModel.Composition.Primitives]]
I want to grab all of the matching parts and do some additional filtering.
Dim allExports = MyBase.GetExports(definition)
The next part involves some KinkyLinq (I should probably grab that url). When I’m doing hard stuff in Linq, I split things up into multiple queries. Linq will optimize this if it can, and my brain won’t explode from one overly complex statement. The first query creates groups by Id. The second grabs the highest priority item in each group:
Dim q1 = From y In allExports _
Group y By key = GetId(y) _
Into Group _
Select key, Group
Dim q2 = From g In q1 _
Select _
( _
From y In g.Group _
Where GetPriority(y) = _
g.Group.Max(Function(z) GetPriority(z)) _
).FirstOrDefault
Return q2.ToList()
End Function
Not all parts will opt into prioritization. This is entirely optional. Managing this with priority is relatively easy. Any part without a priority has a priority of zero. However, managing Id’s for things that opt out of prioritization is a little more complex.
Private Function GetId( _
ByVal tuple As TempTuple( _
Of Primitives.ComposablePartDefinition, _
Primitives.ExportDefinition)) _
As String
' The guid means any export that opted out of prioritization is included
Dim idObject As Object = Nothing
tuple.Second.Metadata.TryGetValue("Id", idObject)
Dim id = CStr(idObject)
If String.IsNullOrEmpty(id) Then
Return Guid.NewGuid().ToString()
End If
Return id
End Function
If the ID exists, it’s used. If the Id does not exist, a Guid takes its place for the purpose of the filter. That means anything without an Id will always be considered the sole member of a unique group and will always be included since one member is selected for each Id.
The amusing thing about this solution is looking back in retrospect at where I spent my time. I spent a lot of time figuring out what could be done with MEF. I spent some time doing something wrong with Id’s at the metadata attribute level (which does not need to be complex) and spend some time on that KinkyLinq statement. Thanks to Glenn Block, Jay Harlow, Rob Teixaira, and Andreas for their help.
What I didn’t spend much time on is actually fitting the solution into LINQ. Adding this additional filtering involved only the code here (and the helper function for GetId() which you can predict). How simple can you get? The extensibility of MEF is what really makes playing with it worthwhile. If you hit a problem, like my unique filtering needs, you can probably find a way to work around it.
First, hugs and kisses to the people at Microsoft that made the decision to include T4 in Visual Studio 2008 instead of having it only available within the separately downloaded DSL toolkit. This indicated an important commitment by Microsoft to T4 and was a really positive step in code generation over all. Thanks guys!
I think the option wasn’t to have T4 done right or wrong in VS 2008, but to have T4 done wrong or not to have it. I’m happy the decision to include it was made, but I also think people need to understand what’s wrong with it.
First, the T4 template engine runs code in place and puts the result in the same project as the template in a dependent location. Huh? When would you ever want this? A core purpose of templates is to reuse templates across many projects, and once you get to working with and debugging the project, the template should be in the background, not the foreground. Oh, and this design strongly implies a single output file when single file output has been pursued by no one outside Microsoft (and by the way, Microsoft, we hate single file output). The folks working on the T4 Toolbox have shown us ways around this, but they are hacks giving templates inappropriate responsibilities for organizing the generation process. Templates should have the single responsibility of defining what to output.
Second, templates do not have a mechanism for passing parameters. Huh? We always pass parameters to templates, and we are almost always looping when we do it. There are hooks to pass parameters in T4, but you must understand some pretty complex plumbing to write into these hooks and it takes a few hundred lines of ugly code and internal, on the fly code generation.
Third, templates represent two interleaved sets of code. It’s the nature of templates and in T4 this is C# or VB code embedded within the artifact definition, which is often the definition of C# or VB code. Ad in the Microsoft provided editor its all the same color (black). Huh? Did you ever notice that these are nearly unreadable when displayed in a single color?
Sure you can fix these problems on your own, but everyone doing things their own way both wastes time and increases software entropy. Software entropy is the converse of feedback systems, and I’ll be talking more about that in relation to architecture expression in the next few days.
There’s good news here. Clarius provides a colorizing editor as a community edition to get you started. If you want fancier features, their main product is just $100. We’re releasing a community generation tool (also for free) as the AppVenture Community Generation Harness. This harness is a fully composable generation harness that will initially deliver with support for T4 and class based generation (such as VB 9 XML literal generation). It’s got the basic feature list in this entry. That’s in review at the moment and I’ll post here on my blog when it’s available at www.AppVenture.com. Using these two tools together, you’ll have a very workable generation environment based on what is a really a very sweet template language in T4 or VB 9 XML literal code generation, or any other type of generation someone writes a wrapper for. And thanks to Clarius and AppVenture, it’s all free to you.
I’ve been contemplating how to organize MEF assemblies. I think the processing I did establishing the first cut at organization, and the shake down of that strategy, may be interesting to other people designing MEF systems.
As a quick review, MEF lets you throw parts into a MEF container and sort out how parts work together at runtime. Parts are recognized by a string identifier. I’m almost always using interfaces as the contract and the interface names as the identifiers. Parts reside within assemblies and in the common case assemblies are discovered because they are grouped into anticipated directories.
With this approach, only the part implementing the interface and the part that is using the interface need to understand the interface or explicitly reference the interface’s assembly. And since parts are discovered and loaded at an assembly level, the granularity of implementing assemblies also controls the granularity of the load. I care about the assembly granularity of contract/interface assemblies so excess stuff can be avoided and naming conflicts (resolved via namespaces) are minimized. I care about the granularity of implementation assemblies because until I attain a priority system with additional granularity, prioritization/defaults are only as granular as their containing assemblies.
At one extreme, all interfaces reside in one assembly and all implementations reside in another. It doesn’t make sense to put them into the same assembly as then hard coded references exist and ensuring isolation is difficult. At the other extreme, every interface and every implementation resides in its own assembly. I think both of these extremes are a terrible solution. That’s because this composable system (and I would think any composable system) have parts with very different roles and lineages/history. In the simplest sense for a generator - metadata providers and templates are fundamentally different and could easily be provided by different teams.
Initially I thought the primary consideration should be the implementation deployment, but Phil Spidey pointed out in the MEF discussions that the interface organization is more important, because once released to the wild it might be hard to fix.
I decided on six contract assemblies:
|
CommonContracts
|
Interfaces referenced by the template harness itself
|
|
CommonDatabaseMetadataContracts
|
Interfaces sharing database structure
|
|
CommonDomainMetadataContracts
|
Interfaces sharing business object structure
|
|
CommonNamingServiceContracts
|
Interfaces for a naming service
|
|
CommonOutputServiceContracts
|
Interfaces for outputting data, including hashing
|
|
CommonServiceContracts
|
Miscellaneous interfaces that don’t fit elsewhere
|
I’ve used a few criteria for this design:
Interfaces that are used by the system and therefore can’t easily be changed reside together in CommonContracts. The template harness also references CommonOutputServiceContracts but this is in a separate assembly because it has a distinct purpose, may evolve on a different time frame and you are far more likely to provide alternate implementations for output than for the core interfaces.
The naming service is also a separate assembly because it is a distinct purpose and some people will certainly supply alternate implementations to manage human languages other than US English. Both the output service and naming service are a few distinct interfaces that work together. I also had a few odd ball interfaces and decided to go with a grab bag of miscellaneous interfaces rather than a separate assembly for each interface. Time will tell whether that is a good decision.
I initially put the two metadata interfaces into a single assembly, but I think it’s quite likely that these interfaces will evolve separately and almost certain that they will be implemented independently.
I’d like to note that the first version of the harness, which is almost, almost done (a separate blog post) will be a CTP /alpha level release. I will take feedback on the interfaces and I do expect them to change. A core part of the composable design is that you can spin off your interfaces/implementations so while these changes will be breaking, you can uptake them at your own pace.
Scott and I sat down at the Rocky Mountain Trifecta 1 to discuss code generation and other fun things. Check out show 170 at www.Hanselminutes.com
If you aren’t currently creating T4 templates, skip this post as a rather geeky exploration of something you should never have to touch. Hopefully in another few days you’ll harness to take care of this ickiness.
T4 templates should know their own output file name! This is not a function of the host or the harness or anything else. We want to wrap up the responsibility of creating a template in one location (with any redirection necessary by the class to get the job done and support single responsibility).
How to do this? My first idea was way nerdy wacko cool – use MEF! It’s new, it’s cool, everyone loves something with such a cute name!
The first step to MEF-ifywas moderately easy – add a class in the T4 template that has an export (or a property, or whatever). This just involves usual ickiness of setting T4 references, imports etc. Messy, but if you are working with T4 hosts and engines, you know this stuff. Got that done.
The code for the MEF export approach might look like:
<#+
[Export(typeof(IT4Template))]
public class TemplateSupport : IT4Template
{
public string GetFileName()
{
return "Fred";
}
}
#>
Then, comes the harder part – where do you deal with the MEF container? Some place in looking through this, I realized why this is NOT a good use for MEF. Two reasons actually – First I know exactly where the value should come from. I suppose I could argue for some sort of default service that uses an embedded naming pattern, but I already know that embedded naming patterns get ugly over time. XSLT will require a naming pattern (or call backs which are problematic during testing), but MEF and XML literals, etc will not. We need a single location, the template, to tell us the output file name. And it needs to run code to determine the name. I can’t predict for a pattern language everything someone will want to do, leaving people to extend a pattern service – well complexity goes up.
The second reason is that there is another way that is demonstrably less complex. To meet this bar, we need code simpler than what I showed above.
The second approach I considered was a value holder service for the host. Basically the template could request a service (which could the template itself) that supported the service and simply set the value. Then after the template ran, the engine could retrieve the filename from the host, which was holding it for everyone’s convenience:
<# (this.Host as IValueHolderService).SetValue("FileName", "Fred"); #>
That’s still pretty ugly. It occurred to me that we already have a value holder service, we just call it properties and it contains parameters to the T4 template. I’m just going to swipe a slot in the properties dictionary for my use, which by implication means you can’t use the property name I use. I decided it would not be nice to force you to avoid having a property named FileName with some other purpose than the output file name. The name needs to be exquisitely precise, because I am messing in your logical symbol space: TemplateOutputFileName does the trick for me (I’ll be happy to take other suggestions).
Now, you can just set the name of the output file in code, using whatever additional functionality you need. At the level of the T4 template code, you are just setting the value of a variable. The result is something like:
<# TemplateOutputFileName = "Fred"; #>
This fulfills my goal of a very simple way for you to set the filename inside your T4 template while allowing you to run any code you. There will be some T4 geeks that do a double take at the fact this is not a directive, but directives do not allow internal template code to run. If this gives people heartburn they can either declare the property (I won’t redeclare it) or I’ll also add support for a directive if people really want it.
Josh said this in the MEF discussion list on CodePlex:
MEF is just a composition engine its job isn't really to offer choices for a users.
While that is true, it’s not that hard to present choices to users and it gives you a bit of insight into the very powerful strongly typed metadata attributes of MEF.
MEF is a tool for matching up parts. Its discoverability is not against the actual class, because that would require too deep a dive into the assembly. Its discoverability is based on class attributes which announce that a part fulfills a contract. In MEF, a contract ID is always a string and you’re committing to fulfill expectations someone will have about something that claims that contract. I almost always use one of two types of contracts – type contracts against interfaces that formalize my commitments and simple strings when I have a random piece of information floating around like a database or server name. To clarify how it works, MEF turns the type into a string for its internal use.
When you create an interface for MEF you have the option to create metadata to use with it. Metadata generally (always in my case) exists as two pieces – an attribute and an interface. What happens internally is that MEF creates a dictionary with the data provided by the attribute. At runtime, you can request that you only see parts that fulfill the contract and metadata by supplying contract interface and metadata interface. If you strongly type this via the generic overload you have a MetadataView property which is of the type of your metadata interface.
You can explore this more in the documentation for strongly typed attributes at the MEF site on CodePlex.
From a binding perspective, if you want to bind something you create an ExportCollection(Of IFoo, IFooMetadata). This is a collection of export objects which have a IFooMetadata strongly typed MetadataView property. With me so far?
<Import()> _
Private mDatabaseServices As _
ExportCollection(Of IDatabaseServices, _
IDatabaseServicesComposition)
And in the Load method:
providerComboBox.ItemsSource = mDatabaseServices
You can bind to this export collection (FriendlyName is a property on my metadata interface):
<ComboBox Grid.Row="1" Grid.Column="1" Name="providerComboBox"
SelectionChanged="providerComboBox_SelectionChanged">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=MetadataView.FriendlyName}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
ExportCollection is not an ObservableCollection, so if you want those extra features, you can create one yourself. In the Load method this is simply:
availableOutputs.ItemsSource = OutputItem.GetBindableList(mOutputListeners)
where OutputItem is
Public Class OutputItem
Private mExport As Export(Of IOutputListener, IOutputListenerComposition)
Public Shared Function GetBindableList( _
ByVal list As IEnumerable(Of Export(Of IOutputListener, IOutputListenerComposition))) _
As ObservableCollection(Of OutputItem)
Dim ret = New ObservableCollection(Of OutputItem)
For Each item In list
ret.Add(New OutputItem(item))
Next
Return ret
End Function
Private Sub New(ByVal export As Export(Of IOutputListener, IOutputListenerComposition))
mExport = export
End Sub
Public ReadOnly Property FriendlyName() As String
Get
Return mExport.MetadataView.FriendlyName
End Get
End Property
The XAML for binding this is:
<ListBox Grid.Row="5" Grid.Column="1" Name="availableOutputs" >
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Path=FriendlyName}"
IsChecked="{Binding Path=IsActive}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Where differences other than in the binding are because I’m solving a different problem.
I'm struggling to get the AppVenture Community Edition Code Generation harness into release because I can't figure out where the boundaries should be. I initially thought I could just reuse my old stuff in the area of data extraction and mapping/morphing, but too much has changed.
What's in:
- Multi-UI supporting core code generation engine
- Full composability via MEF
- Configuration driven ordering of automatically discovered templates
- Template focused generation (templates know stuff)
- Multi-file output via a simple naming mechanism
- Support for VB 9 XML literal templates
- Support for T4 templates
- A few example templates at Hello <item> level
- Key service interfaces defined
- T4 property extraction/value setting
- Partial data extraction (tables and a few others)
- Rudimentary US English pluralization service
What's delayed:
- Full data extraction (views, foreign keys, etc)
- Mapping across data/object impedance mismatch boundary
- Full project templates (stored procs and biz layer)
- Hashing output files to protect handcrafted code
- Services to load stored procedures
- Services to create project files
- XSLT template support
- More services such as a better naming service
The core of this design is that I do not want to stand between you and your templates, metadata or services. Thus if you have metadata, you can hook this up and generate anything you can write T4 or VB9 XML literal templates for. You can create any services, metadata or templates you want.
Delaying stuff is hard. I want this to fully meet the capabilities of the GenDotNet harness so I can retire it. This is a vastly superior way to approach the problem.
So, where's the boundary? For this tool to be worth a look, what does it need to do? This is V1, the rest will come. I'm trying to balance when to release V1 and I'm doing this all in my "spare" time so some patience will be needed.
Comments please!
At the MVP Summit I had the pleasure to sit down at a party for some one on one time with Don Smith. I’m trying to think of my blog as a nice little corner to talk, rather than a soapbox. I want to make an share something that is not shouted from the rooftops. Eeegads, I don’t want to start another debate on this.
A few months ago, the EF team started a wiki where Ward Bell and I felt quite attacked for suggesting that DDD is not always the best approach. And thus, it is with some trepidation that I touch this topic. But today’s Database Weekly has a column on it and I really feel there’s stuff worth hearing. If you’re here in my nice intimate corner, you can hear it.
The question of whether to start with a database or a domain (business object) model makes no sense. The answer is easy: start with the one most likely to bring you success, and don’t ignore the impedance mismatch problem.
A well structured application has a good domain model and a good (relational) database and a good strategy to cross the impedance mismatch boundary. That boundary exists because neither the domain nor the database should drive the structure of the other.
A database might be a more successful starting point if you have good, stubborn, or available DBA’s or if your DBA’s are good analysts. If you’re a small shop – which do you build better and have you ever tried building it the other way? Database first is also often a good starting point if you have an existing database. Even if the database is bad, it contains the existing business, and it’s my belief we should never close our eyes to a way the business has already expressed itself if we can get a hold of it (it’s not in code). While we should consider available expressions of the business, we should not blindly accept any piece without exploring also exploring its problems.
A domain might be a more successful starting point if you have good, stubborn, or available coders, or if your coders are good analysts. If you’re a small shop – which do you build better and have you ever tried building it the other way? Domain first (DDD) can also be a good starting point if you have an existing database. If you build a domain model that you constantly validate against the existing database you can base your thinking on experience while not being stuck in that experience. While we should consider available expressions of the business, we should not blindly accept any piece without exploring also exploring its problems.
If it’s an even match, consider DDD. The issues are more subtle and getting them out of the way might be helpful to your project.
The monumental disservice that resulted from the EF wiki (which has thankfully now died a formal death) is that this decision appeared to be a religious one or one that marked you in one camp, or perhaps to some even something about your level of coding. All of that is stupid.
- Do DDD or database first based on what makes sense in your specific scenario
- Whichever way you start, attention to the impedance mismatch will minimize negative consequences to the other side of the boundary
It comes down to the obvious. It’s your team, it’s your project. Make decisions based on your reality, not dogma. Learn from the debates in our industry. Don’t pick sides and follow blindly (even my side.)
So, now we can go back to the rest of the party. If this kicks off another brawl, I suggest slipping out by the side door.
I don’t know the history of the term red herring, but to me it means something you’re looking at thinking it’s the problem, when it’s just not the right problem.
I have to return to the red-herring in my recent MEF debugging post. I wasted a lot of calendar time thinking the problem was in MEF. It wasn’t. It was in my code.
The biggest hurdle to effective debugging, the biggest time waster, the mind killer of debugging is the red herring. When you are debugging the quickest way to become ineffective is to latch on to a perceived solution and cease to look in other directions. Nancy Folsom and I wrote about this years ago as I was adopting her style of debugging. Her answer is very simple – debug using a scientific method which means you attempt to prove yourself wrong. When you think a problem is in a particular location, figure out a test that will tell you that you are wrong, and do not cling to the incorrect assumption that the converse is true.
There are few tests that can prove you are correct because there are many reasons for a particular result. If you look back at my previous blog post, there’s a profound example of this. While I didn’t perceive it that way, my test of the dictionary was actually evidence of an inheritance problem, but in the attribute while I thought the inheritance problem was in the interface. But remember it wasn’t an inheritance problem at all. Had I taken this as “strong indication” (similar but not quite as strong as the word “proof”) that my theory was correct, I would have continued to dance with the red herring and not proceed toward the solution.
Debugging is full of red herrings. If you watch your debugging process you’ll find you make dozens of incorrect guesses about the problem. This is good. You don’t know what the problem is and you must creatively come up with dozens of ideas. The trick to effective debugging is to come up with these ideas, phrase them as questions that can be answered, prioritize them based on likelihood and ease of testing, and then run tests that prove each idea wrong so the wrong ideas can be discarded as quickly as possible.
Team this with “Price is Right” techniques. There was a game on that show where someone had a short amount of time to guess the right price and an answer of high or low. The smart player guessed any number, then split the difference between that and a boundary condition. This can also be called divide and conquer debugging. While the scenarios where divide and conquer is effective is limited, it’s a valuable way of thinking/debugging in those scenarios. For example, if you have the wrong value displayed, is the database returning the right value, does the object contain the right value, etc. It’s a subset of scientific method debugging, but it’s a significantly important subset to call out.
Enjoy your debugging! It’s where you spend most of your time.
I’ve gotten into what feels like a gnarly debugging problem in a MEF application. Debugging MEF can be challenging so I’ll describe the process I went through. Obviously you are unlikely to have an identical problem, but it might help to see the specific questions I asked as I walked through the debugging process.
NOTE: This describes a problem with the import process; problems in the composition process have very good error messages. With composition problems, you’ll often get “no export” errors. This is a little more complex way to drop into the same debugging process.
I had a working application that I needed to overlay a few new concepts on. This included adding my own defaulting system. This meant adding strongly typed metatdata attributes that corresponded to each of my MEF part interfaces. That background explains why I’ve been all over the code and made hundreds of changes since it last worked. And this would have been a pretty tough refactoring to do in bits and pieces.
The symptom of my broken app is that I have an empty ExportCollection on a field defined with an Import attribute. This is nearly identical to getting a no matching part error for a single value with an Import attribute.
Did MEF evaluate the Import?
If MEF hadn’t tried to fill that collection, it would be null (Nothing in VB). Since I have an empty collection, I’m confident that MEF is evaluating the class. If it was a single value, the value would be the default value rather than receiving the error.
Is the assembly in the catalog as expected?
This question more or less corresponds to whether the assembly is being built in the correct location. I happen to be exporting my export container for other reasons, but you can also check this stepping through the code that builds your export container. In my case, both check out so I’m still tracking down the problem.
Does the Export attribute contain exactly what I’m looking for?
MEF contracts are strings. This offers enormous flexibility, but it also means the match between export and import needs to be exact. When you use a type for a contract, it’s a shortcut for adding the fully qualified name. That shortcut is exceedingly valuable because it makes your code strongly typed and avoids typos. However, if you add an Export attribute without including a parameter, the type name is exported. The vast majority of cases the export should be an interface implemented by the class, not the class itself. Thus, I check that my export attribute contains the interface type and that I’m looking for the same interface in the Import and that they both use the type (GetType in VB, typeof in C#).
If you are using a metadata view in your Import…
The export collection is:
<Import()> _
Private loopExports As ExportCollection( _
Of ILoopValues, ILoopValuesComposition)
Does the collection contain expected values if you remove the metadata view request?
I stripped out the second type parameter to see if the collection remains empty. This required commenting out a bunch of code because I’m depending on that metadata view. I could also have created a new class for the test.
The result of this check is that the collection is empty only when the metadata view is in place. So at least now I know the problem is in the metadata view.
Does the strongly typed attribute have the MetadataAttributeAttribute?
I’ve made this mistake a few times before and MEF has several similarly named attributes so I double check…. All’s good
Do the property names and types match exactly on the metadata view and attribute?
If you don’t understand how strongly metadata views work, a brief summary of what happens under the hood may help. The attribute supplies property to a dictionary of metadata on the export. The result is identical whether you use multiple MetadataAttributes and add the values with string keys, or you use the same keys as the property names in your strongly typed attribute. When matching exports, the MEF container checks whether the dictionary on an export can provide the entire data for the requested interface.
So, I triple check spelling and other obvious issues that mismatch between the custom attribute and interface. I minimize the possibility for this by using an interface. The primary reason I use an interface is to force future changes in the interface to be made in the attribute. However explicit interface implementations do not need to have the same name as the interface and it is the properties of the attribute, not the interface, used in the dictionary. So a mismatch can still occur:
Public Interface ILoopValuesComposition
Inherits IExportCompositionBase
ReadOnly Property LoopTypeNames() As String
End Interface
<MetadataAttribute()> _
Public Class LoopValuesCompositionAttribute
Inherits ExportCompositionBaseAttribute
Implements ILoopValuesComposition
Dim mTypeNames As String
Public ReadOnly Property LoopTypeNames() _
As String _
Implements ILoopValuesComposition.LoopTypeNames
Get
Return mTypeNames
End Get
End Property
...
There is no direct relationship between the metadata view used at runtime and the attribute – the relationship is indirect and through the metadata dictionary of the export object. While it is not necessary for correct runtime behavior, I find it very helpful to implement the metadata interface on the attribute. All looks good.
A red herring….
I’m wondering about the inheritance within the interface. My concern is partly due to the fact I know there are some issues with inheritance in MEF Preview 4. I’ll pull that out and anything that depends on it, and see what happens. Voila’ my collection is no longer empty.
I know I’m going to see Glenn Bock this weekend at Alt.NET, so I’ll talk to him about it. However, it doesn’t make much sense for MEF to skip the base class data in the attribute.
<later>
Glenn is not aware of any problems around my scenario when I explain it to him. He thinks it should work. And he’s sick and involved in Alt.NET so I don’t sit down to pair with him on Friday night.
What is actually in the dictionary?
I’m a bit embarrassed to admit that I woke up in the middle of the night realizing this was an important question to ask to establish that inheritance was the problem. Then inheritance would be “proven” as the problem, and since Glenn thought it should work it would be a bug and I could work on a redesign until the next build.
Because I can get a list of exports when I remove the strongly typed metadata view from the Import request, I have an opportunity to look directly at the metadata dictionary for each export. I’m confident in what it contains, but the process of debugging is around challenging and double checking these kinds of assumptions.
I put a break point within the class with the failing import. Stopping at this line, I look at the metadata view on the first export. It should have three items, two from the ExportCompositionBase and the LoopTypeNames from the code above. I check the count and it has one: just LoopTypeNames.
OK, now I know why the import request is failing. MEF determines whether the dictionary can fulfill the entire metadata view contract/interface. It can’t. It doesn’t have all the values available. It’s missing exactly the values in the base class, which is actually consistent with an inheritance problem, but happily my brain is stuck on the inheritance of the interface, not the inheritance of the attribute, so I retake ownership of the problem.
In my mind, the question is no longer why MEF doesn’t find the appropriate exports based on metadata view, but why doesn’t my class have the correct metadata view? I know I put on the attribute. Here’s the code:
<Export(GetType(IBizModelMetadata))> _
<Export(GetType(ILoopValues))> _
<LoopValuesComposition("IBizObjectMetadata")> _
<BizModelMetadataComposition()> _
Public Class BizModelMetadata
Implements IBizModelMetadata
Implements ILoopObjects
See, there’s a LoopValuesComposition attribute!
Some place in meditating on this code, which has my attention as one of the involved places that contains changes since the last time the code worked, I realize “doh!” MEF does not support two strongly typed metadata attributes. In this case BizModelMetadataComposition should derive from LoopValuesComposition and be the only strongly typed metadata attribute. Due to an error in my code, BizModelMetadataComposition contains a different LoopTypeNames property rather than inheriting from LoopValueComposition.
That fixes the problem. But there’s one more thing I need to do (other than writing this blog post). Is this an issue that could be addressed with a change in the tool? In this case I think it is. If it was in a released product, I’d use Connect (get there by Help/Report a Bug in VS 2008). Since it’s a CodePlex project, I use the Issue Tracker feature of CodePlex. I ask the MEF team to consider one of two changes – either merge the data from multiple strongly typed attributes or report a warning/error if you apply two.
Take-aways
If you’re debugging MEF failures, you’re going to have to understand a bit about how MEF works so you can step through its processes. MEF’s strength is the simplicity of just slapping on Export/Import attributes. However, I think it’s naïve to think that’s all you’ll have to understand to use MEF because you simply can’t debug without understanding a bit of MEF plumbing.
MEF debugging takes slightly different thinking than normal debugging. And I find it significantly harder to do. A patient step wise process is a great help. If you step outside this sequence … What’s the next question you need to ask and how are you going to ask it?
I need to return to the red-herring of the inheritance issue, but I’ll do that in another post.
This is a sad story with a happy ending. Mostly anyway.
My laptop has a problem with its graphic drivers (Lenovo T400) and does a hard crash a couple of times a day. Yesterday it corrupted Outlook. While I had numerous other things backed up, I did not have the Outlook pst backed up, at least not recently enough to matter. Imagine losing your email history, calendar and contacts. The calendar was entirely disastrous.
UPDATE: I neglected to mention until someone mentioned it in comments that at this point I ran scanpst.exe from the Outlook directory (find a KB on it here). This tool failed with a message to the effect the file was corrupted and it could not complete. If you have a similar problem, you should definitely try this tool.
I have good friends so I spent the afternoon crying Julie’s shoulder via IM and brainstorming ideas. She found two commercial products: Stellar’s at http://www.repair-outlook-pst.com/ and Advanced Outlook Repair at http://www.datanumen.com/aor/index.htm. Both have demos, and both returned headers and calendar. The demos don’t get your actual messages. Stellar took hours so I decided to buy the most expensive Advanced Outlook Repair. The day was so bad that I got a call at 5:30 asking me why I wasn’t at the Northern Colorado Architects meeting only to say “wait, I was getting ready for the dojo” which I do on Thursday. That’s in spite of the fact I had had three Wednesday appointments and clearly knew it was Wednesday earlier in the day. I’d had it, bagged it, went to the meeting and dinner afterwards, returning to practice my violin (remember, I’m really, really terrible on the violin) trying to get ready for my first ever “Beginner’s Jam” on Friday night.
This morning Bill McCarthy said hello because of an entirely separate conversation we’ve been having over the last few days. I told him I was positively grumpy from having to spend $250 on a PST recovery tool. For any of you that don’t know Bill, he’s brilliant and amazing (but please don’t tell him I said that). I said “so if you don’t have a better idea, I’m about to go spend $250 on this tool, then $650 on an interim laptop so I can get my Lenovo fixed.”
“Aren’t you on Vista” was his reply.
“Yes, and…”
“Right click on the .pst file and select Restore Previous Versions,” he said.
I don’t recall doing anything to this so anticipate running on defaults. I am not feeling optimistic and it takes considerable time to finish…
But I find a pst file from Tuesday. Apparently it’s been backing up my pst file every day at 8:45AM. I can lose one day of email – although it does mean I may have missed your email if you sent it to me late Tuesday or Wednesday.
Bill’s already a hero because he tucked this conversation in amongst fighting Australia’s bushfires. And he’s helped me dozens of times over the years. I feel very thick that my computer has been quietly covering my butt on this and I didn’t realize it, at least not sufficiently for it to rise to my consciousness when I needed it (I do recall now seeing it demo’d).
There are different problems you may have if you run a busy pst file for a long period of time. Julie’s blogged about that here and I had a similar experience a few months ago where the pst stopped allowing me to empty the deleted folder and other ugly things. My solution to that problem, like Julie’s, was to create a new pst file and eventually allow everything to be archived together or via partitioned archives.
Bill didn’t solve the problem that I simply can’t turn loose of my Lenovo to get it fixed (and yes it’s patched with drivers). That one I still have to figure out. At least adequate computers are relatively cheap at the local Office Depot.
I just got back from a private conference in Saskatchewan. I think it’s a good format for many organizations. You won’t get the breadth of cutting edge information that you get at a major conference like DevConnections or DevTeach. But, the conference can be focused on tools and techniques that matter to your organization. Depending on the facilities the cost may be very reasonable. How many speakers you bring in will also affect your cost, and most speakers will have a minimum fee. But as you balance the cost of taking people away from their jobs, it’s worth investing in some quality speakers. Your staff will rarely get the opportunity for such a great “student teacher ratio”. I think this approach is synergistic with sending people to major conferences. Major conferences keep you abreast of the general trends in the industry, but there’s no deep dive relative to your organizations actual challenges.
But while all this is true and private conferences are a great value and investment in your team staying relevant in light of the rapid technology change, I think there’s a more important reason to have a private conference. A private conference is a retreat and a team building exercise. New and experienced staff is in the same room getting to know each other’s strengths and weaknesses. The independent speaker can help challenge status quo worth challenging, and reinforce good things in the organization.
I enjoy doing private conferences because it’s about people not just technology.
Private conferences are all about strengthening your organization. So as you look at your budget for the coming year, consider whether an internal conference is a good addition.
I just spent days tracking this one down, so let me try to save someone else the grief.
Symptoms: My Silverlight application suddenly started doing a full compiler crashes and brings down Visual Studio crash every time I tried to compile. Cleaning the solution didn’t help. Manually cleaning solution and user files didn’t help.
The Visual Studio solution has about fifteen projects. It’s a Silverlight app with the client and server pieces in one solution. I am using mobile objects, meaning I have Silverlight libraries that contain files that were added using “Add As Link” so the same code appears in both the Silverlight and .NET assemblies. Other than these complexities, it’s not a terribly complex app.
Problem: I ultimately determined that the problem was that I moved files in the .NET project breaking the links within the Silverlight project (the .NET project holds the actual code). I replaced the links with new links to the correct files, but the old links remained. Once I drilled down to the correct directory, it was very easy to see that these files were marked as invalid. And yes, there were error messages that I didn’t see buried in the mess of other errors.
Fix: Remove the bad links.
Obviously I did a dumb thing, and obviously Visual Studio should never crash this badly no matter how badly I screw up.
I have submitted this to Microsoft, but thought I’d also get it up on the web in hopes of saving someone else some time.
I hate spam. You hate spam. We all hate spam.
A year or so ago, one of my ISPs began managing spam by not sending it to me. I balked and downplayed the use of that email address. The idea of missing an important email freaked me out.
But the spam has gotten worse, and my sensitivities have shifted. Spam sitting on servers and backups takes up space. Space on disk is energy. And kathleen@mvps.org has been a public email address for over ten years. You can imagine I get a lot of spam. Space on my disk doesn’t really matter. It doesn’t change the size of disk I buy. But the management of spam on servers does take energy.
This year when mvps.org announced that they would begin refusing spam, I understand and support the move. Their gate blocks the spam. I think they waited on this until they felt they had decent technology. Decent technology is unlikely to be perfect.
This may impact you if you’re trying to contact me. If you get a “rejected as spam” message, try another approach, including IM, calling me, contacting me through this blog, or leaving a comment. I can easily whitelist you; I just need to know if you’re being rejected. So far I know of two messages that have been rejected. One is someone that contacts me regularly and I have no clue why he went into the spam bucket. But, the problem solved itself within the magic spam logic. The other was a friend who thought a particular piece of spam was funny so he forwarded it to me. Cool. Rejected on content. I liked that and I didn’t think it was all that funny when he told me about it.
Assuming your ISP is doing what it should, you’ll get a rejection message based on the rejection from the mvps server. But neither mvps nor I can do anything about whether your server actually informs you of the rejection. If I don’t answer, and you think I would have answered, you’ll have to try again. Don’t take it personally.
If we are exchanging email after sometime this month when they turned the filters on, everything is fine. But even if we exchanged email before that, we could see a problem.
In order to combat spam, more servers internal and external are going to take draconian measures. I can’t get a report, it’s not in my junk folder (not that I’d be that good at manually scanning the hundreds of spam messages I get a day). The world has changed, and each of us is going to have to take a little effort to ensure important email is delivered.
And thanks to the awesome folks at mvps.org for taking such amazing care of me and my email for the last ten years. They manage many extremely public– as in highly spammed – accounts and do a great job. Community often appears just as the façade of people and faces you hear. But community is also a vast network of quieter engines driving the process – for me that includes mvps.org, msmvps.com, and ineta.org. Thanks to the volunteers that keep these running.
This stinks. But I think it’s the best solution today and ask for your patience and perseverance if you need to contact me.
Today in church we honored Martin Luther King by looking beyond him to others in the movement, including the Reverend James Reeb.
Someone wrote in the Joys and Concerns book (I paraphrase) “that my 7 year old may never fully understand the magnitude of what will happen on Tuesday is how we measure how much has changed.”
This is a moment in time worth savoring, especially for those of us that believed it would not come in our lifetime.
As you savor it, consider that there are many verses to “We Shall Overcome. “ They include “We shall walk as one”, “We shall all be free”, and “We shall live in peace.”
In the Bush years, I turned my TV off. The implications of giving up our rights for a false sense of safety, for seeing failure at every level of government oversight, for seeing the government fail to guard the life of every serviceman and Iraqi,for seeing the reins of our government treated frivolously – these things twisted my stomach in a way that I could only turn away from.
Today, freedom, unity, and peace, especially worldwide seem impossible goals - but the I believed Tuesday would not come. If Barrack Obama will be president, what else is possible if we work together? If we are willing to risk working against the status quo, even when the risks are very real.
Remember the other verses, remember the other dreams. This must be only the beginning.We have the new battles with health care and the economy, but let us not lose sight of the old battles: peace, liberty and justice for all.
In Code Complete Steve McConnell looked at core values for programming some fifteen years ago and came up with this list:
- Intelligence
- Humility
- Curiosity
- Intellectual honesty
- Communication and cooperation
- Creativity
- Discipline
- Laziness
And two that McConnell said don’t matter as much as you might think:
I’m doing a talk for INETA (see note) called “Rethinking Object Orientation” which looks another book of the time – Grady Booch’s Object Oriented Design. Our world has changed so fundamentally that the ideals and focus presented in Object Oriented Design have changed, and that’s the core of my talk (the new things that matter). I think the same is true of core values - we need to rethink them.
Rethinking does not mean discarding. That chapter of McConnell’s book is still a good read every year or so. Rethinking means considering in today’s context. I’ll share my thinking but I need a huge caveat here: I rethink my core values and allow them to evolve as I learn and grow.
From OpenSpace.com, comes this:
Open Space Technology runs on two fundamentals: Passion and responsibility. Without passion, nobody is interested. Without responsibility, nothing will get done…If passion isn’t aroused, not much is going to happen, and responsibility will never have a chance.
Just Open Space? What about relationships? What about business? What about code? What about you?
Passion and responsibility must be part of our core values. What should we be passionate about and among the hundreds of possible responsibilities, where should we focus our energy?
Those are the good questions, and thinking about them led me to understanding a few more core values:
- Individual knowledge and skills
- Community knowledge
We must openly and directly stand on the shoulders of giants and acknowledge this to move ahead. One of the most difficult things in acquiring and maintaining individual knowledge and skills is that the body of community knowledge is so immense. If we do not constantly strive to better both, we will not succeed in writing meaningful software.
If we return to McConnell’s list, many features do not seem to be as important today.
For example; it’s popular to announce pride in being a lazy programmer. Not one person that I’ve heard say that was actually lazy. Looking for efficiency is not lazy. And laziness leads to the worst aspect of our industry: Ctrl-C/Ctrl-V.
Learning new things is important, but curiosity needs to be tempered with an enormous amount of responsibility. If you spend 80 hours a week learning new things, and you are brilliant, you will still not keep up with all the new advances in our industry.
Other things from McConnell’s list seem even more important today.
Humility is hugely important. It is why I’ve run crosswise of people that just pissed me off because they believed they had the “true answer.” There is no true answer, everyone is learning, and thank god we have 9-5 programmers.
Honesty is essential. It has always been essential. If you are in a programming environment where it is not OK to say “I don’t know” and “I was wrong”- run away. The environment is too toxic to survive.
I disagree with McConnell that experience and persistence are not as important as you might think.
If you read all of what McConnell says on experience, it’s clear he means is that simply counting years isn’t enough. Of course requesting five years of VB or C# experience is stupid. If you’ve been writing 1.0 code for five years, you have far, far less value than if you have one year embedded in generics, lambda expressions, LINQ, and the new libraries (WPF, WCF, Silverlight, etc).
But, the lack of respect for experience is holding our industry back. People are rediscovering things that have already been done. The act of rediscovery is exciting and sometime new thinking on old problems emerges. Alongside that, we lose the nuances that have already been uncovered. I am not espousing this as a gray haired old woman pouting that you’re not listening to me (a future blog post perhaps). I learn from people in this industry that are half my age but more experienced in some things. Those of us that are old, however, sense the fundamental truths. Unless we can ever write those in a book, which seems unlikely, both technology experience and long term passionate involvement in our industry have much to teach us.
I have the privilege of learning from my sons. My older one is a brilliant coder who grew up intimate with this industry. I told him once what I thought were important characteristics in a programmer – he said “nope, your wrong. The only important characteristic in a good coder is stubbornness.” I do not believe it is the only important characteristic, but it is an important one. In today’s world, we slog through code. We spend months or years on the same project. We debug in convoluted systems. While we sometimes need to find another way to solve a problem that is easier, it takes stubbornness in believing that problem will be solved to find the other route. And learning any technology takes patience and tenacity.
Those are my views. Take some time to consider your core values as a programmer. Take some time to see if those core values contribute to your programming life being what you desire.
More Posts
Next page »