Development

As I transition now into a new job I’ve been reflecting about the people I’ve met and the things I’ve learned. I’ve met a lot of smart people, and also met a lot of terrible people.

I promised myself to learn not just software engineering principles and programming, but the process by which we create these great things on what has come to be known as the Internet of Things. To reflect on the things I’ve learned I will do a blog series on my time there called “A Culture of Incompetence.” This is Part 1.


Hiring and Mentoring New Developers

This issue is particularly interesting to me – the idea of building a team is exciting! You know that scene in the movies where a guy gets a difficult mission and he says, “I’ll do it on one condition: I get to use my own team. These are people I trust.” Building a team isn’t about slapping people together with the right resumes. People will likely need to grow to fill the position you’re hiring them for. This means a lot of checking in, mentoring, and training them to do things the way a well-oiled machine does.

“I’m looking for people who are willing to work long hours – basically for free.”– A Previous Manager

There I was thinking about new team members when one of my managers says to me, “I’m looking for people who are willing to work long hours basically for free.” … yeah, he just said that to my face. It’s true, anyone building a team has constraints, a budget, and I get that, but telling members of your team that you’re looking for indentured servants is not a good look. The funny thing was, he wasn’t kidding. That particular company hired many foreign nationals and sponsored their H1B visas. By being the sponsor company, there’s a certain power dynamic at play when these employees ask for time off, a salary or performance review, or even when asking not to work overtime.

I do believe there’s an untapped pool of very talented individuals who need sponsorship. Turning over every rock to build a team is commendable, but it’s all in how you go about it. In my opinion this approach was unethical. It was the deliberate choice of a lazy management team that wanted to lower costs by hiring cheaper labor instead of developing an efficient process.


Ok, we’ve assembled a team of wage slaves, who have little choice but to come to work every day. Now what do we do? Well, naturally we let them do whatever they want and do nothing about it. One issue in particular that I came into contact with: some teams were not even committing their code to our version control system.

We have whole teams of people, working on client projects that aren’t in version control. Before we get into the cost of a “mishap” related to losing code, let’s discuss what could have caused this situation. Have we made it clear that committing working code regularly is an operational priority? Yes. Do we have hundreds of projects already under version control? Yes. Do we have people available to help if someone doesn’t know what they’re doing? Well, kind of.

I have my own team, we discuss software engineering as a practice. I strive to identify weaknesses in my team and to eradicate them through mentoring and training. This type of mentoring is different for every team member – some need hands-on, some need to see code samples, some you need to light a fire under their ass. Why do I do all this… because I decided I was tired of working with a bunch of apathetic new hires, who really don’t care about anything but lunch and going home. It’s also rewarding to see these people turn into up-and-comers.

When I found out that other teams and their members didn’t bother committing code and were positively cavalier about it, I approached my manager. “Well, it’s ok, that’s just how that person works.” Really? REALLY?! Is that how you build a strong team? This is exactly the type of attitude that has pervaded my places of work in the past. It’s disgusting.

Here we have a management team that is assembling resources as cheaply as it can, and then not taking the time or energy to train them up. I believe this culture of incompetence comes from the top and has trickled its way down. It’s exhausting to deal with, it’s exhausting to work against.

Anyway, those are some observations of my current employer’s hiring and training practices. These are things I need to think about and learn from. That’s it for Part 1… until next time.

It happens all the time, someone deleted an item by mistake. Whether it’s your content author, your customer, or yourself, you’ll need to undelete or recover a deleted item. Here’s how it’s done. If you’re a Sitecore 6 or 7 user, scroll down to that section.

Sitecore 8

Sitecore 8’s Launchpad provides a new way to access the Recycle Bin. From the launchpad just click the Recycle Bin app to access it.

sc8-recyclebin-launchpad

If instead you’re already in the Desktop mode or are used to that, hit the Sitecore menu and click the Recycle Bin app from the right hand side.

sc8-recyclebin

Once you’ve launched the Sitecore Recycle Bin, navigate to your item, select it, and choose “Restore” from the top.

sc8-recyclebin-view

Still on Sitecore 6 or 7?

When logging in select the Desktop view.

sc6-desktopview

From the Sitecore menu select the recycle bin from the right side.

sc6-recyclebin-menu

Navigate to the item you wish to recover, select it, and hit “Recover” at the top of the app. Your item is now recovered.

sc6-recyclebin

Sitecore provides all the tools necessary to easily personalize based on GeoLocation using their partner MaxMind’s webservices. Not only can content authors easily set up personalization based on available GeoLocation data using the rules engine, the development team will be able to leverage the same data in any custom business logic. That being said, content authors, testers and developers need to be able to verify their work for different IP addresses and locations. This approach does not require special .Net code, custom pipeline processors or anything else that could complicate your solution.

Configuration Change

Change the “Analytics.ForwardedRequestHttpHeader” value to “X-Forwarded-For” and you’re all set. This will tell Sitecore to look at that header for IP address information instead of the IP that made the request.

1
2
3
4
5
6
7
8
<!--  ANALYTICS FORWARDED REQUEST HTTP HEADER
      Specifies the name of an HTTP header variable containing the IP address of the webclient.
      For use only behind load-balancers that mask web client IP addresses from webservers.
      IMPORTANT: If used improperly, this setting allows IP address spoofing.
      Typical values are "X-Forwarded-For" and "X-Real-IP".
      Default value: "" (disabled)
-->
<setting name="Analytics.ForwardedRequestHttpHeader" value="X-Forwarded-For" />

Setting your header

To make this easy I use the “Change HTTP Request Header” plugin for Chrome. Setting this up is pretty easy after you have it installed. First add a new header for “X-Forwarded-For”, then add any presets that line up with your test cases – see the screen shots below. Once everything is setup you hit the handy dropdown in the plugin to select a preset or to input one on the fly.

Download the Change HTTP Request Header at the Chrome Store

So, that’s it! Have fun testing your GeoLocation aware apps in Sitecore.

It’s funny how almost all the controls we end up building are a list of something. In Sitecore that means lists of Items! If you are doing WebForms you have become familiar with the <asp:Repeater /> control, and might have some solutions for binding FieldRenderer or <sc:Text /> controls. I’ve found that a custom Repeater control that binds child FieldControls (sc:Text, sc:Image, sc:Date, etc.) automatically has reduced my code and time spent slogging through all the controls necessary to build out a site.

Take for example the following usage assuming an IEnumerable<Item> or IQueryable<Item> was bound to the Repeater

<asp:Repeater runat="server" id="myRepeater">
    <ItemTemplate>
        <h3><sc:Text runat="server" field="Title" Item="<%# (Sitecore.Data.Items.Item)Container.DataItem %>" /></h3>
        <div class="item-content">
            <sc:Text runat="server" field="Description" Item="<%# (Sitecore.Data.Items.Item)Container.DataItem %>" />
        </div>
    </ItemTemplate>
</asp:Repeater>

That is a simple example of how I often see FieldControls binded. An even more extreme case would be to not use FieldControls at all, to set the content for the HtmlGenericControls in the ItemDataBound event.

When it’s time to output my data I don’t want anything getting in my way, so I chose the following approach: Set up a simple ItemRepeater class that extends Repeater and autobinds child FieldControls without an Item set for you. Check out the example usage:

<custom:ItemRepeater runat="server" id="myRepeater">
    <ItemTemplate>
        <h3><sc:Text runat="server" field="Title" /></h3>
        <div class="item-content">
            <sc:Text runat="server" field="Description" />
        </div>
    </ItemTemplate>
</custom:ItemRepeater>

Just set the DataSource and you’re done, that’s how I like it. Check out the class below that takes care of the lifting.

I saw a post yesterday by Paul Irish, showing the classy 3D transformations Amazon is doing on some pages. I’ve been playing with some retro game collecting application ideas and was thinking that the effect would be cool for a collection page, so I set up a prototype.

The HTML

<div class="boxart-container">
    <div class="boxart-canvas">
        <img class="boxart-front" src="http://patrickmjones.com/projects/3dbox/cover_mm2_front.jpg">
        <img class="boxart-back"  src="http://patrickmjones.com/projects/3dbox/cover_mm2_back.jpg">
        <div class="boxart-side">
            <img src="http://patrickmjones.com/projects/3dbox/cover_mm2_side.jpg">
        </div>	
    </div>
</div>

The JavaScript

(function($){
    $(document).ready(function(){
        $('.boxart-canvas').hover(function(){
            $(this).addClass('boxart-rotated');
        }, function(){
            $(this).removeClass('boxart-rotated');
        });
    });
})(window.jQuery);

The JavaScript basically just adds a class that triggers the CSS to rotate the item. Event handlers could instead be on click or any other action… for example in a game.

The CSS

.boxart-canvas {
	display: table-cell;
	vertical-align: middle;
	height: 100%;
	width: 100%;
	position: absolute;
	transform-style:preserve-3d;
	-moz-transform-style:preserve-3d;
	-webkit-transform-style:preserve-3d;
	transition:transform .5s ease 0s;
	-moz-transition:-moz-transform .5s ease 0s;
	-webkit-transition:-webkit-transform .5s ease 0s;
	-webkit-border-radius:0 7px 7px 0;
	-moz-border-radius:0 7px 7px 0;
	border-radius:0 7px 7px 0;
	background:#222 none repeat scroll 0 0;
}
.boxart-canvas .boxart-front {
	backface-visibility:hidden;
	-moz-backface-visibility:hidden;
	-webkit-backface-visibility:hidden;
	-webkit-border-radius:0 4px 4px 0;
	-moz-border-radius:0 4px 4px 0;
	border-radius:0 4px 4px 0;
	transition:transform .5s ease 0s;
	-moz-transition:-moz-transform .5s ease 0s;
	-webkit-transition:-webkit-transform .5s ease 0s;
	transform-origin:0;
	-moz-transform-origin:0;
	-webkit-transform-origin:0;
}
.boxart-rotated {
	transform:rotateY(180deg)!important;
	-moz-transform:rotateY(180deg)!important;
	-webkit-transform:rotateY(180deg)!important;
}
.boxart-front { 
	max-width: 280px; 
	position: absolute;
	top: 0;
	left: 0;
}
.boxart-back { 
	max-width: 280px; 
	position: absolute;
	top: 0;
	left: 0;
}
.boxart-back {
	backface-visibility:hidden;
	-moz-backface-visibility:hidden;
	-webkit-backface-visibility:hidden;
	-webkit-border-radius:4px 0 0 4px;
	-moz-border-radius:4px 0 0 4px;
	border-radius:4px 0 0 4px;
	transform:rotateY(180deg) translateZ(54px);
	-moz-transform:rotateY(180deg) translateZ(54px);
	-webkit-transform:rotateY(180deg) translateZ(54px);
}
.boxart-side img { 
	max-width: 54px; 
	max-height: 382px;
	position: absolute;
	top: 0;
	left: -54px;
	transform:rotateY(-90deg);
	-moz-transform:rotateY(-90deg);
	-webkit-transform:rotateY(-90deg);
	transform-origin:right center 0;
	-moz-transform-origin:right center 0;
	-webkit-transform-origin:right center 0;
}
.boxart-container {
	position: relative;
	display: table;
	width: 100%;
	perspective:1200px;
	-moz-perspective:1200px;
	-webkit-perspective:1200px;
	width: 280px;
	height: 383px;
}

Problems

Yeah, I haven’t tried getting this going in IE just yet. In IE10 the front cover was flipping around, and below that… well, it wasn’t nice.