tag:blogger.com,1999:blog-69595828396909580352024-03-14T03:16:55.963-04:00public void Life(){
throw new NotImplementedException();
}testhttp://www.blogger.com/profile/09609860522747123959noreply@blogger.comBlogger142125tag:blogger.com,1999:blog-6959582839690958035.post-48098013973145276262014-12-03T08:49:00.000-05:002014-12-03T09:07:19.891-05:00A Case Against CommentsWant to hear something opinionated? Comments are a code smell. There, I said it. And I don't apologize for it.<br />
<br />
All comments? Well, maybe not necessarily. I'll concede that there are exceptions to the rule. Header comments which drive intellisense can be useful, for example. Though, seriously, they don't need to be on <i>everything</i>. I'll also concede that once in a while there's an exception to the rule where the purpose behind a particular implementation could require a little more explanation. Comments like, "We use the magic value 3 here because Vendor X's product requires that. Don't let this magic value leak from this dependency implementation." for example.<br />
<br />
But by and large nearly all of the comments I see in real-world code are a code smell. Why? Because they don't add value. They take up space (not as a measure of bytes in the file, but as a measure of time spent understanding and supporting the code), they clutter the code, and they offer no information that the code shouldn't already have.<br />
<br />
I can already hear the responses from every manager, owner, alleged developer, etc... "But without comments how will we know what the code is doing?" As usual, someone else has said it better than I can:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhOxdlQ3JNmYhSd2BnqR6GOhZa75n9wwClvhf6ceKkL5rtj6rSptQoA5VvFdqUHAyGwZWJgjI7wUlMQ0mRL0s4THFfaxGkfoN3j35h_gRZUiEzQH-Z9vAWKG_YhflNrF1sUGTjV3tzzGbbl/s1600/tweet.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhOxdlQ3JNmYhSd2BnqR6GOhZa75n9wwClvhf6ceKkL5rtj6rSptQoA5VvFdqUHAyGwZWJgjI7wUlMQ0mRL0s4THFfaxGkfoN3j35h_gRZUiEzQH-Z9vAWKG_YhflNrF1sUGTjV3tzzGbbl/s1600/tweet.PNG" height="169" width="400" /></a></div>
<div style="text-align: left;">
That's the gist of it, really. If a developer on the team isn't able to convey the business logic in a structured and meaningful way, what good are that developer's comments going to be? Does that developer even understand what he or she is writing? If not, aren't those comments just going to add more confusion and misinformation?<br />
<br />
<a href="http://www.objectmentor.com/omTeam/martin_r.html">Robert Martin</a> has been known to say, "Every comment is an apology." That apology is basically the developer saying that he or she wasn't able to express the meaning in the code, so he or she gave up and just wrote the meaning in comments instead. It's just that... giving up.<br />
<br />
My own take on it is, "Every comment is a lie waiting to happen." That is, either the comment is saying something that the code <i>isn't</i> saying (so it's lying) or the code is going to change at some point and invalidate what the comment is saying (so it will be lying).<br />
<br />
(And please don't say that we can simply enact a policy whereby developers must update the comments when they update the code. And those updates must be peer reviewed and documented and all that nonsense. Policies like that demonstrate only one thing, that the people enacting those policies have no <i>actual meaningful</i> experience leading a team of software developers.)</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Think of it this way...</div>
<blockquote class="tr_bq">
<div style="text-align: left;">
When you're reading code with lots of comments, do both the code and the comments unambiguously tell the same story?</div>
</blockquote>
<div style="text-align: left;">
If not, which one tells the correct story? Which one <i>should</i> tell the correct story? And why should the <i>incorrect</i> story <i>also</i> be told?<br />
<br />
If they <i>do</i> both unambiguously tell the same story, then why does that story need to be told twice? Doesn't that violate <a href="http://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY</a>? What happens when one of their stories changes? Will the other change in the exact same way?<br />
<br />
The story need only be told once. Tell it in the code.</div>
testhttp://www.blogger.com/profile/09609860522747123959noreply@blogger.com1tag:blogger.com,1999:blog-6959582839690958035.post-36026165641366446182014-09-18T19:03:00.003-04:002014-09-18T19:03:41.820-04:00Being Right Isn't EnoughAs engineers we are often faced with a very common problem. How do we convince "business people" that we're right? It seems we're always at odds with each other, doesn't it? Us vs. them? Any avid reader of Dilbert will tell you that we engineers <em>know what we’re talking about</em> and, in fact, <em>that’s why they hired us</em>. So why won't these "business people" listen to us?<br />
<br />
I'm going to let you in on a little secret… They <em>do</em> listen to us. They simply disagree with the position as we've presented it. Sure, all our facts may be correct. Sure, our opinions may be valid. But the conclusion, the <em>call to action</em>, doesn’t resonate. It's not that "they" are incompetent or malicious, it's simply that "we" (which includes <em>both</em> "us" and "them") haven't reached a mutually agreeable course of action. (Caveat: Ok, I'll concede that there are some people out there in positions of authority who are incompetent or malicious or who simply don't want to listen to you. There's not much you can do about those ones. The only advice I can offer in that case is to take your leave of the situation. Create an exit strategy, enact that strategy, and go find something else that doesn't endlessly frustrate you.)<br />
<br />
So, if they're listening to us, why aren't they agreeing with us? How can we impress upon them the <em>need</em> to agree with us? Well, that depends on that call to action and where "they" see that action taking the team. If you're not familiar with Stephen Covey's Time Management Grid, you should be. (Not just because I'm going to be referencing it a lot here, but also because... well... <em>you should be</em>.) It's a simple grid with two axes, one for "urgency" and once for "importance." And the combinations of those axes result in four well defined quadrants:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_m5_sbUp26a-2vEjDKWwTB5szfoWTjtBLON9YVo1eDjk6r4LM3vCs_OWus_k8HUMeuFQcgZwC-GimcgNyTTCRJku-1HhyphenhyphenI-ZId0mtIWY7_777MRhM3tE2IsdGhtY3eK9RD42x1PTDTSjt/s1600/1+-+Chart.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_m5_sbUp26a-2vEjDKWwTB5szfoWTjtBLON9YVo1eDjk6r4LM3vCs_OWus_k8HUMeuFQcgZwC-GimcgNyTTCRJku-1HhyphenhyphenI-ZId0mtIWY7_777MRhM3tE2IsdGhtY3eK9RD42x1PTDTSjt/s1600/1+-+Chart.png" height="317" width="400" /></a></div>
<div style="text-align: center;">
<br /></div>
<br />
Imagine for a moment that any given work item, anything you do as part of your job, falls into one of those four quadrants. For each item, where do you think it goes? Where do you <em>want</em> it to go? Which quadrant contains the things you want to work on? Which contains the things you want to avoid? The grid makes those distinctions pretty clear:<br />
<ul>
<li><strong>Quadrant 1, Manage:</strong> These are the things that need to happen, and they need to happen right now. Production systems have errors and downtime, and fixing them is an immediate need. There are emergencies to resolve, fires to put out, etc. This is where critical decisions need to be made and success needs to be reached. Of course, you don't want to <em>always</em> be here because it means you're always in a hurry, always pressured.</li>
<li><strong>Quadrant 2, Focus:</strong> These are the things that need to happen, but not right away. Investments in the future of the company, improvements to prepare for long-term strategic goals, etc. <em>This</em> is where you want to spend your time. This is where you work on rewarding things without being yelled at and pressured to cut corners.</li>
<li><strong>Quadrant 3, Avoid:</strong> These are things which need to be fixed right now, but shouldn't even be a problem in the first place. This is where you <em>do not</em> want to be. This is the quadrant of work where you're pressured for results on things nobody actually cares about.</li>
<li><strong>Quadrant 4, Limit:</strong> This is a fun little quadrant of things you might like to do but which don't necessarily provide measurable value to the business. (Google made a fortune off of this quadrant by encouraging employees to create their own projects, just FYI.) You want to spend some time here, but not a whole lot. Too much time here means nobody's doing anything important to the business.</li>
</ul>
Now let's think back to that problem of trying to convince "them" that you are "right." How does this grid help us? Well, now that you know where your work items belong on this grid, try also to imagine where your <em>proposed</em> work items belong. That thing you're trying to convince management to invest in... Where does it fit on the grid? And where do "they" think it fits? Step outside of the debate with "them" for a moment and imagine where on this grid you think they are, and where on this grid they think you are. Clearly you both <em>want</em> to be in Quadrant 2 (Focus). But neither of you thinks the other person is there. So how do <em>you</em> convince <em>them</em> that you are in Quadrant 2?<br />
<blockquote>
Tailor your position, and your call to action, based on the axis of movement from where they think you are to where they want you to be.</blockquote>
Let's take a classic example. You're working at a company with an established production system. As an engineer, you see all the problems. The code is a mess, the dependencies are unmanaged, support is difficult and there's too much of it... Technical debt is piling up ever higher. But the thing is, the system <em>works</em>. The business is making money. So, as often happens in these situations, there's no incentive from "them" to invest in improvements to a system that already does what they need it to do. "If it ain't broke, don’t fix it."<br />
<br />
But you're the lead software engineer. You're the guy they hired for the specific purpose of ensuring this system continues to work and can continue to meet changing business needs. So why aren't they listening to you when you explain the things that need to be fixed? Because they see you in the wrong quadrant...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7VEstDJ972kpKoAMdVGso6RA1UZ7uI3jwj4PUIVLITl5gLM-77-KOmZZ7X8hu_-JFTSeEduHo5Gk4K8UQqDZKMNNF3OlgWnRcFJFXpH4KyhmQiQ_3Xuaog_ygOs3ldcHyDVjpmwUI2XN0/s1600/2+-+Where+they+think+you+are.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7VEstDJ972kpKoAMdVGso6RA1UZ7uI3jwj4PUIVLITl5gLM-77-KOmZZ7X8hu_-JFTSeEduHo5Gk4K8UQqDZKMNNF3OlgWnRcFJFXpH4KyhmQiQ_3Xuaog_ygOs3ldcHyDVjpmwUI2XN0/s1600/2+-+Where+they+think+you+are.png" height="318" width="400" /></a></div>
<div style="text-align: center;">
<br /></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhycYM2hTWYJZ2ZRUdUErFFEJlHJ58gfPEmM6ahJrSdVZMTsUGOBVMnjIzSx0CwYv2mmuvFK2pC032PSkghRADC9VWWnZAfumOlcCe4h6r7_IOv-NmFKPkkrP8S5_PDDdXTBNMYC9iaz20h/s1600/3+-+Where+you+think+they+are.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhycYM2hTWYJZ2ZRUdUErFFEJlHJ58gfPEmM6ahJrSdVZMTsUGOBVMnjIzSx0CwYv2mmuvFK2pC032PSkghRADC9VWWnZAfumOlcCe4h6r7_IOv-NmFKPkkrP8S5_PDDdXTBNMYC9iaz20h/s1600/3+-+Where+you+think+they+are.png" height="318" width="400" /></a></div>
<div style="text-align: center;">
<br /></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirNG1LvQy3RqQ7INVxZGrsyJGEMVe2_KBwKFiWoq105UmBEDWjteAX_0yKXyX1r7mJ-dn7zXUNDPoMt9l9o8avuFeDlJxO01rLjKDQbfRmFAs4TFxgDsShDoX8FICMAgms5EkdAUyP0tkf/s1600/4+-+Where+you+want+to+be.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirNG1LvQy3RqQ7INVxZGrsyJGEMVe2_KBwKFiWoq105UmBEDWjteAX_0yKXyX1r7mJ-dn7zXUNDPoMt9l9o8avuFeDlJxO01rLjKDQbfRmFAs4TFxgDsShDoX8FICMAgms5EkdAUyP0tkf/s1600/4+-+Where+you+want+to+be.png" height="318" width="400" /></a></div>
<div style="text-align: center;">
<br /></div>
<br />
You think they're in Quadrant 1, only seeing the immediate concerns and waiting for something to "become a problem" before they solve it. They think you're in Quadrant 4, trying to convince the company to invest in something that is neither urgent nor important. How do you fix that?<br />
<br />
Consider how these debates often play out. You talk about time tables, about how things are going to fail if we don't act soon. You're appealing to <em>urgency</em> in this argument. But if they think you're in Quadrant 4, where does an appeal to urgency make it look like you're going?<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8pbEWRfZNK7tEmEhIWBo6gEfHAbvousJNYNFqjYD5QYP25inLtqT3kbdZ2kEYK1Skr8X0ua0NzW15yseOkuppTR9EL0YfxPk5zebwGvqdAofI7nXlKAZELm7Hb9ZqjAzsFH93ODz9gt5j/s1600/5+-+Where+they+think+you+are+going.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8pbEWRfZNK7tEmEhIWBo6gEfHAbvousJNYNFqjYD5QYP25inLtqT3kbdZ2kEYK1Skr8X0ua0NzW15yseOkuppTR9EL0YfxPk5zebwGvqdAofI7nXlKAZELm7Hb9ZqjAzsFH93ODz9gt5j/s1600/5+-+Where+they+think+you+are+going.png" height="318" width="400" /></a></div>
<div style="text-align: center;">
<br /></div>
<br />
In that case it's pretty clear why they're against the idea. They see you as moving into the very quadrant where nobody should ever be. The argument they might present in response is to stress how your goals don't necessarily align with the business. How you're not seeing the big picture. What does that look like?<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgk3a4ny8x1iEQZWr5XeesqxYezXLbqbYLaK3VTV8QiRDoXk-LWgYQ0aJB9_OcE16Cw-uQPhqguY19QBJIFwYgGWTP9fsP02zWs1lPnR2axDsCoQ6kjRW_DlpfaaH30TXgN8a2dsXGeQ1MM/s1600/6+-+Where+you+think+they+are+going.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgk3a4ny8x1iEQZWr5XeesqxYezXLbqbYLaK3VTV8QiRDoXk-LWgYQ0aJB9_OcE16Cw-uQPhqguY19QBJIFwYgGWTP9fsP02zWs1lPnR2axDsCoQ6kjRW_DlpfaaH30TXgN8a2dsXGeQ1MM/s1600/6+-+Where+you+think+they+are+going.png" height="318" width="400" /></a></div>
<div style="text-align: center;">
<br /></div>
<br />
Clearly that's equally distasteful to you. You see <em>them</em> as moving into the very quadrant where nobody should ever be. The debates aren't reaching a middle ground because both sides are moving along different axes, appealing to entirely different measures of the decision. Assuming that you can't change their position, you need to instead present <em>your</em> position in a way which aligns with theirs.<br />
<br />
In the example we've been discussing, this means appealing to <em>importance</em> rather than <em>urgency</em>. You and I both know that these fixes to the system need to happen soon, perhaps even now. But that's not what's being discussed. So table the discussion on urgency until another time. If the decision-maker you're trying to convince is varying along the axis of importance, then focus on that axis. Appeal to the importance. In this example that could be a matter of discussing the operational costs of support, or discussing the strategic goals of the system (scaling, additional features, etc.) and what it would take to achieve those goals. What might a goal cost in the current system? What might it cost with some fixes in place first? What might those fixes cost? And so on.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKA_sQh8WqDUfJLRrmYoyeBXFbQ17PojG1YQmZehEURgMV8EJnUfNcykhfOyl3Vh5iYphuLaFtg17JxseEaD2V033K-adcfQ9Aqi9Z4xZSTGFtabB8LVBjsJfoVnGh-QGgWeNZcgOMZ2DS/s1600/7+-+You+are+going+this+way.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKA_sQh8WqDUfJLRrmYoyeBXFbQ17PojG1YQmZehEURgMV8EJnUfNcykhfOyl3Vh5iYphuLaFtg17JxseEaD2V033K-adcfQ9Aqi9Z4xZSTGFtabB8LVBjsJfoVnGh-QGgWeNZcgOMZ2DS/s1600/7+-+You+are+going+this+way.png" height="315" width="400" /></a></div>
<div style="text-align: center;">
<br /></div>
<br />
Since "they" think that "they" are already in Quadrant 2, if "you" can convince "them" that you are driving <em>toward</em> Quadrant 2 then that puts you both on common ground. That drives toward a mutually agreeable course of action. Tailor your position to the direction they want you to move, not the direction you think they're moving. This helps bridge that gap from "us <em>vs.</em> them" to "us <em>and</em> them" which is a much more productive team dynamic.testhttp://www.blogger.com/profile/09609860522747123959noreply@blogger.com0tag:blogger.com,1999:blog-6959582839690958035.post-47996609617234463772014-06-20T15:30:00.003-04:002014-06-20T15:42:18.012-04:00Fun with Expression TreesA common pattern I find in my MVC/WebAPI code is that my controller actions usually open a unit of work (or just a read-only repository therein), perform some query or insert/update something, and then return. It's a simple thing to expect a controller action to do, after all. But sometimes I come across an entity model where it's a bit difficult to put much of the logic on the model, and instead it ends up in the controller actions.<br />
<br />
For example, imagine a system where your models are a fairly complex graph of objects, versions of those objects, dynamic properties in the form of other child objects, versions therein as well, etc. It's a common pattern when one builds a framework in which to configure an application, as opposed to building just an application itself.<br />
<br />
Now in this system, imagine that you want all of your queries against "Entity" models to always ever return just the ones which have not been soft-deleted. (Viewing soft-deleted records would be a special case, and one we haven't built yet.) Well, if you have a lot of queries against those entities in their repository, those queries are all going to repeat the same ".Where()" clause. Perhaps something like this:<br />
<br />
<pre class="brush: csharp">
return someRepository.Entities
.Where(e => e.Versions
.OrderByDescending(v => v.VersionDate)
.FirstOrDefault()
.Deleted != true))
.Where(// etc.
</pre>
<br />
That is, you only ever want Entity records where the most recent Version of that Entity is not in a "Deleted" state. It's not a lot of code (at least, not in this simplified example), but it is repeated code all over the place. And for more complex examples, it's a lot of repeated code. And more importantly than the repetition, it's logic which conceptually belongs on the model. A model should be aware of whether or not it's in a "Deleted" state. The controller shouldn't necessarily care about this, save for just invoking some logic that exists on the model.<br />
<br />
At first one might simply add a property to the Entity model:<br />
<br />
<pre class="brush: csharp">public bool IsDeleted
{
get { return Versions.OrderByDescending(v => v.VersionDate)
.FirstOrDefault()
.Deleted != true; }
}
</pre>
<br />
Then we might use it as:<br />
<br />
<pre class="brush: csharp">return someRepository.Entities
.Where(e => !e.IsDeleted)
.Where(// etc.
</pre>
<br />
That's all well and good from an object oriented perspective, but if you're using Entity Framework (and I imagine any number of other ORMs) then there's a problem. Is the ORM smart enough to translate "IsDeleted" to run it on the database? Or is it going to have to materialize every record first and then perform this ".Where()" clause in the code? (Or just throw an error and not run the query at all?) Most likely the latter (definitely the latter with Entity Framework in this case), and that's no good.<br />
<br />
We want as much query logic as possible to run on the database for a number of reasons:<br />
<ul>
<li>It's less data moving across the wire.</li>
<li>It's a smaller memory footprint for the application.</li>
<li>SQL Server is probably <i>a lot</i> better at optimizing queries than any code you or I write in some random web application.</li>
<li>It's a lot easier and more standard to horizontally scale a SQL Server database than a custom application.</li>
</ul>
So we really don't want to materialize all of the records so that our object oriented models can perform their logic. But we <i>do</i> want the logic itself to be defined on those models because, well, object oriented. So what we need on the model isn't necessarily a property, what we need is an expression which can be used in a Linq query.<br />
<br />
A first pass might look something like this:<br />
<br />
<pre class="brush: csharp">
public static Func<Entity, bool> IsNotDeleted = e => e.Versions
.OrderByDescending(v => v.VersionDate)
.FirstOrDefault()
.Deleted != true;
</pre>
<br />
Which we can then use as:
<br />
<br />
<pre class="brush: csharp">
return someRepository.Entities
.Where(Entity.IsNotDeleted)
.Where(// etc.
</pre>
<br />
This is a good first step. However, if you profile the SQL database when this executes you'll find that the filtering logic still isn't being applied in the SQL query, but rather still in-memory in the application. This is because a "Func<>" doesn't get translated through Linq To Entities, and remains in Linq To Objects. In order to go all the way to the database, it needs to be an "Expression<>":
<br />
<br />
<pre class="brush: csharp">
public static Expression<Func<Entity, bool>> IsNotDeleted = e => e.Versions
.OrderByDescending(v => v.VersionDate)
.FirstOrDefault()
.Deleted != true;
</pre>
<br />
Same code, just wrapped in a different type. Now when you profile the database you'll find much more complex SQL queries taking place. Which is good, because as I said earlier SQL Server is <i>really good</i> at efficiently handling queries. And the usage is still the same:
<br />
<br />
<pre class="brush: csharp">
return someRepository.Entities
.Where(Entity.IsNotDeleted)
.Where(// etc.
</pre>
<br />
Depending on how else you use it though, you'll find one key difference. The compiler wants to use it on an "IQueryable<>", not things like "IEnumerable<>" or "IList<>". So it's not a <i>completely</i> drop-in replacement for in-code logic. But with complex queries on large data sets it's an enormous improvement in query performance by offloading the querying part to the database engine.<br />
<br />
There was just one last catch while I was implementing this. In <i>some</i> operations I want records which are "Deleted", and in <i>some</i> operations I want records which are <i>not</i> "Deleted". And obviously this doesn't work:
<br />
<br />
<pre class="brush: csharp">return someRepository.Entities
.Where(!Entity.IsNotDeleted)
.Where(// etc.
</pre>
<br />
How should one invert the condition then? I <i>could</i> create a second expression property called "IsDeleted", but that's tacky. Not to mention it's still mostly repeated logic that would need to be updated in both places should there ever be a change. And honestly, even this "IsNotDeleted" bothers me from a Clean Code perspective because positive conditionals are more intuitive than negative conditionals. I <i>should</i> have an "IsDeleted" which can be negated. But how?
<br />
<br />
Thanks to some help from good old <a href="http://stackoverflow.com/q/24316284/328193">Stack Overflow</a>, there's a simple way. And it all comes down to, again, expression trees. Essentially what's needed is an extension which wraps an expression in a logical inverse. This wrapping of the expression would continue through the expression tree until it's translated at the source (SQL Server in this case). Turns out to be a fairly simple extension:
<br />
<br />
<pre class="brush: csharp">public static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> f)
{
return Expression.Lambda<Func<T, bool>>(Expression.Not(f.Body), f.Parameters);
}
</pre>
<br />
See, while there's no ".WhereNot()" or ".Not()" in our normal Linq extensions, there is one for Expressions. And now with this we can wrap our expression. First let's make it a positive condition:
<br />
<br />
<pre class="brush: csharp">
public static Expression<Func<Entity, bool>> IsDeleted = e => e.Versions
.OrderByDescending(v => v.VersionDate)
.FirstOrDefault()
.Deleted == true;
</pre>
<br />
Now let's get records which are deleted:
<br />
<br />
<pre class="brush: csharp">return someRepository.Entities
.Where(Entity.IsDeleted)
.Where(// etc.
</pre>
<br />
And records which are not deleted:
<br />
<br />
<pre class="brush: csharp">return someRepository.Entities
.Where(Entity.IsDeleted.Not())
.Where(// etc.
</pre>
<br />
Profile the database again and we see that all of the logic is still happening SQL-side. And for the inverted ones, the generated SQL query just wraps the whole condition and negates it exactly as we'd expect it to.
<br />
<br />
Now, we can still have our calculated properties on our models and we can still do a lot with those models in memory once they're materialized from the underlying data source. But in terms of just querying the data, where performance is a concern (which isn't always, admit it), having some expression trees on our models allows us to still encapsulate our logic a bit while making much more effective use of the ORM and database.testhttp://www.blogger.com/profile/09609860522747123959noreply@blogger.com0tag:blogger.com,1999:blog-6959582839690958035.post-41984011415546149542014-05-21T19:30:00.000-04:002014-05-21T19:30:06.080-04:00Continuous Integration with TFS and ClickOnceMy current project is pretty fast-paced, so we need some good infrastructure to keep mundane concerns out of our way. As an advocate of eliminating cruft in the development process, I naturally wanted to implement a fully-automated continuous integration setup with building, testing, and publishing of the applications involved. Everybody's done this plenty of times with web applications, but it turns out that it's not quite so common with databases and <i>ClickOnce</i> applications. Since all three are included in this project, this is as good a time as any to figure out how to unify them all.<br />
<br />
First some infrastructure... We're using Visual Studio 2013, SQL Server (different versions, so standardizing on 2008R2 as a target), and TFS. (I'm actually not certain about the TFS version. It's definitely latest or close to it, but not really being a "TFS guy" I don't know the specifics. It just works for what we need, I know that much. Beyond that, the client owns the actual TFS server and various controllers and agents.)<br />
<br />
The entire solution consists of:<br />
<ul>
<li>A bunch of class libraries</li>
<li>A WebAPI/MVC web application</li>
<li>A WPF application</li>
<li>A bunch of test projects</li>
<li>A database project (schema, test data)</li>
</ul>
<div>
The goals for the build server are:</div>
<div>
<ul>
<li>A continuous integration build which executes on every check-in. (We're actually using gated check-ins too. I don't like gated check-ins, but whatever.)</li>
<li>A test build which executes manually, basically any time we want to deliver something to QA.</li>
</ul>
<div>
And each build should:</div>
</div>
<div>
<ul>
<li>Compile the code</li>
<li>Execute the tests</li>
<li>Deploy the database</li>
<li>Deploy the web application (with the correct config file)</li>
<li>Deploy the ClickOnce WPF application (with the correct config file)</li>
</ul>
<div>
Some of this is pretty much out-of-the-box, some of it very much is not. But with a little work, it's just about as simple as the out-of-the-box stuff. So let's take a look at each one...</div>
</div>
<div>
<br /></div>
<div>
<b>Compile The Code</b></div>
<div>
<b><br /></b></div>
<div>
This one is as out-of-the-box as it gets. I won't go into the details of creating a build in TFS, there's no shortage of documentation and samples of that and it's pretty straightforward. One thing I did do for this process, however, was explicitly define build configurations in the solution and projects for this purpose. We're all familiar with the default Debug and Release configurations. I needed a little more granularity, and knew that the later steps would be a lot easier with distinct configurations, so I basically deleted the Release configuration from everything and added a CI and a Test configuration. For now all of their settings were directly copied from Debug.</div>
<div>
<br /></div>
<div>
I used the default built template, and set each respective build (CI and Test) to build the solution with its configuration (Any CPU|CI and Any CPU|Test). Simple.</div>
<div>
<br /></div>
<div>
<b>Execute The Tests</b></div>
<div>
<b><br /></b></div>
<div>
Again, this one is built-in to the TFS builds. Just enable automated tests with the build configuration and let it find the test assemblies and execute them.</div>
<div>
<br /></div>
<div>
Here's where I hit my first snag. I saw this one coming, though. See, I'm a stickler for high test coverage. 100% ideally. (Jason, if you're reading this... let it go.) We're not at <i>100%</i> for this project (yet), but we are pretty high. However, at this early stage in the project, a significant amount of code is in the Entity Framework code-first mapping files. How does one unit test those?</div>
<div>
<br /></div>
<div>
The simplest way I found was to give the test assembly an App.config with a valid connection string and, well, use the mappings. We're not testing persistence or anything, just mapping. So the simplest and most direct way to do that is just to open a unit of work (which is just a wrapper for the EF context), interact with some entities, and simply dispose of the unit of work without committing it. If valid entities are added to the sets and no exceptions are thrown, the mappings worked as expected. And code coverage analysis validates that the mappings were executed during the process.</div>
<div>
<br /></div>
<div>
However, this is technically an <i>integration</i> test in the sense that EF requires the database to exist. It does some inspection of that database for the initial mappings. That's kind of what we're testing, so we kind of need a database in place. Perhaps we could write some custom mock that pretends to be a SQL database, but that sounds overly-complicated. For the simplest approach, let's just see if we can deploy the database as part of the build. The upside is that this will validate the database schema as part of the build anyway, which is just more automated testing. And automated testing is a good thing.</div>
<div>
<br /></div>
<div>
So...</div>
<div>
<br /></div>
<div>
<b>Deploy The Database</b></div>
<div>
<b><br /></b></div>
<div>
A lot has changed in SQL Server projects between Visual Studio 2010 and Visual Studio 2012/2013. The project itself doesn't respect build configurations like they used to. But there's a new mechanism which effectively replaces that. When you right-click on the database project to publish it, you can set all of your options. Then you can <i>save</i> those options in an XML file. So it seemed sensible to me to save them in the project, one for each build configuration. (From then on, publishing from within Visual Studio just involves double-clicking on the XML file for that publish configuration.)</div>
<div>
<br /></div>
<div>
These XML files contain connection strings, target database names, any SQL command variables you want to define, and various options for deployment such as overwriting data without warning or doing incremental deploys vs. drop-and-create deploys. Basically anything environment-specific about your database deployments.</div>
<div>
<br /></div>
<div>
Now we need the TFS builds to perform a database publish. Since TFS builds are basically a TFS workflow surrounding a call to MSBuild, adding MSBuild arguments in the build configuration seemed like a simple way to perform this with minimal effort. First I included the Publish target for the build:</div>
<blockquote class="tr_bq">
/t:Build /t:Publish</blockquote>
Then I also needed to specify to deploy the database and which publish file to use:<br />
<blockquote class="tr_bq">
/t:Build /t:Publish /p:DeployOnBuild=true /p:SqlPublishProfilePath=CI.publish.xml</blockquote>
I'm actually not <i>entirely</i> sure at this point if all of those are necessary, but it works well enough. We're targeting both Build and Deploy for the build actions and setting a couple of project properties:<br />
<ul>
<li>DeployOnBuild - This is the one about which I'm not entirely certain. This setting doesn't exist in my project files in source control, but it seems to be the setting needed for the SQL Server project to get it to publish. (Or maybe it's used by one of the other projects by coincidence? This was all a bit jumbled together while figuring it out so that's certainly possible.)</li>
<li>SqlPublishProfilePath - This is a setting in the SQL Server project file to tell it which of those XML files to use for its publish settings.</li>
</ul>
<div>
This executes as part of the MSBuild step and successfully deploys to the target CI database (or fails if the code is bad, which is just as useful a result), which means that the updated database is in place and ready by the time the TFS workflow reaches the test projects. So when the unit (and integration) tests execute, the CI database is ready for inspection by Entity Framework. All I needed to do was add an App.config to that particular unit test project with the connection string for the CI database.</div>
<div>
<br /></div>
<div>
But wait... What happens when we want to run those tests locally? If we change the connection string in the App.config then we run the risk of checking in that change, which would break the CI build for no particular reason. (Side note: I <i>loathe</i> when developers say "I'll just keep that change locally and not check it in." They <i>always</i> check it in at some point and break everybody else. Keep your team's environments consistent, damn it.) And App.configs don't have transforms based on build configuration like Web.configs do. (Side note: What the <i>crap</i>, Microsoft? Seriously, why is this not a thing? Web.config transforms have been around for, like, a billion years.)</div>
<div>
<br /></div>
<div>
We're going to need to include the correct configs for the WPF application deployments in a later step, so let's add a step...</div>
<div>
<br /></div>
<div>
<b>Use A Different App.config</b></div>
<div>
<br /></div>
<div>
There are various solutions to perform transforms on an App.config. I tried a few of them and didn't much care for any of them. The most promising one was this tool called SlowCheetah, which <a href="http://www.hanselman.com/blog/SlowCheetahWebconfigTransformationSyntaxNowGeneralizedForAnyXMLConfigurationFile.aspx">came highly recommended</a> by somebody with lots of experience in these sort of things. But for reasons entirely unknown to me, I just couldn't <i>get the damn thing to work</i>. I'm sure I was missing a step, but it wasn't obvious so I continued to look for other solutions.</div>
<div>
<br /></div>
<div>
We can use post-build xcopy commands, but we <i>really</i> don't want to do that. And based on my experience with projects which use that option I <i>guarantee</i> it will cause problems later. But one component of this solution does make sense... Keeping the App.configs in separate files for each build configuration. It'll likely be easier than trying to shoehorn some transform into the process.</div>
<div>
<br /></div>
<div>
After much research and tinkering, I found a really simple and sensible solution. By manually editing the items in the project file I can <i>conditionally</i> include certain files in certain build configurations. So first I deleted the Item entries for the App.config and its alternates from the csproj file, then I added this:</div>
<br />
<pre class="brush: xml"><ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<None Include="App.config" />
</ItemGroup>
<ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'CI|AnyCPU' ">
<None Include="Configs\CI\App.config" />
</ItemGroup>
<ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Test|AnyCPU' ">
<None Include="Configs\Test\App.config" />
</ItemGroup>
</pre>
<br />
Notice the alternate App.config files in their own directories. The great thing about this approach is that Visual Studio doesn't respect the Condition attributes and shows all of the files. Which is great, because as a developer I want to be able to easily edit these files within the project. But when MSBuild comes along, it <i>does</i> respect the Condition attributes and only includes the files for the particular build configuration being built.<br />
<br />
So now we have App.configs being included properly for each build configuration. When running tests locally, developers' Visual Studios will use the default App.config in the test project. When building/deploying on the server, MSBuild will include the specific App.config for that build configuration, so tests pass in all environments without manual intervention. This will also come in handy later when publishing the ClickOnce WPF application.<br />
<br />
Next we need to...<br />
<br />
<b>Deploy The Web Application</b><br />
<b><br /></b>
Web application deployments are pretty straightforward, and I've done them about a million times with MSBuild in the past. There are various ways to do it, and I think my favorite involves setting up MSDeploy on the target server. The server is client-owned though and I don't want to involve them with a lot of setup, nor do I want to install things there myself without telling them. So for now let's just stick with file system deployment and we can get more sophisticated later if we need to.<br />
<br />
So to perform a file system deploy, I just create a network share for the set up IIS site and add some more MSBuild arguments:<br />
<blockquote class="tr_bq">
/p:PublishProfile=CI /p:PublishUrl=\\servername\sharename\</blockquote>
The PublishUrl is, obviously, the target path on the file system. The PublishProfile is a new one to me, but it works roughly the same as the XML files for the database publishing. When publishing the web application from within Visual Studio the publish wizard saves profiles in the Properties folder in the project. These are simple XML files just as before, and all we need to do here is tell MSBuild which one to use. It includes the environment-specific settings you'd expect, such as the type of deploy (File System in this case) or whether to delete existing files first, etc. (Now that I'm looking at it again, it also includes PublishUrl, so I can probably update that in the XML files and omit it from the MSBuild arguments. This is a work in progress after all.)<br />
<br />
At this point all we need to do is...<br />
<br />
<b>Deploy The ClickOnce WPF Application</b><br />
<b><br /></b>
This one was the least straightforward of them all, mainly for one particular reason. A ClickOnce application is mostly useful in that it detects new versions on the server and automatically upgrades the client when it executes. This detection is based on the version number of what's deployed, but how can we auto-increment that version from within the TFS build?<br />
<br />
It auto-increments, well, automatically when you publish from within Visual Studio. And most people online seem content with that. But the whole point here is not to manually publish, but rather to have a continuously deployed bleeding edge version of the application which can be actively tested, as well as have as simple and automated a QA deployment as possible (queue a build and walk away, basically). So we need TFS and/or MSBuild to auto-increment the build number. And they weren't keen on doing that.<br />
<br />
So first thing's first, let's get it publishing <i>at all</i> before worrying about the build number. Much like with the publish profiles for the web application, this involved walking through the wizard once in Visual Studio just to get the project settings in place. Once in place, we can examine what they are in the csproj file and set them accordingly in the MSBuild arguments:<br />
<blockquote class="tr_bq">
/p:PublishDir=\\servername\anothersharename\ /p:InstallUrl=\\servername\ anothersharename\ /p:ProductName=HelloWorldCI</blockquote>
The PublishDir and InstallUrl are for ClickOnce to know where to put the manifest and application files from which clients will install the application. The ProductName is just any unique name by which the application is known to ClickOnce, which would end up being its name in the Start Menu and the installed programs on the computer. (At this time I'm actually not sure how to get multiple different versions to run side-by-side on a client workstation. I'm sure it involves setting some other unique environment-specific value in the project, I'm just not sure what.)<br />
<br />
So now clients can install the ClickOnce application from the network share, it has the correct App.config (see earlier), and everything works. However, at this time it doesn't detect new versions unless we <i>manually</i> update the version number. And we don't like "<i>manually</i>" around here. Researching and tinkering to solve this led me down some deep, dark rabbit holes. Colleagues advised and assisted, much Googling and Stack Overflowing was done, etc. I was very close to defining custom Windows Workflow actions and installing them on the server as part of the build workflow to over-write the csproj file after running it through some regular expressions. This was getting <i>drastically</i> over-complicated for my tastes.<br />
<br />
While pursuing this approach, the big question was where I would persist the incrementing number. It needed to exist somewhere because each build would need to know what the value <i>is</i> before it can increment it. And I really didn't like the idea of putting it in a database somewhere <i>just</i> to support this one thing. Nor did I like the idea of storing it in the csproj file or any other file under source control because that would result in inconsistencies as gated check-in builds are queued. Then it hit me...<br />
<br />
We have an auto-incrementing number on TFS. The ChangeSet number.<br />
<br />
Now, I've never really edited the build workflow templates before. (Well, technically that's not <i>entirely</i> true. I did make some edits to one while specifically following steps from somebody else's blog post in order to build a SharePoint project before. But it was more SharePoint than TFS else and I had no idea what I was actually doing. So I didn't retain much.) And as such I didn't really know what capabilities were in place or how to reference/assign values. But with a little tinkering and researching, I put together something <i>really</i> simple.<br />
<br />
First, I added a step to the build workflow template just before the MSBuild step. It was a simple Assign workflow item, and the value it was changing was MSBuildArguments (which is globally available throughout the workflow). Logically it basically amounts to:<br />
<br />
<pre class="brush: csharp">MSBuildArguments.Replace("$ChangeSet$", BuildDetail.SourceGetVersion.Replace("C", String.Empty))
</pre>
<br />
That is, it looks for a custom placeholder in the arguments list called $ChangeSet$ and replaces it with the ChangeSet number, which is also globally-available in the workflow as SourceGetVersion on the BuildDetail object. This value itself needs to have its "C" replaced with nothing, since ChangeSet numbers are prepended with "C". Now that I have the "persisted auto-incrementing" number, I just need to apply it to the project settings. And we already know how to set values in the csproj files:<br />
<blockquote class="tr_bq">
/p:ApplicationRevision=$ChangeSet$ /p:MinimumRequiredVersion=1.0.0.$ChangeSet$</blockquote>
And that's it. Now when the ClickOnce application is published, we update the current version number as well as the minimum required version to force clients to update. Somewhere down the road we'll likely need to update the first three digits in that MinimumRequiredVersion value, but I don't suspect that would be terribly difficult. For now, during early development, this works splendidly.<br />
<br />
So at this point what we have is:<br />
<br />
<ul>
<li>Explicit build configurations in the solution and projects</li>
<li>XML publish profiles for the database project and the web application project</li>
<li>Web.config transforms and App.config alternate files</li>
<li>Conditional items in the csproj for the App.config alternate files, based on build configuration</li>
<li>A workflow step to replace MSBuild argument placeholders with the ChangeSet number</li>
<li>A list of MSBuild arguments:</li>
<ul>
<li>/t:Build /t:Publish /p:DeployOnBuild=true /p:PublishProfile=CI /p:SqlPublishProfilePath=CI.publish.xml /p:PublishUrl=\\servername\sharename\ /p:PublishDir=\\servername\someothersharename\ /p:InstallUrl=\\servername\someothersharename\ /p:ApplicationRevision=$ChangeSet$ /p:MinimumRequiredVersion=1.0.0.$ChangeSet$ /p:ProductName=HelloWorldCI</li>
</ul>
</ul>
Replace "CI" with "Test" and we have the Test build. If we want to create more builds (UAT? Production?) all we need to do is:<br />
<br />
<ul>
<li>Create the build configurations</li>
<li>Create the config files/transforms</li>
<li>Create the publish profiles</li>
<li>Set up the infrastructure (IIS site, network shares)</li>
<li>Create a new TFS build with all the same near-default settings and just replace "CI" in the MSBuild arguments with the new configuration</li>
</ul>
And that's it. The result is a fully-automated continuous integration and <i>continuous deployment</i> setup. Honestly, I've worked in so many environments where a build/deploy consisted of a long, involved, highly manual, and highly <i>error-prone</i> process. Developers and IT support were tied up for hours, sometimes days, trying to get it right. What I have here, with a few days of research and what boils down to an hour or two of repeatable effort, is a build/deploy process which involves:<br />
<br />
<ul>
<li>Right-click on the build definition in TFS</li>
<li>Select "Queue New Build"</li>
<li>Go grab a sandwich and take a break</li>
</ul>
<div>
I <i>love</i> building setups like this. My team can now accomplish in <i>two mouse clicks</i> what other teams accomplish in <i>dozens of man-hours</i>.</div>
testhttp://www.blogger.com/profile/09609860522747123959noreply@blogger.com12tag:blogger.com,1999:blog-6959582839690958035.post-2922352964976861372014-04-28T20:42:00.003-04:002014-04-28T20:42:29.399-04:00Composition... And Coupling?Last week I had an interesting exchange with a colleague. We were discussing how some views and view models are going to interact in a WPF application we’re building, and I was proposing an approach which involves composition of models within parent models. Apparently my colleague is vehemently opposed to this idea, though I’m really not certain why.<br />
<br />
It’s no secret that the majority of my experience is as a web developer, and in ASP.NET MVC I use composite models all the time. That is, I may have a view which is a host of several other views and I bind that view to a model which is itself a composition of several other models. It doesn’t necessarily <i>need</i> to be a 1:1 ratio between the views and the models, but in most clean designs that ends up happening if for no other reason than both the views and the models represent some atomic or otherwise discreet and whole business concept.<br />
<br />
The tooling has no problem with this. You pass the composite model to the view, then in the view where you include your “partial” views (which, again, are normal views from their own perspective) you supply to that partial view the model property which corresponds to that partial view’s expected model type. This works quite well and I think distributes functionality into easily re-usable components within the application.<br />
<br />
My colleague, however, asserted that this is “tight coupling.” Perhaps there’s some aspect of the MVVM pattern with which I’m unaware? Some fundamental truth not spoken in the pattern itself but known to those who often use it? If there is, I sure hope somebody enlightens me on the subject. Or perhaps it has less to do with the pattern and more to do with the tooling used in <i>constructing</i> a WPF application? Again, please enlighten me if this is the case.<br />
<br />
I just don’t see the tight coupling. Essentially we have a handful of models, let’s call them Widget, Component, and Thing. And each of these has a corresponding view for the purpose of editing the model. Now let’s say our UI involves a single large “page” for editing each model. Think of it like stepping through a wizard. In my mind, this would call for a parent view acting as a host for the three editor views. That parent view would take care of the “wizard” bits of the UX, moving from one panel to another in which the editor views reside. Naturally, then, this parent view would be bound to a parent view model which itself would consist of some properties for the wizard flow as well as properties for each type being edited. A Widget, a Component, and a Thing.<br />
<br />
What is being tightly coupled to what in this case?<br />
<br />
Is the parent view model coupled to the child view models? I wouldn’t think so. Sure, it has properties of the type of those view models. In that sense I suppose you could say it has a dependency on them. But if we were to avoid such a dependency then we wouldn’t be able to build objects in an object-oriented system <i>at all</i>, save for ones which only recursively have properties of their own type. (Which would be of very limited use.) If a Wizard shouldn’t have a property of type Widget then why would it be acceptable for it to have a property of type string? Or int? Those are more primitive types, but types nonetheless. Would we be tightly coupling the model to the string type by including such a property?<br />
<br />
Certainly not, primarily because the object isn’t terribly concerned with the <i>value</i> of that string. Granted, it may require specific string values in order to exhibit specific behaviors or perform specific actions. But I would contend that if the object is provided with a string value which doesn’t meet this criteria it should still be able to handle the situation in some meaningful, observable, and of course testable way. Throw an ArgumentException for incorrect values, silently be unusable for certain actions, anything of that nature as the logic of the system demands. You can provide mock strings for testing, just like you can provide mock Widgets for testing. (Though, of course, you probably wouldn’t need a mocking framework for a string value.)<br />
<br />
Conversely, are the child view models tightly coupled to the parent view model? Again, certainly not. The child view models in this case have no knowledge whatsoever of the parent view model. Each can be used independently with its corresponding view regardless of some wizard-style host. It’s by coincidence alone that the only place they’re used in this particular application (or, rather, this particular user flow or user experience) is in this wizard flow. But the components themselves are discreet and separate and can be tested as such. Given the simpler example of an object with a string property, I think we can agree that the string type <i>itself</i> doesn’t become coupled to that object.<br />
<br />
So… Am I missing something? I very much contend that composition is not coupling. Indeed, composition is a fundamental aspect of object-oriented design in general. We wouldn’t be able to build rich object systems without it.testhttp://www.blogger.com/profile/09609860522747123959noreply@blogger.com0tag:blogger.com,1999:blog-6959582839690958035.post-1278308555427404542014-04-21T10:35:00.000-04:002014-04-21T10:35:39.359-04:00Say Fewer, Better ThingsLast week, while beginning a new project with a new client, an interesting observation was made of me by the client. As is usual with a new project, the week was filled with meetings and discussions. And more than once the project sponsor explicitly said to me, "Feel free to jump in here as well." Not in a snarky way mind you, he just wanted to make sure I'm not waiting to speak and that my insights are brought to the group. At one point he said, "I take it you're the strong silent type, eh?"<br />
<br />
Well, I like to think so.<br />
<br />
In general it got me thinking, though. It's no secret that I'm very much an introvert, <a href="http://theviralmedialab.org/wp-content/uploads/2013/11/the-power-of-introverts-L-09nPwa.png">and that's okay</a>. So for the most part I have a natural tendency to prefer not speaking over speaking. But the more I think about it, the more I realize that there's more to it than that.<br />
<br />
As it turns out, in a social gathering I'm surprisingly, well, social. I'm happy to crack a joke or tell a story, as long as I don't become <i>too much</i> a center of attention. If I notice that happening, I start to lose my train of thought. In small groups though it's not a problem. In a work setting, however, I tend not to jump in so much. It's not that I'm waiting for my turn to speak, it's that I'm waiting for my turn to add something of value.<br />
<br />
This is intentional. And I think it's a skill worth developing.<br />
<br />
I've had my fair share of meetings with participants who just like to be the center of the meeting. For lack of a better description, they like to hear themselves talk. The presence of this phenomenon varies wildly depending on the client/project. (Luckily my current project is staffed entirely by professionals who are sharp and to the point, for which I humbly thank the powers that be.) But I explicitly make it a point to try not to be this person.<br />
<br />
Understand that this isn't because I don't want to speak. This is because I <i>do</i> want to <i>listen</i>. I don't need (or even really want) to be the center of attention. I don't need to "take over" the meeting. My goal is to simply contribute value. And I find that I can more meaningfully contribute value through listening than through speaking.<br />
<br />
I'll talk at some point. Oh, I will definitely talk. And believe me, I'm <i>full</i> of opinions. But in the scope of a productive group discussion are all of those opinions relevant? Not really. So I can "take that offline" in most cases. A lot of that, while potentially insightful and valuable, doesn't necessarily add value to the discussion at hand. So rather than take the value I already know and try to adjust the meeting/discussion/etc. to fit my value, I'd rather absorb the meeting/discussion/etc. and create <i>new</i> value which I <i>don't</i> already know which targets the topic at hand.<br />
<br />
That is, rather than steer the meeting toward myself, I'd rather steer myself toward the meeting. And doing so involves more listening than talking. Sometimes a lot more.<br />
<br />
In doing so, I avoid saying too much. Other people in the meeting can point out the obvious things, or can brainstorm and openly steer their trains of thought. What I'll do is follow along and observe, and when I have a point to make I'll make it. I find this maximizes the insightfulness and value of my points, even if they're few and far between. And that's a good thing. I'd rather be the guy who made one point which nobody else had thought of than the guy who made a lot of points which everybody else already knew. The latter may have been more the center of attention, but the former added more value.<br />
<br />
Listen. Observe. Meticulously construct a mental model of what's being discussed. Examine that model. And when the room is stuck on a discussion, pull from that model a resolution to that discussion. After all, concluding a discussion with a meaningful resolution is a lot more valuable than having participated in that discussion with everybody else.testhttp://www.blogger.com/profile/09609860522747123959noreply@blogger.com0tag:blogger.com,1999:blog-6959582839690958035.post-39511844622551907342014-04-10T10:46:00.000-04:002014-05-21T15:18:49.954-04:00Agile and BranchingI've recently interacted with an architect who made a rather puzzling claim in defense of his curious and <i>extraordinarily inefficient</i> source control branching strategy. He said:<br />
<blockquote class="tr_bq">
"One of the core principles of agile is to have as many branches as possible."</blockquote>
I didn't have a reply to this statement right away. It took a while for the absurdity of it to really sink in. He may as well have claimed that a core principle of agile is that the oceans are made of chocolate. My lack of response would have been similar, and for the same reason.<br />
<br />
First of all, before we discuss branching in general, let's dispense with the provable falsehoods of his statement. The "core principles" of agile are, after all, <a href="http://agilemanifesto.org/">highly visible for all to see</a>:<br />
<blockquote class="tr_bq">
We are uncovering better ways of developing
software by doing it and helping others do it.
Through this work we have come to value:<br />
<ul>
<li>Individuals and interactions over processes and tools</li>
<li>Working software over comprehensive documentation </li>
<li>Customer collaboration over contract negotiation </li>
<li>Responding to change over following a plan </li>
</ul>
That is, while there is value in the items on
the right, we value the items on the left more.
</blockquote>
Pretty succinct. So let's look at them one-by-one in this case:<br />
<br />
<hr />
<br />
<b>Individuals and interactions over processes and tools</b><br />
<br />
The intent here is pretty clear. This "core principle" is to favor the team members and how they interact, not to favor some particular tool or process. If a process which works well with one team doesn't work well with another team, that other team shouldn't adopt or adhere to that process. Put the team first, not the process or the tool.<br />
<br />
Source control is a tool. Branching is a process. To favor such things despite a clear detriment to the team and to the business value is to explicitly work <i>against</i> the <i>very first</i> principle of agile. Indeed, not only does agile as a software development philosophy make <i>no</i> claim about tools and processes, it <i>explicitly</i> says not to do so.<br />
<br />
<b>Working software over comprehensive documentation</b><br />
<b><br /></b>
In this same environment I've often heard people ask that these processes and strategies at least be documented so that others can understand them. While they may put some balm on the wound in this company, it's not really a solution. If you document a fundamentally broken process, you haven't fixed anything.<br />
<br />
The "core principle" in this case is to focus on delivering a working product. Part of doing that is to eliminate any barriers to that goal. If the developers can't make sense of the source control, that's a barrier.<br />
<br />
<b>Customer collaboration over contract negotiation</b><br />
<b><br /></b>
In this case the "customer" is the rest of the business. The "contract" is the requirements given to the development team for software that the business needs. This "negotiation" takes the form of any and all meetings in which the development team and the business team plan out the release strategy so that it fits all of the branching and merging that's going to take place.<br />
<br />
That negotiation is a lie, told by the development team, and believed by the rest of the business. There is no need for all of this branching and merging other than to simply follow somebody's process or technical plan. It provides no value to the business.<br />
<br />
<b>Responding to change over following a plan</b><br />
<b><br /></b>
And those plans, so carefully negotiated above, become set in stone. Deviating from them causes significant effort to be put forth so that the tools and processes (source control and branching) can accommodate the changes to the plan.<br />
<br />
<hr />
<br />
So that's all well and good for the "core principles" of agile, but what about source control branching? Why is it such a bad thing?<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEie_cmgHwcKIOXfWHttw_rXzzYp_gK9K8DJ6JBs1mzoeS_heKOFRPUE3DBNhyw7QtVJwXgGaiBVev8QuTMlX75pRJVvs_-tKtVrA-1ZVC1GEL7PsvrFJweLKQdt5M4EdxEHjRZR6Y-HGWsI/s1600/122c6346-12f3-4a8a-b50d-2680369b5ebd.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEie_cmgHwcKIOXfWHttw_rXzzYp_gK9K8DJ6JBs1mzoeS_heKOFRPUE3DBNhyw7QtVJwXgGaiBVev8QuTMlX75pRJVvs_-tKtVrA-1ZVC1GEL7PsvrFJweLKQdt5M4EdxEHjRZR6Y-HGWsI/s1600/122c6346-12f3-4a8a-b50d-2680369b5ebd.jpeg" /></a></div>
<br />
The problem with branching isn't the branching per se, it's the <i>merging</i>. What happens when you have to merge?<br />
<br />
<ul>
<li>New bugs appear for no reason</li>
<li>Code from the same files changed by multiple people has conflicts to be manually resolved</li>
<li>You often need to re-write something you already wrote and was already working</li>
<li>If the branch was separated for a long time, you and team members need to re-address code that was written a <i>long</i> time ago, duplicating effort that was already done</li>
<li>The list of problems goes on and on...</li>
</ul>
<div>
Merging is <i>painful</i>. But, you might say, if the developers are careful then it's a lot <i>less</i> painful. Well, sure. That may be coincidentally true. But how much can we rely on that? Taken to an extreme to demonstrate the folly of it, if the developers were "careful" then the software would never have bugs or faults in the first place, right?</div>
<div>
<br /></div>
<div>
Being careful isn't a solution. Being <i>collaborative</i> is a solution. Branches means working in isolated silos, not interacting with each other. If code is off in a branch for months at a time, it will then need to be re-integrated with other code. It already works, but now it needs to be made to work again. If we simply practice continuous integration, we can make it work <i>once</i>.</div>
<div>
<br /></div>
<div>
This is getting a bit too philosophical, so I'll step back for a moment. The <i>point</i>, after all, isn't any kind of debate over what have become industry buzz-words ("agile", "continuous integration", etc.) but rather the actual delivery of value to the business. That's why we're here in the first place. That's what we're doing. We don't necessarily write software for a living. We <i>deliver business value</i> for a living. Software is simply a tool we use to accomplish that.</div>
<div>
<br /></div>
<div>
So let's ask a fundamental question...</div>
<blockquote class="tr_bq">
What business value is delivered by merging branched code?</blockquote>
The answer is simple. None. No business value at all. Unless the actual business model of the company is to take two pieces of code, merge them, and make money off of that then there is <i>no</i> value in the act of merging branches. You can have those meetings and make those lies all you like, but all you're doing is trying to justify a failing in your own design. (By the way, those meetings further detract from business value.)<br />
<br />
Value comes in the form of features added to the system. Or bugs fixed in the system. Or performance improved in the system. And time spent merging code is time not spent delivering this value. It's <i>overhead</i>. <i>Cruft</i>. And the "core principles" of agile demand that <i>cruft</i> be eliminated.<br />
<br />
The business as a whole isn't thinking about how to best write software, or how to follow any given software process. The business as a whole is thinking about how to improve their products and services and maximize profit. Tools and processes related to software development are entirely unimportant to the business. And those things should never be valued above the delivery of value to the business.testhttp://www.blogger.com/profile/09609860522747123959noreply@blogger.com0tag:blogger.com,1999:blog-6959582839690958035.post-45640460273242002152014-04-03T13:34:00.000-04:002014-05-21T15:27:39.355-04:00RoboCop-Driven Development<div>
How many cooks are in your kitchen? Or, to use a less politically-correct analogy, what's the chief-to-indian ratio in your village? If you're trying to count them, there are too many.</div>
<div>
<br /></div>
<div>
There are as many ways to address this problem as there are stars in the sky. (Well, I live in a populated area, so we don't see a whole lot of stars. But there are some, I'm sure of it.) There can be a product owner at whom the buck stops for requirements, there can be quick feedback cycles to identify and correct problems as early as possible, there can be drawn-out analysis and charting of requirements to validate them, prototyping to validate them, etc.</div>
<div>
<br /></div>
<div>
But somehow, we often find ourselves back in the position that there are too many cooks in the kitchen. Requirements are coming from too many people (or, more appropriately, too many <i>roles</i>). This doesn't just end up killing the Single Responsibility Principle, it dances on the poor guy's grave.</div>
<div>
<br /></div>
<div>
Let me tell you a story. Several years ago I was a developer primarily working on a business-to-business web application for a private company. The company, for all its failings, was a stellar financial success. Imagine a dot-com-era start-up where the money never ran dry. I think it was this "can't lose" mentality which led to the corporate culture by which pretty much anybody could issue a requirement to the software at any time for any reason.</div>
<div>
<br /></div>
<div>
One day a requirement made its way to my inbox. On a specific page in the application there was a table of records, and records which meet a specific condition need to be highlighted to draw the attention of the user. The requirement was to make the <b><i>text</i></b> of those table rows <b><i>red</i></b>. A simple change to say the least. And very much a non-breaking change. So there wasn't really a need to involve the already over-burdened QA process. The change was made, developer-tested, and checked in. Another developer could even have code-reviewed it, had that process been considered necessary.</div>
<div>
<br /></div>
<div>
Around the same time, a requirement from somebody else in the business made its way to another developer's inbox. On a specific page in the application there was a table of records, and records which meet a specific condition need to be highlighted to draw the attention of the user. The requirement was to make the <b><i>background</i></b> of those table rows <b><i>red</i></b>. A simple change to say the least. And very much a non-breaking change. So there wasn't really a need to involve the already over-burdened QA process. The change was made, developer-tested, and checked in. Another developer could even have code-reviewed it, had that process been considered necessary.</div>
<div>
<br /></div>
<div>
Both requirements were successfully met. And, yes, the changes were successfully promoted to production. (Notice that I'm using a more business-friendly definition of the word "successfully" here.) The passive-aggressive side of me insists that there's no problem here. Edicts were issued and were completed as defined. The professional side of me desperately wants to fix this problem every time I see it.</div>
<div>
<br /></div>
<div>
Sometimes requirements, though individually well-written and well-intentioned, don't make sense when you put them together. Sometimes they can even be mutually exclusive. The psychology of this can be difficult to address. We're talking about two intelligent and reasonable experts in their field. Each individually put some measure of thought and care into his or her own requirement. That requirement makes sense, and it's necessary for the growth of the system to meet business needs. Imagine trying to explain to this person that their requirement <i>doesn't</i> make sense. Imagine trying to say, "You are right. And you over there are also right. But together you are wrong."</div>
<div>
<br /></div>
<div>
To a developer, that conversation always sounds like this:</div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/BKorP55Aqvg?feature=player_embedded' frameborder='0'></iframe></div>
<div>
<br /></div>
<div>
Someone wanted the lines to be red. Somebody else wanted them to be drawn with specific inks. Somebody else wanted there to be seven of them. Somebody else wanted them to be perpendicular to each other. And so on and so forth. In the video all of those requirements came filtered through what appeared to be a product owner, but the concept is the same. And to a developer there isn't always a meaningful difference. "You" made this requirement can be the singular "you" or the plural "you", it's just semantics.</div>
<div>
<br /></div>
<div>
Remember that "business-friendly" definition of "successful"? That is, we can all work diligently to achieve every goal we set forth as a business, and still not get anywhere. The goals were "successfully" met, but did the product successfully improve? We did what we set out to do, and we pat ourselves on the back for it. All the while, nothing got done. Each individual goal was reached, but if you stand back and look at the bigger picture you clearly see that it was all a great big bloody waste of time.</div>
<div>
<br /></div>
<div>
(If your hands-on developers can see the big picture and your executives can't, something's wrong.)</div>
<div>
<br /></div>
<div>
Creators of fiction have presented us with this group-think phenomenon many times. My personal favorite, for reasons unknown to me, is RoboCop 2. If you'll recall, RoboCop had a small set of prime directives. These were his standing orders which he was physically incapable of violating. They were hard-coded into his system, and all subsequent orders must at least maintain these:</div>
<div>
<ol>
<li>Serve the public trust</li>
<li>Protect the innocent</li>
<li>Uphold the law</li>
<li>(There was a fourth, "classified" directive placed there by the suits who funded his construction, preventing him from ever acting against them personally. That was later removed.)</li>
</ol>
<div>
There's lots of precedent for "directives" such as these. Much of the inspiration clearly comes from <a href="http://en.wikipedia.org/wiki/Three_Laws_of_Robotics">Isaac Asimov's three laws of robotics</a>. Hell, even in real life we have similar examples, such as the <a href="http://usmilitary.about.com/od/armyjoin/l/blbasicgenorder.htm">general orders</a> presented to soldiers in the US Army during basic training. It's an exercise in simplicity. And, of course, life is never that simple. Asimov's stories demonstrated various ways in which the Three Laws didn't work as planned (or worked completely differently than planned, such as when a robot invented faster-than-light travel). And I'm sure any soldier will tell you some stories of real life after training.</div>
</div>
<div>
<br /></div>
<div>
But then fast-forward to RoboCop 2, when the special interest groups got involved. It became political. And his 3 directives quickly ballooned into over 300 directives. Each of which, I'm sure, was well-intentioned. But when you put all of them together, he became entirely unable to function. He had too many conflicting requirements. Too many individual "rights" added up to one great big "wrong."</div>
<div>
<br /></div>
<div>
(Parents of the world would be perplexed. Two wrongs don't make a right, but two rights can very easily make a wrong.)</div>
<div>
<br /></div>
<div>
Is your business environment a dizzying maelstrom of special interest groups? Do they each have an opportunity to individually contribute to the product? Is this <i>helping</i> the product? Which is more important to the business... Appeasing every group individually or building a compelling product?</div>
testhttp://www.blogger.com/profile/09609860522747123959noreply@blogger.com0tag:blogger.com,1999:blog-6959582839690958035.post-42379881543208301392014-04-01T09:55:00.000-04:002014-04-01T09:55:05.405-04:00Scientists Have Been Doing TDD for CenturiesI've recently been watching <a href="http://www.cosmosontv.com/">Cosmos: A Spacetime Odyssey</a> (and I don't have the words to describe how excellent it is), and the subject came up with my children about what science really is. Fundamentally, aside from all the various beliefs and opinions that people have, how can one truly know what is "science" and what is not.<div>
<br /></div>
<div>
The answer turns out to be very simple. The science is in the test. Ideas, opinions, even reason and logic themselves are all ancillary concepts to the test. If it isn't tested (or for whatever reason <i>can't be</i> tested, such as supernatural beliefs), then it isn't science. That isn't to say that it's <i>wrong</i> or <i>bad</i>, simply that it isn't <i>science</i>.</div>
<blockquote class="tr_bq">
Science is the act of validating something with a test.</blockquote>
You can believe whatever you like. You can even apply vast amounts of reason and logic and irrefutably derive a very sensible conclusion about something. But if you don't validate it with a test, it's not science. It's conjecture, speculation. And as I like to say at work, "Speculation is free, and worth every penny."<br />
<br />
A Google search on "the scientific method" (which I think we can agree is the core foundation of all scientific study) lands me on a site called <a href="http://www.sciencebuddies.org/">Science Buddies</a>, which presents <a href="http://www.sciencebuddies.org/science-fair-projects/project_scientific_method.shtml#overviewofthescientificmethod">this handy graphic</a> to visualize the process:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgr0rFUseY3mwMSLzlP3Svr015CJJGWOE5ilamraeQCfR9E6XiJ2Pyn_v4pF3fLvc2kIv_vVeqTjPatH05QQdp1IsHT5t3G_o1TEFCo380PdID-OGfPMEJIGJERmbr3LiG1qKJYB7FudP0s/s1600/2013-updated_scientific-method-steps_v6_noheader.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgr0rFUseY3mwMSLzlP3Svr015CJJGWOE5ilamraeQCfR9E6XiJ2Pyn_v4pF3fLvc2kIv_vVeqTjPatH05QQdp1IsHT5t3G_o1TEFCo380PdID-OGfPMEJIGJERmbr3LiG1qKJYB7FudP0s/s1600/2013-updated_scientific-method-steps_v6_noheader.png" /></a></div>
<div style="text-align: left;">
This seems similar enough to what I remember from grammar school. Notice a few key points:</div>
<div style="text-align: left;">
</div>
<ul>
<li>Attention is drawn to the bright green box. (Green means good, right?) That box is the center of the whole process. That box is the test being conducted.</li>
<li>The very first step is "Ask a Question." Not define what you think the answer is, not speculate on possible outcomes, but simply ask the question.</li>
<li>There's a cycle to the process, using the tests to validate each iteration of the cycle. The results of the tests are fed back into the process to make further progress.</li>
</ul>
<div>
This reminds me of another cycle of testing:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSXOA7olmQA3SZSTWwal9tFnlAbZ26N4KIpF4xtTDP4zCpxKDuUgYmiqzroJTcKikKt4Q_OraF0wCIeluB2ZsKEyYvmgzuBXR99yspA8EDul5IYJmTvUm0t36CfFGuvPJZBtSbCrVD216y/s1600/redgreenrefacor.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSXOA7olmQA3SZSTWwal9tFnlAbZ26N4KIpF4xtTDP4zCpxKDuUgYmiqzroJTcKikKt4Q_OraF0wCIeluB2ZsKEyYvmgzuBXR99yspA8EDul5IYJmTvUm0t36CfFGuvPJZBtSbCrVD216y/s1600/redgreenrefacor.png" height="273" width="320" /></a></div>
<div style="text-align: left;">
Even the coloring is the same. The first step, in red, is to ask the question. The central step, in green, is to run a test against the implementation to produce results, validating both the test and the implementation. The loop back step, in blue, is to adjust the system based on the results of the test and return to the start of the cycle, using the test and its results to further refine and grow the next test(s).</div>
<blockquote class="tr_bq">
TDD is the Scientific Method applied to software development.</blockquote>
The two processes share core fundamental values. Values such as:<br />
<br />
<ul>
<li>Begin by asking a question. The purpose of the process is not to <i>answer</i> the question, but to arrive at a means of <i>validating</i> an answer. Answers can change over time, the key value is in being able to validate those answers.</li>
<li>Tests must be repeatable. Other team members, other teams, automated systems, etc. must be able to set up and execute the test and observe the results. If the results are inconsistent then the tests themselves are not valid and must be refined, removing variables and dependencies to focus entirely on the subject being tested.</li>
<li>The process is iterative and cyclic. Value is attained not immediately, but increasingly over time. Validating something once is only the first step in the process, if the same thing can't be validated repeatedly then it wasn't valid in the first place, the initial result was a false positive. Only through repetition and analysis can one truly be confident in the result.</li>
</ul>
<div>
We've all heard the analogy that TDD is similar to double-entry bookkeeping. And that analogy still holds true. This one is just resonating with me a lot more at the moment. It's not just the notion that the code and the tests mutually confirm each other, but that the fundamental notion of being able to validate something with a repeatable test is critical to truly understanding that something. Anything else is just speculation.</div>
<br />
testhttp://www.blogger.com/profile/09609860522747123959noreply@blogger.com0tag:blogger.com,1999:blog-6959582839690958035.post-73568547889132667102014-03-24T11:21:00.001-04:002014-03-24T11:27:13.716-04:00Don't Judge Too QuicklyWriting software is a team effort. And as with any team effort, we have to work together. This includes the ever-dreaded notion of having to read, understand, and perhaps even maintain code written by somebody else. Maybe that "somebody else" is a close and trusted colleague, maybe it is a client-appointed counterpart, maybe it is a team member who left the team long ago. Regardless of who originated the code we're looking at, that developer is in some way a part of the overall team.<br />
<div>
<br /></div>
<div>
And let's be honest here... We don't like working on other people's code. It's not something to be ashamed of. After all software development is in many ways a creative endeavor, an ill-defined Venn intersection between creativity, engineering, salesmanship, sarcasm, and caffeine. And who wants to create on top of something that's already been created? A painter prefers a canvas to be blank. A sculptor prefers an unbroken stone. But these analogies extend only so far in our craft, and clinging too tightly to them detracts from the team.</div>
<div>
<br /></div>
<div>
So how do we approach existing ("legacy") code? Hopefully not with judgements and preconceptions.</div>
<div>
<br /></div>
<div>
Over the years I've heard lots of good advice from my manager. Recently he made a suggestion which particularly resonated with me, <b>"Don't pass judgement on their code for at least a month."</b> My initial internal reaction was to remind myself that "I know these code smells all too well" and that "I've had enough conversations with these guys to know that they have no idea what they're doing." The sheer arrogance of these thoughts quickly became apparent. Clearly I needed to do a little less deciding and a little more observing.</div>
<div>
<br /></div>
<div>
What can be observed is the history of the codebase. Why certain things were done certain ways, what other factors have been in place (including the factors which have long-since vanished after having left their discernible mark in the code). What becomes clear during this period is the subtle reminder that our clients and counterparts are not unintelligent, neither malicious nor insane, and that as reasonable people with reasonable goals they have time and again enacted reasonable decisions with the information they had. Maybe that information was incorrect or incomplete, or maybe that information has changed over time.</div>
<div>
<br /></div>
<div>
"This legacy code is a mess" is in every way a cop-out. It's how we throw in the towel, declaring to the world that we are not in a position to help. Even if it's <i>correct</i>, it's not <i>productive</i>. (This reminds me of another nugget of management wisdom I've heard, "Being right isn't good enough.") The productive approach is to understand the decisions of yesterday so that we can better advise on the decisions of today.</div>
<div>
<br /></div>
<div>
A significant reason why this advice resonates with me is because, during this "month of observation," a curious turning of the tables has occurred. While at this client, I've written some of the best code in my life. It's a small project, and one in which I was explicitly given freedom to demonstrate some technologies, patterns, and practices which could be applied elsewhere in the company's software. It was both a solution to a simple problem as well as a proof of concept for solution patterns in general. And almost immediately after I completed development of this codebase the client hired a new Solution Architect who took one look at it and didn't like it.</div>
<div>
<br /></div>
<div>
It wasn't what he expected. Or, rather, it wasn't what he <i>would have written</i>. And because it didn't fit his mold, it was to him in every way a "legacy mess." How could this be? Patterns are documented, concerns are separated, test coverage is high, each individual fully-encapsulated component is elegant in its simplicity. (At least, I think so.) And it was everything he didn't want in an architecture.</div>
<div>
<br /></div>
<div>
Who is he to tell me that my baby is ugly? Well, who am I to tell any client that their baby is ugly?</div>
<div>
<br /></div>
<div>
What he hasn't been able to tell me is any meaningful reason <i>why</i> my code is "bad." If he could, I'd be happy to listen to his points. Any opportunity to learn and improve is welcome. But "I don't like it" isn't such an opportunity. So, following that same reasoning, what meaningful points can I provide the client about <i>their</i> code? Why don't <i>I</i> like it?</div>
<div>
<br /></div>
<div>
Those points can be productive and helpful, as long as they're backed by meaningful information. And that information starts with understanding the existing codebase and why each component is what it is. Despite years of experience, that understanding doesn't come from a cursory look at the code but rather from time spent "in the trenches" working, studying, observing. Doing so "for at least a month" sounds like as good a rule of thumb as any.</div>
testhttp://www.blogger.com/profile/09609860522747123959noreply@blogger.com0tag:blogger.com,1999:blog-6959582839690958035.post-52694769753245433672014-03-17T08:03:00.001-04:002014-03-17T08:03:10.223-04:00Dependency Injection ScreencastHere's a screencast of a presentation I've given a few times at local events, called "What Is Dependency Injection?" It's basically an intro-to-DI for an audience of developers (both new and experienced) who haven't been exposed to DI implementations but have been hearing about it, or perhaps developers who haven't used it but suddenly need to and want to know what it's all about.<br />
<br />
Enjoy!<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/j6Le6YJH5o8?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
<br /></div>
testhttp://www.blogger.com/profile/09609860522747123959noreply@blogger.com0tag:blogger.com,1999:blog-6959582839690958035.post-36989399086537444402014-03-14T12:59:00.003-04:002014-03-14T12:59:41.349-04:00Refactoring Screencasts VIRecently I've once again had the occasional opportunity to sit in a (mostly) quiet room and record some more screencasts, so here's the Dealing With Generalization series. Enjoy!<br />
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/S2PNQ2OyvTs?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
Pull Up Field</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/6fDHUCl9kXA?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
Pull Up Method</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/ycV0Hs5fqbw?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
Pull Up Constructor Body</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<object width="320" height="266" class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="https://i1.ytimg.com/vi/gI_jvp19PqY/0.jpg"><param name="movie" value="https://www.youtube.com/v/gI_jvp19PqY?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" /><param name="bgcolor" value="#FFFFFF" /><param name="allowFullScreen" value="true" /><embed width="320" height="266" src="https://www.youtube.com/v/gI_jvp19PqY?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" type="application/x-shockwave-flash" allowfullscreen="true"></embed></object></div>
<div style="text-align: center;">
Push Down Method</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<object width="320" height="266" class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="https://i1.ytimg.com/vi/j_jo8a7iMNY/0.jpg"><param name="movie" value="https://www.youtube.com/v/j_jo8a7iMNY?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" /><param name="bgcolor" value="#FFFFFF" /><param name="allowFullScreen" value="true" /><embed width="320" height="266" src="https://www.youtube.com/v/j_jo8a7iMNY?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" type="application/x-shockwave-flash" allowfullscreen="true"></embed></object></div>
<div style="text-align: center;">
Push Down Field</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<object width="320" height="266" class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="https://i1.ytimg.com/vi/1c1B_BK7fOE/0.jpg"><param name="movie" value="https://www.youtube.com/v/1c1B_BK7fOE?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" /><param name="bgcolor" value="#FFFFFF" /><param name="allowFullScreen" value="true" /><embed width="320" height="266" src="https://www.youtube.com/v/1c1B_BK7fOE?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" type="application/x-shockwave-flash" allowfullscreen="true"></embed></object></div>
<div style="text-align: center;">
Extract Subclass</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/yphgEqXkH3M?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
Extract Superclass</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/JSpjrMmHBDk?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
Extract Interface</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/pZGOLu4JcBM?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
Collapse Hierarchy</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<object width="320" height="266" class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="https://i1.ytimg.com/vi/Oz4_45DD8qU/0.jpg"><param name="movie" value="https://www.youtube.com/v/Oz4_45DD8qU?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" /><param name="bgcolor" value="#FFFFFF" /><param name="allowFullScreen" value="true" /><embed width="320" height="266" src="https://www.youtube.com/v/Oz4_45DD8qU?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" type="application/x-shockwave-flash" allowfullscreen="true"></embed></object></div>
<div style="text-align: center;">
Form Template Method</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/QBJigWDBlGE?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
Replace Inheritance With Delegation</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/a0XIK8AcALU?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
Replace Delegation With Inheritance</div>
testhttp://www.blogger.com/profile/09609860522747123959noreply@blogger.com0tag:blogger.com,1999:blog-6959582839690958035.post-53103476443253039722014-03-11T09:00:00.003-04:002014-03-11T09:00:50.040-04:00On .on(), or Event Delegation ExplainedJust as I'm quite sure there are straightforward concepts unfamiliar to me in technologies and architectures with which I have little or no experience, so too are there such concepts which I take for granted each day but which befuddle otherwise capable developers who simply haven't had exposure to them. (Of course, this one also befuddles developers who really <i>should</i> understand it by now, but I digress.) So perhaps I can "do the universe a solid" and attempt to share that which I have and, for the most part, have been oblivious to the fact that there are others who do not have it.<br />
<div>
<br /></div>
<div>
In this case, I'm speaking of <a href="https://api.jquery.com/on/">jQuery's .on() function</a>. We've all seen the recommendations to use that, though the more I see such recommendations on, say, Stack Overflow answers the more I discover that there's no shortage of developers who treat .on() as a magic spell. An incantation which, when invoked, solves their problem. Or at least <i>should</i>, and when it doesn't they are again confused.</div>
<div>
<br /></div>
<div>
Allow me to start by stating a couple of unshakable truths regarding this sorcery:</div>
<div>
<ol>
<li>.on() is not magic.</li>
<li>Event handlers are attached to <i>elements</i>, not to selectors.</li>
<li>When an event handler is attached to an element, the selector is evaluated <i>once</i> at that time and never again.</li>
</ol>
<div>
Some of that sounded pretty matter-of-fact as far as blanket statements go, and indeed perhaps I could wordsmith it better. But I wanted to sound that way, because I want to get your attention. You may point out that .on() uses event delegation which clearly means the selector is evaluated again at another time. However, if you know what you're talking about then you know that's kind of a misleading statement because you're referring to a different selector. And if you don't know what I meant by that statement then this article is for you.</div>
</div>
<div>
<br /></div>
<div>
First, let's consider the following code:</div>
<div>
<br /></div>
<pre class="brush: html"><button class="editButton">Edit</button>
<script type="text/javascript">
$('.editButton').click(function () {
// handle the button click event
});
</script>
</pre>
<br />
A very simple and straightforward jQuery event handler. When the button is clicked, the handler code runs. In the highly dynamic world of AJAX and dynamic DOM structures, however, this straightforward approach doesn't always work. A developer then asks, "Why doesn't my click event handler execute for edit buttons that are added to the page via AJAX?" A very reasonable novice question, often met with an equally novice answer... "Just use .on() instead."<br />
<br />
This might lead the developer to try this approach:<br />
<br />
<pre class="brush: html"><button class="editButton">Edit</button>
<script type="text/javascript">
$('.editButton').on('click', function () {
// handle the button click event
});
</script></pre>
<br />
Now the developer is using .on(), but he didn't solve the problem. The magic spell didn't work. So the question is re-asked and further clarification is provided, again in the form of an incantation, "Use 'document' and add a second selector." This exchange leads the developer here:<br />
<br />
<pre class="brush: html"><button class="editButton">Edit</button>
<script type="text/javascript">
$(document).on('click', '.editButton', function () {
// handle the button click event
});
</script></pre>
<br />
This "works" in the strictest definition of the word. (That is, when comparing "works" with "doesn't work" as an equally vague description of events.) It solves the problem of giving a man a fish so that he may eat today. And in a world where quarterly earnings are valued above long-term sustainability that may be enough. But as developers we don't necessarily live in that world. We have to stomach it from time to time, but <i>our</i> world is about long-term sustainability. The code we write needs to be understandable by whoever has to support it, including ourselves. That is, the developer needs to understand <i>why</i> this incantation "works."<br />
<br />
Let's switch gears for a moment and discuss the DOM and events therein. We're all familiar with the fact that when you click something, it raises a click event. (There are plenty of other events as well, but for the purpose of this discussion we'll just focus on the most common of them... click.) Some of us may also be familiar with the fact that events "bubble up" in the DOM, which is at the heart of how .on() performs its "magic." Consider an HTML structure:<br />
<br />
<pre class="brush: html"><body>
<div>
<button class="editButton">Edit</button>
</div>
</body>
</pre>
<br />
When you click on the button, the button invokes its click event and any handlers for that event attached to that element are thus invoked. But then the event "bubbles up" the structure. After the button invokes it event, the div invokes <i>its</i> click event, invoking any handlers attached <i>to the div</i>. Then the body invokes <i>its</i> click event for handlers attached to <i>it</i>. The top-level html tag also then invokes its click event, and the document object at the very top of the DOM invokes <i>its</i> click event.<br />
<br />
That's a lot of click events for a single click. So how does this relate to the "working" incantation above? In that code, look at the element to which we're <i>actually</i> binding the click event:<br />
<br />
<pre class="brush: html"><button class="editButton">Edit</button>
<script type="text/javascript">
$(document).on('click', '.editButton', function () {
// handle the button click event
});
</script></pre>
<br />
We're binding it to the <i>document</i>. Let's assume for a moment that the HTML being dynamically changed via AJAX calls is the div and the button. This means we could also have bound to the body or the html (though I don't think I've ever seen that latter one in the wild) and it would still "work." This is because any element in the DOM, when raising this event, propagates the event upwards through the structure of the DOM. (Unless, of course, <a href="https://developer.mozilla.org/en-US/docs/Web/API/event.stopPropagation">propagation is explicitly stopped</a>.)<br />
<br />
Indeed, <i>every</i> click <i>anywhere</i> in the DOM is going to invoke the click event handler(s) on the document object. This is where that other selector in .on() comes in. It's a filter for the event propagation, indicating to jQuery that this particular function should only be invoked when the originating element matches that selector. <i>That</i> selector is evaluated when the event is invoked, whereas the selector for assigning the event was evaluated only once when the page was loaded.<br />
<br />
Had we done this, our event handler would execute for any click anywhere on the page:<br />
<br />
<pre class="brush: html"><button class="editButton">Edit</button>
<script type="text/javascript">
$(document).on('click', function () {
// handle the button click event
});
</script></pre>
<br />
This is also why the developer's first attempt to use .on() "worked" in the sense that his initially loaded button(s) still invoked the handler, because it still attached that handler to the selected elements. But as new elements are added to the DOM, those elements have no handlers attached to them and so it "didn't work" for them.<br />
<br />
So basically, the event originates at the clicked element (in this case a button) and travels upward through the HTML elements all the way to the top. That event can be "handled" anywhere along the way. The sorcery of .on() then is simply that it's handled further up the chain instead of at the element itself. This allows us to dynamically alter elements within the document without losing the handler, because even though newly added elements don't have their own handlers assigned they <i>do</i> still "bubble up" their events to parent elements.<br />
<br />
It's common to attach these handlers to the document object, though any common parent element will "work." Let's say you have a containing div and within that div you add/remove elements. As long as the div element isn't removed then you can keep your event handler there. (For a large and complex page it's probably best not to put <i>all</i> handlers on the document object, if for no other reason than saner organization of code.) Any common parent over the dynamic elements will "work."<br />
<br />
It's not magic, and it's important to understand which parts of the code are evaluated at what time. The selector which targets the element(s) on which we're assigning a handler is evaluated <i>once</i> and never again. The selector which filters the child element(s) which originated the event is evaluated each time the event occurs.testhttp://www.blogger.com/profile/09609860522747123959noreply@blogger.com0tag:blogger.com,1999:blog-6959582839690958035.post-34974481699540428072014-03-03T12:45:00.000-05:002014-03-04T09:01:17.249-05:00Persistence Ignorance with Entity FrameworkI've never been shy about the fact that I don't like Entity Framework. It's not because I think it's a bad framework, it's just that for my code it didn't seem to fit the task. And after all, the tools should support the need. The reason for this was mainly because I didn't want a data access framework to pollute my otherwise dependency-free domain.<br />
<br />
For a lot of applications this isn't a problem, but I'm not working on those applications. For the stuff I work on, keeping dependencies isolated is <i>very</i> valuable. Additionally, any introductory walk-through of Entity Framework usually involved one of two things:<br />
<ol>
<li>Generate the models from the database. I really,<i> really</i> don't like doing this. Again, for a lot of applications this is fine. But more often than not I'm working in a fairly complex domain and need to have some real business-logic control over the models. I often find myself insisting such truths as, "Not every table is a business entity" or "Relational structures and object-oriented structures don't always match perfectly." In the end, as an object-oriented developer I like to have control over my models. (Also, I hate EDMX files. A lot.)</li>
<li>With the advent of "Code First," generate the database from the models. While I certainly support the idea of starting with the domain modeling, and while I think it's an interesting approach to generate the database structure, does any significant real-world project actually do this? Are you really going to explain to your IT manager that they don't need to worry about their database schema and the framework is just going to handle that for them? Good luck with that.</li>
</ol>
<div>
So, really, what I've always wanted the framework to be able to provide for me was just a mapping between the models I create and the database schema I create. (Understanding that different models created in different applications may also map (albeit differently) to those same database tables.) And while I always thought that Entity Framework could do this, it wasn't obvious and I never had a compelling reason to dig into it.</div>
<div>
<br /></div>
<div>
But times change, and if you're doing data access work on the Microsoft stack these days then you'd be remiss not to be following along with Entity Framework. So recently I had an opportunity to really dig into it on a fairly simple project and see if I could achieve real persistence ignorance in an application. And, much to my surprise, I did. And very easily at that. So let's take a look at what's involved here...</div>
<div>
<br /></div>
<div>
First let's start with the models. (I told you I really support that.) Note that what follows is, of course, simplified for this example. But it works just fine. Now, in this business domain we have a concept of an Occurrence, with a stripped-down model here:<br />
<br /></div>
<pre class="brush: csharp">public class Occurrence
{
public int ID { get; private set; }
public bool InterestingCase { get; set; }
public string Comments { get; set; }
public Status ReviewStatus { get; set; }
public string FieldToIgnore { get; private set; }
public virtual ICollection<ContributingFactor> ContributingFactors { get; private set; }
protected Occurrence()
{
ContributingFactors = new List<ContributingFactor>();
}
public Occurrence(bool interestingCase, string comments)
: this()
{
InterestingCase = interestingCase;
Comments = comments;
ReviewStatus = Status.New;
}
public enum Status
{
New,
In_Progress,
Finalized
}
}
public class ContributingFactor
{
public int ID { get; private set; }
public string Factor { get; private set; }
protected virtual Occurrence Occurrence { get; private set; }
public static readonly Expression<Func<ContributingFactor, Occurrence>> OccurrenceProperty = c => c.Occurrence;
public int OccurrenceID { get; private set; }
protected ContributingFactor() { }
public ContributingFactor(string factor)
: this()
{
Factor = factor;
}
}
</pre>
<br />
Simple enough, and as I said it's been stripped-down of a lot of business logic. (For example, the real one has a bunch of logic in the setters for tracking historical changes to the model at the field level, as well as a custom implementation of ICollection<t> which prevents modifying the collection without using other custom methods on the model, again to ensure tracking of changes to values.) Let's identify a couple of the interesting parts:</t><br />
<ul>
<li>The ID setter is private. This is because identifiers are system-generated by the backing data store and consuming code should never need to set one.</li>
<li>There's a contrived FieldToIgnore in the model. This is present in the example solely to demonstrate how the Entity Framework mappings can be set to ignore fields. By default it tries to make sense of every field, and a complex model can have a lot of calculated or otherwise not-persisted properties.</li>
<li>The collection of child objects is virtual, this helps Entity Framework populate it. It's <i>kind of</i> an example of EF leaking into the domain, but there's no compelling reason in the domain <i>not</i> to make it virtual, so I'm fine with it.</li>
<li>On the child object there's a protected reference to the parent object. Normally this might be public, but since the child <i>can't exist</i> outside the context of the parent then there's no need to be able to navigate back to the parent. Indeed, being able to do so introduces an infinite recursion when serializing and would require additional workarounds.</li>
<li>Also on the child object is a reference to the ID of the parent object. This will become clear when we discuss our database structure. Essentially it's needed because it's part of the key in my table. (I tend to use the identity column and the parent foreign key column as the primary key when a child is explicitly identified by its parent.)</li>
<li>You're probably also noticing that Expression property. That's another example of the Entity Framework implementation <i>kind of</i> leaking into the domain, sort of. It's there because the mappings in the DAL are going to need to reference that Occurrence property in order to map the relational structure. But since it's protected, they can't. Honestly, I've since discovered that having property references like this can be very handy for objects, so it's quickly becoming a more common practice for me anyway.</li>
<li>The child object is intended to be something of an immutable value type. The parent is the aggregate root and is the real domain entity, the child is just a value that exists on the parent.</li>
</ul>
A simple enough domain for an example. Now, our persistence-ignorant domain is going to need a repository and, just for good measure, a unit of work:<br />
<br />
<pre class="brush: csharp">public interface OccurrenceRepository
{
IQueryable<Occurrence> Occurrences { get; }
void Add(Occurrence model);
void Remove(Occurrence model);
}
public interface UnitOfWork : IDisposable
{
OccurrenceRepository OccurrenceRepository { get; }
void Commit();
}
</pre>
<br />
That looks persistence-ignorant enough for me. So consuming code might look something like this:<br />
<br />
<pre class="brush: csharp">using (var uow = IoCContainerFactory.Current.GetInstance<UnitOfWork>())
{
var occurrence = new Occurrence(true, "This is a test");
occurrence.ContributingFactors.Add(new ContributingFactor("Test Factor"));
uow.OccurrenceRepository.Add(occurrence);
uow.Commit();
}
</pre>
<br />
Now, in order to get that to work (glazing over the IoC implementation, which isn't relevant to this example, but just know that I'm using a simple home-grown service locator) we're going to need our DAL implementation. That's the project which will hold the reference to Entity Framework. But before we get to that, let's create our tables:
<br />
<br />
<pre class="brush: sql">CREATE TABLE [dbo].[Occurrence] (
[ID] INT IDENTITY (1, 1) NOT NULL,
[Comments] NVARCHAR (MAX) NULL,
[InterestingCase] BIT NOT NULL,
[Status] INT NOT NULL,
CONSTRAINT [PK_Occurrence] PRIMARY KEY CLUSTERED ([ID] ASC)
);
CREATE TABLE [dbo].[ContributingFactor] (
[ID] INT IDENTITY (1, 1) NOT NULL,
[OccurrenceID] INT NOT NULL,
[Factor] NVARCHAR (250) NOT NULL,
CONSTRAINT [PK_ContributingFactor] PRIMARY KEY CLUSTERED ([ID] ASC, [OccurrenceID] ASC),
CONSTRAINT [FK_ContributingFactor_Occurrence] FOREIGN KEY ([OccurrenceID]) REFERENCES [dbo].[Occurrence] ([ID])
);
</pre>
<br />
Again, as you can see, I'm using a composite key on the child table. Everything else is pretty straightforward. Best of all so far is that nothing has referenced Entity Framework. The domain, the database, the application... They're all entirely ignorant of the specific implementation of the DAL. So now let's move on to that DAL implementation.<br />
<br />
Entity Framework has objects which are analogous to the repository and the unit of work, called DbSet and DbContext respectively. Let's start with the unit of work implementation:<br />
<br />
<pre class="brush: csharp">public class UnitOfWorkImplementation : DbContext, UnitOfWork
{
public DbSet<Occurrence> DBOccurrences { get; set; }
private OccurrenceRepository _occurrenceRepository;
public OccurrenceRepository OccurrenceRepository
{
get
{
if (_occurrenceRepository == null)
_occurrenceRepository = new OccurrenceRepositoryImplementation(this);
return _occurrenceRepository;
}
}
static UnitOfWorkImplementation()
{
Database.SetInitializer<UnitOfWorkImplementation>(null);
// A fix for a known issue with EF
var instance = SqlProviderServices.Instance;
}
public UnitOfWorkImplementation() : base("Name=EFBlogPost") { }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new OccurrenceMap());
modelBuilder.Configurations.Add(new ContributingFactorMap());
}
public void Commit()
{
SaveChanges();
}
}
</pre>
<br />
The interesting bits here are:<br />
<ul>
<li>A reference to the DbSet which will correspond to the repository.</li>
<li>A late-bound repository property to implement the interface. Note that we're passing a reference of the unit of work itself to the constructor, we'll see why when we build the repository.</li>
<li>A static initializer to set the database's initializer. (Also present is a small fix for an issue I spent an hour or so researching online regarding the SqlProvider. Without this line of code that doesn't do anything, Entity Framework was failing to load the provider at runtime. With it, no problems.)</li>
<li>The constructor passes a hard-coded connection string name to the DbContext's constructor. Feel free to make this as dynamic as you'd like.</li>
<li>An override for OnModelCreating which specifies our mappings. We'll create those in a minute.</li>
<li>The Commit implementation for the interface, which just called SaveChanges on the DbContext.</li>
</ul>
So far so good, pretty simple and with minimal code. Now let's see the repository implementation:<br />
<br />
<pre class="brush: csharp">public class OccurrenceRepositoryImplementation : OccurrenceRepository
{
private UnitOfWorkImplementation _unitOfWork;
public IQueryable<Occurrence> Occurrences
{
get { return _unitOfWork.DBOccurrences; }
}
public OccurrenceRepositoryImplementation(UnitOfWorkImplementation unitOfWork)
{
_unitOfWork = unitOfWork;
}
public void Add(Occurrence model)
{
_unitOfWork.DBOccurrences.Add(model);
}
public void Remove(Occurrence model)
{
_unitOfWork.DBOccurrences.Remove(model);
}
}
</pre>
<br />
Even simpler, with even less code. It's basically just a pass-through to the DbSet object referenced on the unit of work implementation. (Indeed, you can just pass the DbSet itself in the constructor instead of the whole unit of work, but this plays nicer with dependency injector graphs.) So far there hasn't been much ugliness from the framework at all. How about the mappings...<br />
<br />
<pre class="brush: csharp">public class OccurrenceMap : EntityTypeConfiguration<Occurrence>
{
public OccurrenceMap()
{
ToTable("Occurrence").HasKey(o => o.ID).Ignore(o => o.FieldToIgnore);
Property(o => o.ID).IsRequired().HasColumnName("ID").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(o => o.InterestingCase).IsRequired().HasColumnName("InterestingCase");
Property(o => o.Comments).IsUnicode().IsOptional().HasColumnName("Comments");
Property(o => o.ReviewStatus).IsRequired().HasColumnName("Status");
}
}
public class ContributingFactorMap : EntityTypeConfiguration<ContributingFactor>
{
public ContributingFactorMap()
{
ToTable("ContributingFactor").HasKey(c => new { c.ID, c.OccurrenceID });
HasRequired(ContributingFactor.OccurrenceProperty).WithMany(o => o.ContributingFactors).HasForeignKey(c => c.OccurrenceID);
Property(c => c.ID).IsRequired().HasColumnName("ID").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(c => c.Factor).IsRequired().IsUnicode().HasColumnName("Factor");
}
}
</pre>
<br />
Still pretty simple and straightforward. Indeed, I've written more code than I really needed to here. A lot of this mapping logic is implicit in the framework, but making it explicit I think makes it more clear and at a cost of very little additional code. Again, the interesting bits:<br />
<ul>
<li>In the parent object's map we set the field to ignore as an extension of defining the table and key.</li>
<li>We explicitly tell it when a column is an identity. For the parent object this actually isn't a problem, the framework figures this out. However for the child object it doesn't figure it out (because of the composite key) and needs to be explicitly specified. I just added the specification to the parent object's mapping as well for consistency.</li>
<li>The child object uses an anonymous type to define the composite key.</li>
<li>The child object requires that a parent object exists.</li>
</ul>
<div>
And, well, that's about it. The code runs as-is and consuming code can instantiate a unit of work, interact with it, commit it, and be done with it. Change tracking is all handled by the framework. Even setting those private fields, since the framework internally uses reflection to do all of this.</div>
<div>
<br /></div>
<div>
In fact, if you inspect your models at runtime you'll find that they're not actually your models, they're a dynamically-built type which inherit from your models (having used reflection to define the type). This is how the framework gets into your domain in this case, to perform entity tracking and all that good stuff. Which is great, because it means that I don't have to actually change my models to account for Entity Framework. The framework does that at runtime, leaving my design-time code unpolluted and re-usable.</div>
<div>
<br /></div>
<div>
All things considered, and I never thought I'd say this... I'm really liking Entity Framework at this point.<br />
<br />
(If interested, the code from this post is available <a href="https://github.com/dpdonahue/EFBlogPost">here</a>.)</div>
testhttp://www.blogger.com/profile/09609860522747123959noreply@blogger.com0tag:blogger.com,1999:blog-6959582839690958035.post-57665416383721543822014-02-27T13:15:00.000-05:002014-02-27T13:15:01.258-05:00It's OK to use POSTI recently attended a great presentation by <a href="http://www.linkedin.com/pub/rob-daigneau/1/102/592">Rob Daigneau</a> on RESTful services, and as with any discussion about REST the group briefly waxed philosophical. (We were a pretty laid back group on the subject, actually. Conversations between software architects about what REST is and what it means can get pretty dogmatic.) And, as any such conversation goes, we ended up asking an age-old question...<br />
<blockquote class="tr_bq">
How can we perform complex searches on a resource?</blockquote>
Rob categorized three general approaches, ordered from least flexible to most flexible:<br />
<br />
<ul>
<li>Query string parameters</li>
<li>Basic DTOs</li>
<li>Complex DTOs with expression trees</li>
</ul>
(Note that this is also ordered from least difficult to most difficult.)<br />
<br />
While we'd all love to have the complex DTOs which can express boolean logic and complex search criteria, I think we can all agree that the vast majority of cases doesn't merit the effort. Most of the time we just use query string parameters, and that's a perfectly workable reality for a lot of cases.<br />
<br />
But some of us (read: me) are purists. We don't want strings, we want <i>objects</i>. Looking at a request with lots of query string parameters is like looking at a function signature with lots of parameters. It's distasteful. For functions which accept complex parameters, we build a structure to hold those parameters. It's why we use model binding in our MVC actions, it's why we use anonymous objects to initialize jQuery plugins, heck for some of us these object oriented principles are why we get out of bed in the morning.<br />
<br />
So we land on the basic DTOs for issuing searches to resources. Right? Sounds good to me. Except... Aren't these GET requests?<br />
<br />
Aye, there's the rub. For in that GET of requests what DTOs may come, when the server have shuffled off the request body?<br />
<br />
The fact that we are purists is what brought us here. And the fact that we are purists is what troubles us still. As a purist for object oriented design principles, we want to use a DTO for our search predicates. As a REST purist, we want to issue a GET request because we're only <i>fetching</i> data, not creating or updating it. A quandary indeed. Or is it?<br />
<br />
Life just wouldn't be the same without semantics. We argue them all the time, and we also use them to our advantage all the time. This situation is no different. So instead of trying to muck with the technology to hopefully put together something that works, let's step back and look at this from a semantic point of view. Let's think about this for a moment not in terms of technologies and implementations, but in terms of patterns and domain languages.<br />
<br />
What is the request that we are making? If we're simply fetching a resource, then clearly it should be a GET request. But... <i>are</i> we simply fetching a resource? Or are we doing something <i>more</i>? Let's look at our object-oriented principles again, since those are what brought us here in the first place. We're not necessarily fetching an <i>instance</i> of a resource, we're fetching a <i>collection</i> of resources. And a collection of objects is itself an object, with its own logic and rules operating at the collection level.<br />
<br />
Let's examine this collection a little further. Does this collection already exist on the server? Its <i>elements</i> exist, and ultimately those are what we're looking to fetch. But does the <i>collection</i> exist? More to the point, does <i>this specific instance</i> of such a collection exist?<br />
<br />
No, it doesn't. We're using custom search criteria for our predicate. We're... <i>creating</i> a new <i>instance</i> of a collection of these entities. And what, dear fellow REST purists, do we use when we're creating a new instance of something? :::drumroll::: POST.<br />
<br />
Take a moment to think about it. Let the ramifications sink in and fit so elegantly into all of the dogmatic puritan notions we share about REST. See the beauty of it.<br />
<br />
Just look at the semantics of our clean URLs. For fetching an instance of a Customer, we might use this:<br />
<blockquote class="tr_bq">
GET /Customers/123</blockquote>
And for creating an instance of a collection of customers, we might use this:<br />
<blockquote class="tr_bq">
POST /CustomerSearches</blockquote>
Clean. Beautiful. Poetic. We're creating a new collection of Customers, unique and unlike any other existing collection that may already be on the server. So we stuff a DTO into the request body, which contains all of the information needed to create this resource, and we get back the resource we just created.<br />
<br />
But wait, there's more. You may have noticed that there's a possibility of a performance boost here. Now, the server makes no guarantee that this new unique instance of a CustomerSearch is going to stay there for long. Indeed, you may expect the server not to retain it at all. But it <i>can</i>. It can store the results, c<i>aching</i> them if you will so as to not bother the backing data store if the user wants to run the same search again before some expiry time, and return an identifier along with the resource. So perhaps some time later the user can issue:<br />
<blockquote class="tr_bq">
GET /CustomerSearches/456</blockquote>
And that user will get back the same results from that previous search. Or maybe it's not even the same results, maybe what was cached were the <i>criteria</i> of the search, and that GET request on CustomerSearches is simply a way to re-run the same search again. (Not unlike how databases cache query execution plans.) The possibilities are all there, and they're all semantically sound with RESTfulness.<br />
<br />
We have beautiful objects, beautiful URLs, and beautiful HTTP verbs. We even have the added benefit of caching results and/or query executions. The purist in me rejoices.<br />
<br />
Now, Rob would be the first to point out that the spec actually allows for POST to be used to solve our original problem anyway. Technically there's nothing wrong with sending the search DTO here:<br />
<blockquote class="tr_bq">
POST /Customers</blockquote>
Go ahead and read <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html">the spec</a> for yourself. POST can indeed be used to handle a number of alternate functions besides simply adding a new instance of a resource. So Rob's right about that, and in most cases that's not only acceptable but prudent and pragmatic. But settling for that doesn't satisfy the purist in me, not one bit. The above scenario, on the other hand, does. It reminds me of the REST promise ring I metaphorically wear (or perhaps the Clean Code wristband).<br />
<br />
Either way, it's OK to use POST for the scenario of a complex search. Both approaches satisfy the spec, and more importantly both work for the system and are easily understood and supportable. The above approach, however, also fills me with that emotion I'm told is called joy.testhttp://www.blogger.com/profile/09609860522747123959noreply@blogger.com0tag:blogger.com,1999:blog-6959582839690958035.post-71996847304914213572014-01-16T15:02:00.003-05:002014-01-16T15:02:36.917-05:00Capitalism - Still A Better Love Story Than TwilightWe live in a capitalist society. And I think that word has become socially distasteful over the years. (To be fair, living any any *-ist society sounds kind of distasteful. Perhaps it's the act of classifying and not the classification itself that's really at the heart of the perception?) We can debate at length as to how and why, or whether or not such perceptions are justified, but that's not what this is about.<div>
<br /></div>
<div>
I am a capitalist. There's that distaste again. Can you feel it? Just by hearing me say that, can you feel an almost foaming-at-the-mouth either in yourself or in others? After all, this means I'm <i>greedy</i>, doesn't it? It means I <i>worship money</i>, right? That I want to enslave the downtrodden so I can stand on their backs and smoke an expensive cigar?</div>
<div>
<br /></div>
<div>
I really don't think that's what it means. I honestly don't draw such a connection between being an active part of the society in which I live and being <a href="http://en.wikipedia.org/wiki/Kingpin_(comics)">Kingpin</a>. Though I've certainly met (or in some way interacted with) a fair number of people who, for whatever reason or set of reasons, don't separate the two concepts. And that's too bad for them, really.</div>
<div>
<br /></div>
<div>
Capitalism is not inherently evil. Are there evil people within capitalist societies? People who lie, bully, extort, and generally do terrible things for personal gain? Absolutely. If you can find me <i>any</i> society in the entirety of human history, capitalist or otherwise, which didn't suffer from that plague then I'm certainly interested to hear about it.</div>
<div>
<br /></div>
<div>
So no, I don't sit around reading Ayn Rand and thinking of ways I can abuse people and take their money. To be honest, I barely only tangentially knew who Ayn Rand was until the accusations of this behavior started to become more frequent. Cursory research on the subject led me to three conclusions about her work:</div>
<div>
<ol>
<li>Her fiction work was awful. I mean really just abysmal. This isn't to say that mine is any better (or even, you know, extant), but that's neither here nor there. If you're curious to learn just <i>how bad</i> it is but don't want to invest the time in reading one of her novels (who could blame you?), know that at the time of this writing parts 1 and 2 of the Atlas Shrugged movies are available for your viewing, um, pleasure. Pay close attention to the forced narrative, un-relatable characters, and absurd storyline.</li>
<li>People who claim to hate her are <i>obsessed</i> with her. Again, the name was barely a footnote in my knowledge prior to encountering such people. Prior to this writing, I don't recall ever once injecting the subject into any conversation. But she sure has come up a lot from other people. I guess I don't see the attraction.</li>
<li>To disagree with her philosophies is a human right. To deny her impact on modern business practices is, at best, naive.</li>
</ol>
<div>
But I digress. A lot. This isn't about the notion that people fervently accuse me of evil deeds simply because I have a fairly successful career. No, this is about a little corner of capitalism that is often forgotten. This is about the idea that just because we're looking at a spreadsheet of numbers doesn't necessarily conclude that we're not doing something good for the world.</div>
</div>
<div>
<br /></div>
<div>
That's all it really comes down to, isn't it? A spreadsheet of numbers? Capitalism isn't about being evil. There are no <a href="http://en.wikipedia.org/wiki/Captain_Planet_and_the_Planeteers">Captain Planet</a> villains who spend billions on a business model that has no customers, only destructive deeds. It's about money. You know, <i>capital</i>. The rules are simple. If the gain outweighs the cost, it's a go. (Of course, there is much disagreement about the "cost" of non-tangibles, such as employee work/life balances or environmental damage. There is much disagreement about a lot of things. Welcome to life.)</div>
<div>
<br /></div>
<div>
At its simplest, if the numbers in Column A add up to more than the numbers in Column B then clearly Column A is the sound choice. All the complaining and arguing in the world isn't going to change the clarity of numbers. However, with a little reason and pragmatism, you can change the numbers themselves.</div>
<div>
<br /></div>
<div>
They're just variables. Values with weights assigned to them. If you <i>desperately want</i> Column B to be the outcome of the decision then your goal is pretty clear. Is your goal to argue? No. Is your goal to accuse the supporters of Column A of malfeasance? That doesn't seem productive either. Indeed, your goal is to <i>get more numbers</i>. What other factors haven't been considered? What other variables can be weighed and accounted? Outside of what other <i>boxes</i> can you <i>think</i>?</div>
<div>
<br /></div>
<div>
Because guess what? That <i>works</i>. I doubt any business leader or board member or what-have-you has ever been under the delusion of knowing <i>everything</i>. Sure, they may put up a front of sorts, because that's part of their job. But business decisions are based on information. And with a goal as clear as <i>one number being greater than another number</i> acting upon information seems like a pretty straightforward activity.</div>
<div>
<br /></div>
<div>
So... What information can you add to the discussion? Keep in mind that your personal opinions, regardless of how much passion you have for those opinions, are not information. Sorry to break it to you, but strongly-held opinions are not facts.</div>
<div>
<br /></div>
<div>
But that's not necessarily <i>evil</i>. No more than the application of the <a href="http://en.wikipedia.org/wiki/Scientific_method">scientific method</a> in research is <i>evil</i>. I dare say that a separation of opinion from fact is a cornerstone of enlightened society. (Though that's just my opinion.)</div>
<div>
<br /></div>
<div>
Now before the accusations fly again, let me assure you that I still realize that there are bad people who do bad things in the world. I toil under no delusion that capitalism <i>by design</i> is "good" (whatever that word means) or benevolent. (There is, after all, <i>a lot</i> of money to be made in standing on the backs of others. I don't personally do that, but it's hard to deny the motivations of those who do.) But just as it's not one extreme of that particular spectrum, it's also not the other.</div>
<div>
<br /></div>
<div>
Somewhere in the middle, in an oft forgotten corner of society, there exist numbers which add up to really, really good things. And when they do, it is indeed the function of capitalism which turns those good numbers into those good things. After all, if Column A is a greater sum than Column B then there's profit to be made. And if Column A also happens to be really good for the world, so much the better, right?</div>
<div>
<br /></div>
<div>
I sometimes refer to this phenomenon as The Lost Dream Of Capitalism. And, yes, I have examples.</div>
<div>
<br /></div>
<div>
Have you seen how <a href="http://www.huffingtonpost.com/2011/09/30/utah-homelessness-rate-plummets_n_987695.html">Utah is planning to end homelessness</a>? The statement alone sounds pretty good, doesn't it? But surely, <i>surely</i> such an endeavor would be expensive and nobody would want to pay for it, right? Nope. It's actually going to be <i>cheaper</i>. How did they come up with this? Simple. The numbers in Column A added up to more than the numbers in Column B.</div>
<div>
<br /></div>
<div>
The premise is financially sound. A bit of research into some data, pivoted and examined in the right light, led to a fascinating conclusion. The state basically figured out how much money they pay to subsidize emergency room services for care directly resulting from the poor living conditions of the homeless. (This is Column B.) Then they figured out how much it would cost to <i>give</i> apartments to their homeless population and assign them case-workers to help them become self-sustaining. (This is Column A.)</div>
<div>
<br /></div>
<div>
Both columns are a deficit, clearly. Both involve spending tax money. But the two numbers are not equal. While still in the negative, Column A was a <i>greater value</i> than Column B. It was a <i>net gain</i> for the budget. <i>Helping people was deemed profitable</i>. So, in traditional capitalist style, the more fiscally-sound choice was made. And, lo and behold, it <i>wasn't inherently evil</i>.</div>
<div>
<br /></div>
<div>
There are, indeed, a lot of businesses who are actively working toward this same fiscal model. A little closer to home for me is the company <a href="http://www.dovetailhealth.com/">Dovetail Health</a>. This is a company which reduces healthcare costs, increases patient care quality, and <i>makes money doing it</i>. (And they're not alone, they're just the only one I know off-hand.)</div>
<div>
<br /></div>
<div>
The business model is simple... Intervene in patient care conditions outside of a hospital setting at periodic intervals for the purpose of preventing further hospital visits. After all, hospital visits are expensive. <i>Really expensive</i>. But with a little bit of in-home intervention and comparatively simple patient care, hospital visits can be avoided. Insurance companies pay less for care (win), benefits-holders pay less for insurance (win), hospitals pay less in overhead (win), patients are healthier and more effectively avoid injuries (win), and finally... the company doing this makes money (win). Where's the evil in that last one again? Cause I'm not seeing it.</div>
<div>
<br /></div>
<div>
By thinking outside of a box or two, shifting the occasional paradigm, or whatever cliche business gobbledygook you want to use, the idea of making money can actually conform with the idea of improving the world in which we live.</div>
<div>
<br /></div>
<div>
It's something people don't often see when they look at the (evil) capitalist society around us. But for those who find it, for those who participate in it, the monetary rewards alone pale in comparison to the profound sense of community and fraternity to be found in not just doing something well, but doing something... <i>good</i>. Therein lies that lost dream of capitalism. Stepping outside the stereotype of nickeling-and-diming everybody into oblivion to squeeze more profit from society, and stepping into the simple notion of putting the right numbers into Column A to actually make the world a slightly better place to live.</div>
<div>
<br /></div>
<div>
It's all too rare, hence the "lost dream." But it's real. It exists. And if I can wish for anything on the subject it would be that the rabid opponents to the very <i>word</i> "capitalism" could step away from their Facebook rants for a moment and actually help with efforts like this. Actually use their intelligence for the better. The world could use better numbers in Column A, it can't use angry Facebook posts.</div>
testhttp://www.blogger.com/profile/09609860522747123959noreply@blogger.com0tag:blogger.com,1999:blog-6959582839690958035.post-50212597987740162282013-10-29T11:45:00.003-04:002013-12-18T09:24:39.626-05:00Refactoring Screencasts VThere exist a host of excuses for why it took so long to get these finished. But they boil down to two:<br />
<div>
<ol>
<li>There is no quiet place to record at home.</li>
<li>There is no quiet place to record at work.</li>
</ol>
<div>
The first one is being remedied as we speak, for I'm in the process of moving to a new house and there will be space to set aside for a make-shift "recording studio" in said house. (Which will basically be a table and chair in the basement with some heavy blankets draped around it for sound dampening. But it's something at least. Note, however, that this "being remedied" is a long and drawn-out process, to be followed by the holidays, so I may be quiet for a while. But I digress...)</div>
</div>
<div>
<br /></div>
<div>
The second one hadn't been a problem during the summer, when my work mainly involved travel and hotel rooms are notoriously quiet when one is alone. However, for some time now I've been "between projects" and mainly sitting around in the company's office. (Which is not normally where a consultant spends his time.) Again, normally this isn't a problem. We have a conference room for this sort of thing. But another large project has been much taken over our office's conference room, for reasons I'm not aware of but aren't so uncommon to bear going into.</div>
<div>
<br /></div>
<div>
Yesterday, however, the conference room was inexplicably empty. So I was able to knock out the remaining recordings for the Making Method Calls Simpler series in an afternoon. Hopefully they don't appear hurried as a result. In any event, here they are. Enjoy!</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<object class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="http://i1.ytimg.com/vi/iShbl_0-4BY/0.jpg" height="266" width="320"><param name="movie" value="http://www.youtube.com/v/iShbl_0-4BY?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" /><param name="bgcolor" value="#FFFFFF" /><param name="allowFullScreen" value="true" /><embed width="320" height="266" src="http://www.youtube.com/v/iShbl_0-4BY?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" type="application/x-shockwave-flash" allowfullscreen="true"></embed></object></div>
<div style="text-align: center;">
Rename Method</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/MiKyMPn1Zaw?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
Add Parameter</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/HoJyPtIcMqU?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
Remove Parameter</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/S3d0ydyZIi0?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
Separate Query From Modifier</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/ALjKXW4YNbo?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
Parameterize Method</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/uO2Y6aIKsIw?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
Replace Parameter With Explicit Methods</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/TRzuoB67BBI?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
Preserve Whole Object</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<object class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="http://i1.ytimg.com/vi/d6TW_lgNn4U/0.jpg" height="266" width="320"><param name="movie" value="http://www.youtube.com/v/d6TW_lgNn4U?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" /><param name="bgcolor" value="#FFFFFF" /><param name="allowFullScreen" value="true" /><embed width="320" height="266" src="http://www.youtube.com/v/d6TW_lgNn4U?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" type="application/x-shockwave-flash" allowfullscreen="true"></embed></object></div>
<div class="separator" style="clear: both; text-align: center;">
Replace Parameter With Method</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<object class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="http://i1.ytimg.com/vi/SzFe-C_ZHBI/0.jpg" height="266" width="320"><param name="movie" value="http://www.youtube.com/v/SzFe-C_ZHBI?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" /><param name="bgcolor" value="#FFFFFF" /><param name="allowFullScreen" value="true" /><embed width="320" height="266" src="http://www.youtube.com/v/SzFe-C_ZHBI?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" type="application/x-shockwave-flash" allowfullscreen="true"></embed></object></div>
<div class="separator" style="clear: both; text-align: center;">
Introduce Parameter Object</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/IsVJ-EJctUU?feature=player_embedded' frameborder='0'></iframe></div>
<div class="separator" style="clear: both; text-align: center;">
Remove Setting Method</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/b-mfm6U1l8U?feature=player_embedded' frameborder='0'></iframe></div>
<div class="separator" style="clear: both; text-align: center;">
Hide Method</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/FIUsB6Oshhk?feature=player_embedded' frameborder='0'></iframe></div>
<div class="separator" style="clear: both; text-align: center;">
Replace Constructor With Factory Method</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/cHO930Q45bc?feature=player_embedded' frameborder='0'></iframe></div>
<div class="separator" style="clear: both; text-align: center;">
Encapsulate Downcast</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/sI9pznrfCPo?feature=player_embedded' frameborder='0'></iframe></div>
<div class="separator" style="clear: both; text-align: center;">
Replace Error Code With Exception</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/HfayrmLF4E0?feature=player_embedded' frameborder='0'></iframe></div>
<div class="separator" style="clear: both; text-align: center;">
Replace Exception With Test</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Next I'll move on to the Dealing With Generalization series of patterns.</div>
testhttp://www.blogger.com/profile/09609860522747123959noreply@blogger.com0tag:blogger.com,1999:blog-6959582839690958035.post-12036635679556996702013-10-25T13:33:00.000-04:002013-10-25T13:33:39.258-04:00The Left Turn At AlbuquerqueBugs Bunny is lost. <i>Really</i> lost. And looking at a map of his current location doesn't seem to be helping him.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAnpr6TtWPmxyZwHpKBz_Vn0pRJG7HZoQeHUSzk67pJh8GYm5BereUINzeDL6Hziq3LLX1xD7dJGC_GPyNwe-CFGly634bLDmO6TSzBU7aW5dC2u3xO5LjIGeHQuwxDNm_a937cO61PKZe/s1600/0.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAnpr6TtWPmxyZwHpKBz_Vn0pRJG7HZoQeHUSzk67pJh8GYm5BereUINzeDL6Hziq3LLX1xD7dJGC_GPyNwe-CFGly634bLDmO6TSzBU7aW5dC2u3xO5LjIGeHQuwxDNm_a937cO61PKZe/s320/0.jpg" width="320" /></a></div>
You see, he should have taken that left turn back at Albuquerque. Unfortunately, he missed that turn and just kept going in the wrong direction. And kept going, and kept going. Where is he now? Is this place even on his map? One thing's for certain... Getting from where he is now to where he wants to be isn't going to be easy. His original intent assumed a left turn at Albuquerque, so by definition <i>everything</i> he's done since then has been wrong.<br />
<br />
This happens to programmers a lot. Invariably they find their way to <a href="http://stackoverflow.com/">Stack Overflow</a> to ask a question about where they should go next. And very often they get a series of comments similar to this:<br />
<blockquote class="tr_bq">
"Why are you doing it that way? There's no need for that. You're doing something else wrong."</blockquote>
It seems unhelpful on its face, but it's exactly the problem the programmer is facing. He's trying to solve a problem that he <i>shouldn't have in the first place</i>. And he's getting frustrated by the fact that there isn't a readily available solution to the problem that he just invented.<br />
<br />
How should Bugs Bunny get to where he's going? Well, we don't know. We'll never know, because he didn't tell us where he's going. Nor did he tell us where he came from. We don't know the problem domain that he's trying to solve.<br />
<br />
The programmer needs to step back for a moment and examine the bigger picture. It's not that we don't want to help him solve his problem, it's that we don't know what the <i>actual</i> problem is. And we need to know that to be of any use. Sure, maybe we can help him with his current roadblock. Then he'll just come back in an hour trying to solve his next roadblock.<br />
<br />
If Bugs Bunny's tunnel encounters a massive outcropping of rock, he's going to ask someone how to get around that rock. And maybe they'll show him. Great, now he's on the other side of the rock. But is he any closer to his destination? We don't know, because that's not what he asked us. He only asked us how to get around the rock.<br />
<br />
The programmer took a wrong turn somewhere. Perhaps a <i>very</i> wrong turn. Perhaps somewhere a <i>long</i> time ago. We don't know. All we know is that the sequence of steps, with no weights assigned to them to provide any perspective, went something like this:<br />
<ol>
<li>Programmer performed Step 1.</li>
<li>Programmer performed Step 2.</li>
<li>Programmer messed up on Step 3.</li>
<li>Programmer figured out how to perform Step A.</li>
<li>Programmer figured out how to perform Step þ.</li>
<li>Programmer got stuck on Step ± and asked for help.</li>
<li>Programmer became frustrated that the help didn't get him any closer to Step 10.</li>
<li>Rinse, repeat.</li>
</ol>
<div>
We want to help this programmer. We really do. But we can't unless we know the actual problem he's trying to solve. Not the immediate roadblock he's facing right now, but the actual problem being solved.</div>
<div>
<br /></div>
<div>
I guess if there's any piece of advice I can give from this little rant, it's this...</div>
<div>
<ul>
<li>Never assume that everything you've done until now has been correct.</li>
<li>Never assume that just because you got something to work it means you're any closer to your goal.</li>
</ul>
</div>
testhttp://www.blogger.com/profile/09609860522747123959noreply@blogger.com0tag:blogger.com,1999:blog-6959582839690958035.post-87593620706060939132013-09-21T18:12:00.002-04:002013-09-21T18:12:52.444-04:00Refactoring Screencasts IVContinuing the series, here are the screencasts for Simplifying Conditional Expressions. Enjoy!<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/L-uA8GfiwFM?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
Decompose Conditional</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/8GvvfGWzlRc?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
Consolidate Conditional Expression</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/Ig9mQeoOJl8?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
Consolidate Duplicate Conditional Fragments</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/rcbgHs93BO8?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
Remove Control Flag</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/uT-SAW1AV6Y?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
Replace Nested Conditional With Guard Clauses</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<object width="320" height="266" class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="http://i1.ytimg.com/vi/NCsoEEz_Ta0/0.jpg"><param name="movie" value="http://www.youtube.com/v/NCsoEEz_Ta0?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" /><param name="bgcolor" value="#FFFFFF" /><param name="allowFullScreen" value="true" /><embed width="320" height="266" src="http://www.youtube.com/v/NCsoEEz_Ta0?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" type="application/x-shockwave-flash" allowfullscreen="true"></embed></object></div>
<div style="text-align: center;">
Replace Conditional With Polymorphism</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/v6l5jd3VPZA?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
Introduce Null Object</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/NFCe-tYzb1Y?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
Introduce Assertion</div>
testhttp://www.blogger.com/profile/09609860522747123959noreply@blogger.com0tag:blogger.com,1999:blog-6959582839690958035.post-61953366999553478442013-09-03T14:27:00.001-04:002013-09-03T14:27:12.729-04:00Refactoring Screencasts IIII know, this took a lot longer than expected. But it's been an interesting summer employment-wise. Lots of travel, lots of experiences, etc. I finally finished this series though, and have continued well into the next one.<br />
<br />
It's worth noting that I skipped three of the patterns in this series.<br />
<ul>
<li>I skipped Self-Encapsulate Field because the differences in how inheritance work in C# vs. Java were getting in the way, and ultimately the C# version was essentially identical to Encapsulate Field.</li>
<li>I also skipped Duplicate Observed Data because <i>a lot</i> has changed over the years in terms of data binding and the tooling that's available.</li>
<li>And I skipped Replace Record With Data Class because in modern tooling it seemed <i>really similar</i> to Replace Array With Data Class. (Though it's likely that I missed a key point/difference.) </li>
</ul>
<br />
Without further ado, here are the videos for the Organizing Data patterns:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<object width="320" height="266" class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="http://i1.ytimg.com/vi/z0F1zLO0_40/0.jpg"><param name="movie" value="http://www.youtube.com/v/z0F1zLO0_40?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" /><param name="bgcolor" value="#FFFFFF" /><param name="allowFullScreen" value="true" /><embed width="320" height="266" src="http://www.youtube.com/v/z0F1zLO0_40?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" type="application/x-shockwave-flash" allowfullscreen="true"></embed></object></div>
<div style="text-align: center;">
Replace Data Value With Object</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<object width="320" height="266" class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="http://i1.ytimg.com/vi/lUHu3_BijJo/0.jpg"><param name="movie" value="http://www.youtube.com/v/lUHu3_BijJo?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" /><param name="bgcolor" value="#FFFFFF" /><param name="allowFullScreen" value="true" /><embed width="320" height="266" src="http://www.youtube.com/v/lUHu3_BijJo?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" type="application/x-shockwave-flash" allowfullscreen="true"></embed></object></div>
<div style="text-align: center;">
Change Value To Reference</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<object width="320" height="266" class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="http://i1.ytimg.com/vi/3j_EFAbWW9Y/0.jpg"><param name="movie" value="http://www.youtube.com/v/3j_EFAbWW9Y?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" /><param name="bgcolor" value="#FFFFFF" /><param name="allowFullScreen" value="true" /><embed width="320" height="266" src="http://www.youtube.com/v/3j_EFAbWW9Y?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" type="application/x-shockwave-flash" allowfullscreen="true"></embed></object></div>
<div style="text-align: center;">
Change Reference To Value</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/bekpt1ihrKs?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
Replace Array With Object</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/Lsw4Acn5Sfg?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
Change Unidirectional Association To Bidirectional</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/9-E0xONjLNE?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
Change Bidirectional Association To Unidirectional</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/UTNParCCyQ8?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
Replace Magic Number With Symbolic Constant</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/p1ZGHJweVbc?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
Encapsulate Field</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<object width="320" height="266" class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="http://i1.ytimg.com/vi/_twxZnyywik/0.jpg"><param name="movie" value="http://www.youtube.com/v/_twxZnyywik?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" /><param name="bgcolor" value="#FFFFFF" /><param name="allowFullScreen" value="true" /><embed width="320" height="266" src="http://www.youtube.com/v/_twxZnyywik?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" type="application/x-shockwave-flash" allowfullscreen="true"></embed></object></div>
<div style="text-align: center;">
Encapsulate Collection</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/9RKvyBSC1H0?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
Replace Type Code With Class</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/0pWinOxlqyI?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
Replace Type Code With Subclasses</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/nOX27nHmFKQ?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
Replace Type Code With State/Strategy</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/apSlxPYKDOQ?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
Replace Subclass With Fields</div>
testhttp://www.blogger.com/profile/09609860522747123959noreply@blogger.com0tag:blogger.com,1999:blog-6959582839690958035.post-61434290311203037212013-07-24T11:21:00.000-04:002013-08-05T09:09:25.098-04:00Where The Money Comes FromThe more corporate entities I encounter in my career, the more patterns start to emerge. And one set of patterns I've been particular keen to find are those which tend to cause agile adoption to fail. "Agile" itself has clearly moved from the periphery to the mainstream, at least as a buzzword. In today's world no manager wants to admit to a <i>lack of agility</i> after all. But beyond the buzzword is an actual adoption of software development practices which, more often than not in my experience, fail to meet the goal and really end up being the same old status quo with just new names for the meetings.<br />
<div>
<br /></div>
<div>
There are many reasons why agile adoption can fail. It can range from a manager/director/executive/etc. who simply "doesn't get it" to an entire corporate culture which is inherently opposed to it. However, in many cases these failures to adopt seem to stem from some common factors in how the projects themselves are treated at a financial level. In many cases, it seem that the very <i>source of the money</i> for the project is a make-or-break factor for a successful adoption of agile practices.</div>
<div>
<br /></div>
<div>
Now, let me preface this by clarifying that I'm not an accountant. While I'm confident that my own checkbook is balanced and my own finances are handled, I know almost nothing of corporate accounting and budgets and finance at that level. Honestly, it's all white noise to me. I simply have no interest in the subject. But there is one thing I do know. There are two very different kinds of budgets tracked in two very different ways:</div>
<div>
<ul>
<li>One-time up-front costs</li>
<li>Periodic ongoing costs</li>
</ul>
<div>
They're tracked separately on whatever spreadsheets are used to track these things. And they're financed very differently throughout corporate accounting structures.</div>
</div>
<div>
<br /></div>
<div>
Now consider a software project in any corporate setting. There's an identified business need to make something or enhance something to address an operational concern. And so that project is going to need some money. It's going to need a budget of funds. Where does that budget come from?</div>
<div>
<ul>
<li>One-time up-front costs</li>
</ul>
<div>
That budget is defined as a fixed figure for one single up-front "purchase" of the project. "For $1.5M we can add these new features to the software. It will take a team of X people Y months to complete." The problem is, that's not really how "agile" approaches things. We don't plan Y months in advance down to every detail. We can't. The very nature of what we're doing has identified that such a plan is inherently incorrect because at the very start of the project is when we know the least about it. But I'm not going to go into the details of what agile is and how it works in this article...</div>
</div>
<div>
<br /></div>
<div>
When you consider the structure of an agile software development environment, it's based entirely on iterations of work. Each iteration adjusts its structure based on the successes or failures of the previous iteration. Each iteration is an opportunity for the business to change direction or adjust priorities. Each iteration is an isolated and complete period of development in an ongoing effort. So, from where does it <i>make more sense</i> for the money to come?</div>
<div>
<ul>
<li>Periodic ongoing costs</li>
</ul>
<div>
When asked "how long will it take to complete" or "what is the whole thing going to cost me" we often try to explain that "agile doesn't work that way." To someone who has a budget in one hand and a calendar in the other, that's not an acceptable answer. We have to go deeper than that. We have to engage at an earlier time, before the budget is defined, and guide the corporate entity not only on how to manage an agile team but even how to <i>finance</i> an agile team.</div>
</div>
<div>
<br /></div>
<div>
With a single up-front budget, the iterations are simply burning efforts against that budget. No matter how you slice it up, it's a countdown to "no more money" and a march toward "no more time." Whichever end-game is reached first becomes the deciding factor for the project, regardless of whether the product is ready or not. And, throughout that march, how often did we sell "agility" to the business in the form of changes to scope or priority? How much has the overhead of that cost us against the original budget? Can we still make it before the deadline?</div>
<div>
<br /></div>
<div>
But with on ongoing periodic budget, the control of when anything is finished is entirely in the hands of the business managing the project. It's no longer even a "project" per se, but rather simply a "capacity of work." Each iteration has a capacity, and a certain amount of work can be done in that iteration. As the periodic budget allows, capacity can be increased or decreased. There's really no "end-game" in this scenario, simply the ongoing capacity of work.</div>
<div>
<br /></div>
<div>
It's not that the managers of a failing agile adoption "don't get it." It's that an inaccurate direction was set before we got there. The questions they're asking ("when will it be done" and "how much will it cost") are directly derived from their budgeting concerns, which is what fundamentally drives the business. As an industry we've successfully brought agile into the development domain (even though most adoptions are still unsuccessful, the attempts at least indicate that the desire is there), but we have to continue to adapt to the rest of the corporate structure as well.</div>
<div>
<br /></div>
<div>
We have to not only <i>develop</i> our software with agility, we have to <i>finance</i> our software with agility.</div>
testhttp://www.blogger.com/profile/09609860522747123959noreply@blogger.com0tag:blogger.com,1999:blog-6959582839690958035.post-61002969979088782342013-07-15T11:09:00.002-04:002013-07-15T11:09:52.471-04:00Refactoring Screencasts IIHere are some videos I made for the second series of <a href="http://www.amazon.com/Refactoring-Improving-Design-Existing-Code/dp/0201485672">Martin Fowler's refactoring patterns</a>, called Moving Features Between Objects. Enjoy!<br />
<br />
<div style="text-align: center;">
Move Method:</div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/yGxk1mU9uyc?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: center;">
Move Field:</div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/lPKjdy07Z1o?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: center;">
Extract Class:</div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/V9tm2av-v8g?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: center;">
Inline Class:</div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/Nanc5l9bwpo?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: center;">
Hide Delegate:</div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/Ocimeg5kXBI?feature=player_embedded' frameborder='0'></iframe></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
Remove Middle Man:</div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/jJfY0D0j5TU?feature=player_embedded' frameborder='0'></iframe></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
Introduce Foreign Method:</div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/XkrtVVbDIEU?feature=player_embedded' frameborder='0'></iframe></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
Introduce Local Extension:</div>
<div class="separator" style="clear: both; text-align: center;">
<object width="320" height="266" class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="http://i1.ytimg.com/vi/7UZAGMvv_74/0.jpg"><param name="movie" value="http://www.youtube.com/v/7UZAGMvv_74?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" /><param name="bgcolor" value="#FFFFFF" /><param name="allowFullScreen" value="true" /><embed width="320" height="266" src="http://www.youtube.com/v/7UZAGMvv_74?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" type="application/x-shockwave-flash" allowfullscreen="true"></embed></object></div>
testhttp://www.blogger.com/profile/09609860522747123959noreply@blogger.com0tag:blogger.com,1999:blog-6959582839690958035.post-67239496728212317222013-07-08T15:52:00.000-04:002013-07-08T15:52:10.271-04:00Refactoring ScreencastsProbably the biggest reason why I've been quiet for a while is that I've been focusing my efforts on some more company-internal stuff recently. Most notably a Code Dojo for my colleagues. It's a ton of fun, and we're sort of feeling our way around how to make it work. (I'm finding a lot of good information in <a href="https://leanpub.com/codingdojohandbook">Emily Bache's book</a> on the subject, too.)<div>
<br /></div>
<div>
Given the team's vast geographic disparities, we've tried a few dojo-ish off-shoot styles to fit a strictly online-only (Microsoft Lync mostly), including walking though various samples and tutorials and such. Essentially treating the whole thing as a collaborative learning space for whatever we want to learn or share.</div>
<div>
<br /></div>
<div>
In that format, one of the things we've walked through was <a href="http://www.amazon.com/Refactoring-Improving-Design-Existing-Code/dp/0201485672">Martin Fowler's refactoring patterns</a>. And I promised my colleagues that I'd make some persistent screencasts of the patterns that can be retained going forward, mostly since it wasn't really proper dojo format and is less likely to be repeated. Well, I've finally had a chance to start recording them, so here's the first series walking through the Composing Methods patterns:</div>
<div>
<br /></div>
<div style="text-align: center;">
Extract Method:</div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/mFIiGg5zO5c?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: center;">
Inline Method:</div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/Itl67XWTi2Q?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: center;">
Inline Temp:</div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/p5gzEhfBBIs?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: center;">
Replace Temp With Query:</div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/KIJXT7TQSbI?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: center;">
Introduce Explaining Variable:</div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/1dDCFwCMeJc?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: center;">
Split Temporary Variable:</div>
<div class="separator" style="clear: both; text-align: center;">
<object width="320" height="266" class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="http://i1.ytimg.com/vi/B_6yFjmGcNs/0.jpg"><param name="movie" value="http://www.youtube.com/v/B_6yFjmGcNs?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" /><param name="bgcolor" value="#FFFFFF" /><param name="allowFullScreen" value="true" /><embed width="320" height="266" src="http://www.youtube.com/v/B_6yFjmGcNs?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" type="application/x-shockwave-flash" allowfullscreen="true"></embed></object></div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: center;">
Remove Assignments To Parameters:</div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/2NZlIq5yAUc?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: center;">
Replace Method With Method Object:</div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/Emyyp8giuf0?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: center;">
Substitute Algorithm:</div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/UIVwcya4XIA?feature=player_embedded' frameborder='0'></iframe></div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: left;">
That's in for the first series. More to come!</div>
testhttp://www.blogger.com/profile/09609860522747123959noreply@blogger.com0tag:blogger.com,1999:blog-6959582839690958035.post-14538449409890923522013-05-28T12:52:00.001-04:002013-05-28T12:52:35.196-04:00StructureMap Convention ScannerSeveral jobs ago, an architect introduced his team (of which I was a member) to dependency injection, specifically using StructureMap. Admittedly it took me a while to get it, but once I did I became hooked and have been ever since. To this day I still prefer StructureMap, if for no other reason than I'm very familiar with it.<br />
<div>
<br /></div>
<div>
And over the years, my use of this tool has rarely seen drastic change. The pattern from that old team, which used the Common Service Locator (of which I use a smaller home-grown version), worked very well and has fit the bill for almost all of my control inverting needs. From time to time, however, I would come up with some new need and have to create something new to handle it.</div>
<div>
<br /></div>
<div>
To date, my biggest change was the use of a custom convention scanner. Nothing fancy, it just scanned assemblies and used my own custom naming convention for interfaces (<a href="http://publicvoidlife.blogspot.com/2012/05/dropping-i.html">I dropped the "I" and never looked back</a>) and matched implementations to interfaces. The scanner itself looked like this:</div>
<div>
<br /></div>
<div>
<pre class="brush: csharp">public class DomainInterfaceNamingConvention : IRegistrationConvention
{
public void Process(Type type, Registry registry)
{
if (IsntRegisterable(type))
return;
Type interfaceType = type.GetInterface(type.Name.Replace("Implementation", string.Empty));
registry.AddType(interfaceType, type);
}
private bool IsntRegisterable(Type type)
{
return type.IsAbstract || !type.IsClass || !ImplementsACustomInterface(type);
}
private bool ImplementsACustomInterface(Type type)
{
foreach (var iface in type.GetInterfaces())
if (iface.Namespace.Contains("Acme"))
return true;
return false;
}
}
</pre>
</div>
<div>
<br /></div>
<div>
Simple enough. If the type is one of the types I want to register, it gets the interface that it's implementing based on the word "Implementation" at the end of that interface (my own convention, favored over configuration) and adds it to the registry. This has worked splendidly for years. Until I thought of something I wanted to support but couldn't with this.<br />
<br />
This convention assumes something I'd always been assuming and had never bothered me. Namely that all instances are default instances. And in all fairness, I've never had a need for named instances. I was able to swap out different implementations by changing some custom configuration settings. The bootstrapper which references this convention scanner would dynamically build the assemblies based on those configuration settings.<br />
<br />
So, let's say I have three implementations of a set of data repositories. Using a naming convention (favored over configuration again, and borrowed in large part from that same job long ago), the assemblies would be named something like this:<br />
<br />
<ul>
<li>Acme.Infrastructure.DAL.SQLExpress</li>
<li>Acme.Infrastructure.DAL.XMLFiles</li>
<li>Acme.Infrastructure.DAL.Mock</li>
</ul>
<div>
These would be three valid implementations of my repositories, all transparent to the rest of the domain, and which one any given application instance uses would be a config setting.</div>
<div>
<br /></div>
<div>
But recently I found a situation where I might want the same application instance to use multiple implementations for the same dependency. Without going into too many details, let's say for the sake of argument that the application needs to move data from one place to another. If I can only use one implementation of a given dependency, then one of those two "places" would have to be a completely different dependency.</div>
<div>
<br /></div>
<div>
This led me down a distasteful path. Things which logically should just be repository implementations (because they're just persisting data) ended up being their own isolated dependencies, filled with DTOs that were littering my models.</div>
<div>
<br /></div>
<div>
The first example of this on a project was when I had to integrate some different calendar systems into our event data. We have a database for storing event data, and that's essentially the system of record for that data. It has repository implementations accordingly. However, the business wanted to manage events using a third party tool (in this case some crappy-but-functional desktop calendar application), and additionally wanted to publish events to a third party tool (in this case, Google Calendar).</div>
<div>
<br /></div>
<div>
Well, the DAL dependency was already taken up by the event data repositories. So I introduced a new dependency called CalendarManager and another called CalendarPublisher. I wrote implementations for them using these two third party systems, as well as mock implementations for testing. And essentially the process would be to read from the CalendarManager, persist to the Repositories, perform some domain logic, read from the Repositories, persist to the CalendarPublisher.</div>
<div>
<br /></div>
<div>
It worked, but it was distasteful. I already have models and repository structures for Events. These other dependencies <i>should</i> just be alternate implementations of the repositories for those models. But then one application instance wouldn't be able to use all three.</div>
<div>
<br /></div>
<div>
What I needed were named instances. But whenever I've seen named instances used in the past, they were on a class level instead of an assembly level. I don't want to have to specify every individual class in my bootstrapping code. For starters, that would favor configuration over convention which I don't want to do. But more importantly it would mean that any implementation or any interface that's added to the domain would have to be manually specified there. Unintuitive at best, error prone at worst. I'd much rather just have to specify the assemblies (of which there are several) instead of the classes (of which there are hundreds).</div>
<div>
<br /></div>
<div>
So how can I name my instances at the assembly level? How can I scan my assemblies and add them into the object graph from which I could essentially pull named instances like this?:</div>
<div>
<br /></div>
<div>
<pre class="brush: csharp">var eventSource = IoCFactory.GetInstance<EventRepository>("CalendarPlanner");
var eventDestination = IoCFactory.GetInstance<EventRepository>("GoogleCalendar");
var eventData = IoCFactory.GetInstance<EventRepository>();</pre>
</div>
<div>
<br /></div>
<div>
Basically I'm looking to be able to specify an instance, or take a default. (In this case the default for the repositories would be the database implementation.)<br />
<br />
After some back and forth on Stack Overflow and a lot of tinkering, I've ended up with this:<br />
<br />
<pre class="brush: csharp">public class DomainInterfaceNamingConvention : IRegistrationConvention
{
public void Process(Type type, Registry registry)
{
if (IsntRegisterable(type))
return;
var interfaceType = GetInterfaceType(type);
var dependencyName = GetDependencyName(type);
var implementationName = GetImplementationName(type);
AddInstanceUnlessOverridden(type, registry, interfaceType, dependencyName, implementationName);
AddInstanceOverrides(type, registry, interfaceType, dependencyName, implementationName);
AddDefaultInstance(type, registry, interfaceType, dependencyName, implementationName);
}
private static void AddDefaultInstance(Type type, Registry registry, Type interfaceType, string dependencyName, string implementationName)
{
if (ConfigurationFactory.GetDefault(dependencyName) == implementationName)
registry.For(interfaceType).Use(type);
}
private static void AddInstanceUnlessOverridden(Type type, Registry registry, Type interfaceType, string dependencyName, string implementationName)
{
if (!ConfigurationFactory.GetOverrides(dependencyName).Keys.Contains(implementationName))
registry.For(interfaceType).Add(type).Named(implementationName);
}
private static void AddInstanceOverrides(Type type, Registry registry, Type interfaceType, string dependencyName, string implementationName)
{
if (ConfigurationFactory.GetOverrides(dependencyName).Values.Contains(implementationName))
foreach (var dependencyOverride in ConfigurationFactory.GetOverrides(dependencyName).Where(o => o.Value == implementationName))
registry.For(interfaceType).Add(type).Named(dependencyOverride.Key);
}
private static string GetImplementationName(Type type)
{
return type.Assembly.GetName().Name.Split('.').Last();
}
private static string GetDependencyName(Type type)
{
return type.Assembly.GetName().Name.Split('.').Reverse().Skip(1).First();
}
// etc.
}
</pre>
<br />
Still favoring convention over configuration, I've continued with the assumption of my assembly names. Given that, it takes a minimal amount of reflection to get the name of the assembly for the implementation and use that convention to name the instances.<br />
<br />
It was then irresistible to take it a step further and define some more custom configuration for these overrides. After all, one of the biggest reasons I have this setup is for testing. I like to create custom mock implementations for dependencies and then my testing instance (which has its own config file) can simply specify to use the mock implementations instead of the default ones. This is especially useful for automated integration testing because I can keep multiple config files for the tests and just have the build scripts deploy and run multiple instances of the test code with different config files. Thus isolating individual dependency implementations for testing while using mocks for everything else. This greatly reduces the number of variables in automated testing for me.<br />
<br />
So now in that custom configuration section I can override defaults as well as override named instances. Thus, even if my code calls for this:<br />
<br />
<pre class="brush: csharp">var eventDestination = IoCFactory.GetInstance<EventRepository>("GoogleCalendar");</pre>
<br />
I might decide to override that for a specific application, essentially telling it that "even if I ask you for this specific instance, give me this other one (such as the Mock) instead." Thus far this has prevented me from too tightly coupling the code asking for the implementations with the implementations themselves. The application isn't tightly bound to the actual implementation, it can override it. So as long as I keep my names fairly general, I'm happy with the level of coupling.<br />
<br />
Not shown here is the implementation of ConfigurationFactory, which is local to my IoC implementation project. But basically all it does is check the config file (using a standard .NET custom config section implementation) for any specified defaults or overrides. So, for example, by default the non-named instance for the repositories might be the SQLExpress implementation. In the config file I might then say to use the XML one as the default instead, so non-named instances become the XML one for that application. I may then also take it a step further and configure it to use the XML one even when the SQLExpress one is explicitly requested. (Which doesn't happen in the codebase at this time, but it does for other implementations such as the aforementioned Event stuff.)<br />
<br />
All in all, I'm pretty happy with this implementation. And I'll be a lot happier once I go back through the code and re-implement these custom dependencies as repositories which they should have been all along. This will reduce the number of service DTOs in the system to almost none, making use of the existing models instead. And it will get rid of several mock implementations since I can just re-use the one I already have for the DAL.</div>
</div>
testhttp://www.blogger.com/profile/09609860522747123959noreply@blogger.com0tag:blogger.com,1999:blog-6959582839690958035.post-47884746295656616452013-04-30T16:57:00.000-04:002013-05-21T11:37:12.924-04:00I Love My Surface RT, But...Each holiday season my employer gets a "tech gift" for everybody in the company. And last year was quite possibly the biggest one yet, a Surface RT. Before I go any further, I want to tell you that I <i>love</i> my Surface RT. I loves it very much. I love the feel of it. I love its usefulness as a Netflix appliance (huzzah for the built-in kick stand!). I love writing code for it. I love that I work for an employer who buys us things like that. All in all, I am very happy with my Surface RT.<br />
<div>
<br /></div>
<div>
But...</div>
<div>
<br /></div>
<div>
Well, I've come to realize why I'm so happy with it. It's not because the Surface is a compelling product or provides a rich experience or anything like that. It's not because the ratio of price to value is so good. It's not because it's a <i>good</i> product. No. It's because I'm a tech geek. And, as a tech geek, I like tech toys. It didn't have to specifically be a Surface, it could have been anything. Any shiny new toy would have been great. Even look at how I worded it in the above paragraph... "I love <i>my</i> Surface RT." I don't love the product, I just love that I have one.</div>
<div>
<br /></div>
<div>
Additionally, I've come to realize that my colleagues and I, who all share this love for our Surface RTs, are in a distinct minority. Most people do not love this product. And, honestly, I don't blame them.</div>
<div>
<br /></div>
<div>
The most direct experience I've had with this is watching my family. I have a wife and three daughters. (Only two of whom are old enough to even use such a device. The infant would just drool on it.) For a while, I didn't let anybody use my Surface. We have an iPad, we have a Kindle Fire (flashed with a real version of Android of course, since that Amazon-only stuff was crap), we have a handful of iPhones between us, we have computers and devices and toys aplenty. So I kept the Surface for myself.</div>
<div>
<br /></div>
<div>
My daughters didn't like that, of course. "Daddy, can we play with the new big phone?" (They started calling the iPad a "big phone" when I first got it. They were younger and, well, it was just like Daddy's phone but bigger. The name has kind of stuck.) "Sorry honey, that one's mine. I need to do important stuff on it. You can use the other ones, though." And they were happy enough to do so, but that lingering desire for the new toy was always there.</div>
<div>
<br /></div>
<div>
One day, somewhat recently, I opened up relations with China. I allowed the family unfettered use of the Surface RT. I presented it to them, power cord in hand, and instructed them to go forth and enjoy the device.</div>
<div>
<br /></div>
<div>
That lasted only a few minutes. Literally.</div>
<div>
<br /></div>
<div>
First, I had to create a user account other than my own. After all, one of the cool features of Windows 8 devices is the multi-user setup. And since my Windows 8 account is used across a handful of other computers and devices, I didn't want the kids polluting my stuff. So I set about creating an account. This was a <i>painful</i> process. It was clunky, unintuitive, and just overall dismal. But I put up with it. (I don't have any specifics on it to share at this time, it was a short while ago but long enough that the details are forgotten. Just know that, while the OS walks you through the initial setup rather well, setting up additional users is jarring and unpleasant. At least it was for me.)</div>
<div>
<br /></div>
<div>
The process of setting up a user account for my older daughter actually lasted longer than her interest in the device. Again, literally.</div>
<div>
<br /></div>
<div>
My older daughter took hold of the Surface and began to play. First thing's first, she wanted to play Minecraft. (She loves playing it on the iOS devices and on the family computers.) Sorry, not available. The app store doesn't have one, and the full version doesn't run on RT. So she looked for other games. There... aren't many. In the commercials they highlight Angry Birds, which is available. But who the hell cares about Angry Birds anymore?</div>
<div>
<br /></div>
<div>
The only thing she could find to do with it was watch something on Netflix. (Honestly, that's about 95% of my use of it as well.) This is where the kick stand comes in handy. You can place it nearby (such as on a night stand) and watch your favorite movies and TV shows. At least until the battery runs out. Which will be soon.</div>
<div>
<br /></div>
<div>
This trend continued until everybody in the house completely lost interest in the device. It currently sits unused on a table, devoid of battery life because nobody cares enough to plug it in.</div>
<div>
<br /></div>
<div>
Again, I love this device. It's great, as a toy. As a family computing device, not so much. This is pretty evident in the fact that my family just doesn't give a crap about it. Remember how great the built-in kick stand was? Each time my older daughter gets something to eat and sits down at the table to watch Netflix, does she grab the device with the built-in kick stand? No. She grabs the iPad, leans it against something, and places a napkin between it and the table to create some static friction to keep it standing up.</div>
<div>
<br /></div>
<div>
I want so much for this to be a more compelling device. I want to write software for it. I want it to open up .NET development throughout the tablet and mobile spaces even more than Mono does. (Just listening to that last sentence cements the fact that I am a tech geek, not an average consumer.) I want it to be successful. But it's not. Microsoft apologists in general will happily tell you that "the next one will be better" but I've learned not to hold my breath on that. (Pick a Microsoft product, and I'll show you an apologist who has said this about the shortcomings for any given version of it.)</div>
<div>
<br /></div>
<div>
Today a colleague showed us an amusing web site called <a href="http://aaplinvestors.net/stats/ipad/ipaddeathwatch/">iPad Death Watch</a>. Apparently the Microsoft apologists are <i>thriving</i> here. To give you an idea, this is my favorite quote about Apple's iPad on that page:</div>
<blockquote class="tr_bq">
"What an utter disappointment and abysmal failure of an Apple product. How can Steve Jobs stand up on that stage and hype this product up and not see everything this thing is not and everything this thing is lacking?"</blockquote>
It's so delicious to read it must be fattening. Honestly, I can't tell if that page is serious or satire. Imagining listening to someone say all the same things as Stephen Colbert, but it's not Stephen Colbert. Are they a comedian or are they insane? It'd be difficult to discern.<br />
<br />
Amid all of the comments on that page, however, is an infographic which, again, leaves me wondering if it's serious or satire. For posterity, here is the infographic in its entirety:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgF4myu7YFdkyRtmT3PT9hDK1f4dScP0jucLlODMMvCJ6GDYJ85WhIif7TtGrtK-tfACWXctM0kAw429eIi2KVr1jmS4jqI5yEHuiyahZROwcBBupqMaFU1fwMNp992HWkDz7lLap_zT8nF/s1600/why-surface-infographic.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgF4myu7YFdkyRtmT3PT9hDK1f4dScP0jucLlODMMvCJ6GDYJ85WhIif7TtGrtK-tfACWXctM0kAw429eIi2KVr1jmS4jqI5yEHuiyahZROwcBBupqMaFU1fwMNp992HWkDz7lLap_zT8nF/s1600/why-surface-infographic.jpg" /></a></div>
<br />
I'll continue to try to use the term "Microsoft apologist" instead of "Microsoft shill" but it's going to be difficult.<br />
<br />
So let's dissect this infographic a piece at a time...<br />
<br />
<ul>
<li>Multiple Users</li>
<ul>
<li>Easier and safer to share single device</li>
<ul>
<li>"Safer"? Maybe. "Easier"? Definitely not. The process was painful. Maybe I wasn't doing it right? Kind of like iPhone 4 users weren't holding it right? Ya, if that excuse doesn't work for Apple then it doesn't work for Microsoft either. The principle of least astonishment left much to be desired in the interface here.</li>
</ul>
<li>Same Windows user account experience but in a fun tablet size kids will love</li>
<ul>
<li>I couldn't help but emit an audible chuckle when I read that. For one thing, it sounds like they're marketing a pill. But more to the point, my kids don't love it. At all. This also implies that people inherently "love" the "Windows user account experience" in the first place. I contend that nobody cares. People appreciate the benefits it can provide, but they don't care about the "Windows user account" part of it.</li>
</ul>
</ul>
<li>Metro core of RT</li>
<ul>
<li>Addresses market that will likely be much more popular than traditional PCs within the next few years.</li>
<ul>
<li>That's a creative way to say, "Our competitors have already enjoyed billions in profit from this market in the past few years, so we think there may be something to it."</li>
</ul>
<li>Isn't aimed to be a PC replacement (i.e. - Incompatible with many desktop applications, partial driver support)</li>
<ul>
<li>You're... not the best salesman... are you? "Incompatible with many desktop applications" is a <i>benefit</i>? No, it's a pain in the ass. One thing I <i>have</i> watched my family do is go to "desktop mode," get excited that it's a full computer, try to install something, and see an error message saying they can't use that. (And to rub salt in the wound, the same error suggests visiting the Windows App Store. Which has, like, 12 apps in the entire store. 4 of which are Angry Birds. It's absurd.) <i>This is not a feature. This is a failure.</i></li>
</ul>
</ul>
<li>Mouse</li>
<ul>
<li>When you want to get real work done, nothing beats a keyboard and a mouse.</li>
<ul>
<li>First of all, don't quote yourself in your marketing material. Quote somebody else. Quoting yourself in an attempt to get your own point across is... not awesome.</li>
<li>Second, what's with the focus on "getting real work done"? Just a moment ago we were being sold on the idea that this "isn't aimed to be a PC replacement." Now we're being told that it's better because it can replace the PC? This isn't a product, this is an identity crisis. It reminds me of every failed attempt Microsoft has ever made to put a Start Menu on a phone. (And there have been many.) Remember that "market that will likely be much more popular than traditional PCs"? (Also known as that market where Apple has, with a single division of their business, out-profited the entire Microsoft corporate empire.) Trying to shove traditional PCs into that market isn't the way to go.</li>
<li>Finally, that last bullet point where he shows a negative is a bit... out of place. "No Mouse and Keyboard Center-based customization software offered just yet." Um... ok. Thanks. I guess the next one will be better?</li>
</ul>
</ul>
<li>USB Port</li>
<ul>
<li>Connect: External hard drives, printers, keyboards, mice</li>
<ul>
<li>It sounds an awful lot like this is <i>really</i> trying to be a traditional PC. I don't think I've ever wanted to print something from my iPad.</li>
</ul>
<li>Transfer camera files</li>
<ul>
<li>No, just no. <i>This is not my PC</i>. For internet-connected devices, files transfer (or should transfer) fairly seamlessly. (See <a href="http://www.apple.com/icloud/features/photo-stream.html">Photo Stream</a>) For non-connected devices (such as traditional digital cameras), I connect them to my PC. The PC is my central hub. From there they get disseminated to my other devices. (See <a href="http://www.apple.com/icloud/features/photo-stream.html">Photo Stream</a>) I would never even think to plug my digital camera into my iPad. It's a ridiculous notion. Again, and this is all over this friggin' infographic... <i>Are you comparing this device with a PC or with an iPad</i>? Microsoft doesn't seem to understand that there's a difference.</li>
</ul>
<li>Charge phones</li>
<ul>
<li>HA! The battery life is horrendous enough as it is. And now you're going to encourage people to plug powered devices into it? I bet the Surface RT powers down before the phone is even charged. Go ahead and try to plug a USB-powered spinning disk drive (like my old WD Passport, which I love) into one of these. I give it 5 minutes tops.</li>
</ul>
</ul>
<li>Task Switching aka "Windows Flip"</li>
<ul>
<li>Easily flip between programs with Alt+Tab</li>
<ul>
<li>Average consumers don't use Alt+Tab. They don't know or care about it. I did just discover in testing this one that Alt+Tab does include "metro" apps in the task switching, so that's cool. Point to Microsoft for that small bit of convenience. (It is the little things that make the compelling interface, after all.)</li>
</ul>
<li>Windows 8 and RT also offer Metro-style "Switcher interface" (Win Key+Tab)</li>
<ul>
<li>Ya, but it's only for Metro apps. So they've created a second kind of task switching which behaves almost like the first one, but differently. And they both exist on the same device. That's kind of jarring, don't you think? Oh, and also note that Metro apps don't show up in the traditional task bar, where people expect to see their apps. I guess this "Switcher interface" is the second task bar for a new class of apps. On a technical level I can understand this and it doesn't bother me. As a developer, this makes sense. But consumers will think it's stupid.</li>
</ul>
<li>Apple could close the productivity gap between its iPad and the Surface... by adding one critical missing feature to iOS: Simply allow users to task switch by using Alt+Tab</li>
<ul>
<li>Did you quote yourself again? But I digress...</li>
<li>Have you ever even seen an iPad? There is no Alt, and there is no Tab. There is no keyboard. I can't stress this enough, <i>the iPad is not a PC</i>. This identity crisis for the Surface and what it actually <i>is</i> is starting to get old. Besides, the iPad has a task switcher. Swipe to the side with 3 fingers. That feature has been there for a while now.</li>
</ul>
</ul>
<li>Fully-Functional Microsoft Office</li>
<ul>
<li>Office Home & Student 2013 RT</li>
<ul>
<li>Ok, I actually really like this part. Well, I would if I used Office for anything. (I do for work, but don't use my Surface RT for work because ([clears throat]) it is not a PC. But for people who do want to use Office on a tablet, including it was a pretty cool thing to do.</li>
</ul>
<li>Unlike Office for iPad - will require monthly Office 365 subscription</li>
<ul>
<li>There's an Office for iPad? I guess I didn't notice what with the iOS productivity apps so readily available. Pages, Numbers, and Keynote. Sure, they're "limited-functionality mobile apps" but, you know, they're on a limited functionality mobile device. (Not a PC?) As someone who also has a Mac (sort of a PC?) they play nicely with my setup. Oh, and they don't require a subscription to whatever Office 365 is. So, yes, iPad doesn't run Office. It doesn't purport to. My car also doesn't run Office. Is the Surface better than my car? (Note: My car is also not a PC.)</li>
</ul>
</ul>
</ul>
<div>
I don't fault Paul for this. He's in every way a Microsoft guy, and Microsoft is sending very mixed messages with their attempts to break into the non-PC market. The only <i>clear</i> message they seem to be sending is that they truly believe (whether intentionally or through a lack of understanding of the world around them) that the way to move into the non-PC space is to bring PCs there.</div>
<div>
<br /></div>
<div>
So that was enough ranting, and I got a little too emotionally charged on some of those responses. Maybe I'm the one who "doesn't get it"? I don't know. But my family doesn't get it either. Nor does just about anybody else I've met. And by "get it" I mean "buy a Surface or a Windows Phone 8." It's just not something people do.</div>
<div>
<br /></div>
<div>
Again, I love my Surface RT. I just don't see why anybody else would.<br />
<br /></div>
<hr />
<br />
NB: My older daughter's birthday is coming up and we've bought her a simple Dell laptop as her very first computer. It will be running Windows 8. I can almost <i>guarantee</i> that the moment she turns it on and sees the Metro start menu, she's going to feel a sense of disappointment and think it's as bad as "the new big phone." I'll try to salvage that. Putting Minecraft on it will be my primary weapon.testhttp://www.blogger.com/profile/09609860522747123959noreply@blogger.com0