Why Startups Don’t Use .NET
Recently a blogger named Aaron wrote a thought-provoking post called .NET Culture Shock: Why .NET Adoption Lags Among Startups. Aaron elucidates the problem insightfully, determining that .NET is well established among enterprise developers whose chief concern is supporting systems, whereas startup developers worry primarily about supporting products. Aaron concludes that there is nothing inherent in .NET that precludes its use among startups; it is simply limited by culture differences between enterprise developers and startup developers.
Aaron claims that objections against .NET in the startup world such as platform lock-in and licensing costs do not “pass the objective reality test”, but he doesn’t provide an objective reality test to back up these claims. Here’s an objective reality test. My cash-strapped startup needs an IDE. Will I choose Microsoft Visual Studio Ultimate for $11,899 or Aptana Studio for free?
However, there is a simpler and more compelling reason why startups do not use .NET (.NET boosters will be quick to point out that developers can get Microsoft Visual Studio Express for free). Startups preach the use of web standards, semantic HTML, and css-driven layouts. Here’s a snippet from a job description posted by Ze Frank (and re-tweeted by startup leaders such as Jonah Peretti, founder of Huffington Post and Buzzfeed), “You should have sent at least one email to someone you have never met telling them that they should stop using tables.” Keep that “stop using tables” thought in mind. It’s going to come back up in a moment.
I recently had the opportunity to work on my first .NET project. It’s a large, established enterprise web application and I’m implementing a number of UI enhancements. The project uses .NET UI widgets made by DevExpress, a very popular commercial UI widget library for .NET.
One of my first assignments was to create a form that included a simple dropdown list with three items. As a proponent of web standards and semantic HTML, I would normally code this dropdown list as such:
<select name=”Selection”>
<option value=”Single”>Single</option>
<option value=”Multiple”>Multiple</option>
<option value=”CheckColumn”>CheckColumn</option>
</select>
However, the technical lead on the project directed me to use the DevExpress dropdown control so that he could easily tie it into the back-end code. So, here is the HTML and javascript generated by DevExpress to create the same dropdown list that I have coded above (if you don’t believe me, you can see this code for yourself; just view source on this page at DevExpress):
<td>
<table cellspacing=”1” cellpadding=”0” border=”0” style=”border-collapse: separate;” id=”ctl00_phContent_lbSelectionMode” class=”dxeButtonEdit_Aqua “>
<tbody><tr>
<td style=”display: none;”><input type=”hidden” name=”ctl00_phContent_lbSelectionMode_VI” id=”ctl00_phContent_lbSelectionMode_VI” value=”2”></td><td style=”width: 100%;” onmousedown=”return aspxDDDropDown(‘ctl00_phContent_lbSelectionMode’, event)” class=”dxic”><input type=”text” style=”border-width: 0px; width: 100%; padding: 0px; margin: 1px 1px 2px; cursor: default;” readonly=”readonly” onchange=”aspxETextChanged(‘ctl00_phContent_lbSelectionMode’)” onfocus=”aspxEGotFocus(‘ctl00_phContent_lbSelectionMode’)” onblur=”aspxELostFocus(‘ctl00_phContent_lbSelectionMode’)” id=”ctl00_phContent_lbSelectionMode_I” value=”CheckColumn” name=”ctl00$phContent$lbSelectionMode” class=”dxeEditArea_Aqua ” autocomplete=”off”></td><td style=”-moz-user-select: none;” onmousedown=”return aspxDDDropDown(‘ctl00_phContent_lbSelectionMode’, event)” class=”dxeButtonEditButton_Aqua” id=”ctl00_phContent_lbSelectionMode_B-1”><table cellspacing=”0” cellpadding=”0” border=”0” style=”border-collapse: separate;” class=”dxbebt”>
<tbody><tr>
<td class=”dx”><img style=”border-width: 0px;” alt=”v” src=”/ASPxEditorsDemos/DXR.axd?r=1_3” class=”dxEditors_edtDropDown_Aqua” id=”ctl00_phContent_lbSelectionMode_B-1Img”></td>
</tr>
</tbody></table></td>
</tr>
</tbody></table><input type=”hidden” value=”0:0:12000:395:120:0:-10000:-10000” name=”ctl00_phContent_lbSelectionMode_DDDWS” id=”ctl00_phContent_lbSelectionMode_DDDWS”>
<div style=”position: absolute; left: 395px; top: 120px; z-index: 12000; height: 69px; width: 170px; overflow: visible; visibility: hidden; display: none;” id=”ctl00_phContent_lbSelectionMode_DDD_PW-1”>
<table cellspacing=”0” cellpadding=”0” border=”0” style=”border-collapse: separate; position: relative; left: 0px; top: 0px;” id=”ctl00_phContent_lbSelectionMode_DDD_PWST-1”>
<tbody><tr>
<td style=”width: 168px; cursor: default; height: 0px;” onmousedown=”aspxPWMDown(event,’ctl00_phContent_lbSelectionMode_DDD’,-1,false)”><table cellspacing=”0” cellpadding=”0” border=”0” style=”width: 168px; border-collapse: separate; height: 67px;” id=”ctl00_phContent_lbSelectionMode_DDD_CLW-1”>
<tbody><tr>
<td style=”height: 100%;” id=”ctl00_phContent_lbSelectionMode_DDD_PWC-1”><table cellspacing=”0” cellpadding=”0” border=”0” style=”border-collapse: separate; height: 0px; width: 170px;” id=”ctl00_phContent_lbSelectionMode_DDD_L” class=”dxeListBox_Aqua”>
<tbody><tr>
<td valign=”top”><div style=”width: 168px; overflow: hidden; height: 66px; padding-right: 0px;” class=”dxlbd” id=”ctl00_phContent_lbSelectionMode_DDD_L_D”>
<input type=”hidden” name=”ctl00$phContent$lbSelectionMode$DDD$L” id=”ctl00_phContent_lbSelectionMode_DDD_L_VI” value=”2”><table cellspacing=”0” cellpadding=”0” border=”0” style=”width: 100%; border-collapse: separate;” id=”ctl00_phContent_lbSelectionMode_DDD_L_LBT”>
<tbody><tr class=”dxeListBoxItemRow_Aqua”>
<td class=”dxeListBoxItem_Aqua” id=”ctl00_phContent_lbSelectionMode_DDD_L_LBI0T0”>Single</td>
</tr><tr class=”dxeListBoxItemRow_Aqua”>
<td class=”dxeListBoxItem_Aqua” id=”ctl00_phContent_lbSelectionMode_DDD_L_LBI1T0”>Multiple</td>
</tr><tr class=”dxeListBoxItemRow_Aqua”>
<td class=”dxeListBoxItem_Aqua dxeListBoxItemSelected_Aqua” id=”ctl00_phContent_lbSelectionMode_DDD_L_LBI2T0”>CheckColumn</td>
</tr>
</tbody></table>
</div></td>
</tr>
</tbody></table><script type=”text/javascript” id=”dxss_1162343191”>
<!—
var dxo = new ASPxClientListBox(‘ctl00_phContent_lbSelectionMode_DDD_L’);
window[‘ctl00_phContent_lbSelectionMode_DDD_L’] = dxo;
dxo.uniqueID = ‘ctl00$phContent$lbSelectionMode$DDD$L’;
aspxAddDisabledItems(‘ctl00_phContent_lbSelectionMode_DDD_L’,[[[‘dxeDisabled_Aqua’],[”],[”]]]);
dxo.SelectedIndexChanged.AddHandler(function (s, e) { aspxCBLBSelectedIndexChanged(‘ctl00_phContent_lbSelectionMode’, e); });
dxo.ItemClick.AddHandler(function (s, e) { aspxCBLBItemMouseUp(‘ctl00_phContent_lbSelectionMode’, e); });
dxo.RequireStyleDecoration();
dxo.styleDecoration.AddStyle(‘F’,’dxeFocused_Aqua’,”);
dxo.savedSelectedIndex = 2;
dxo.itemsValue=[‘0’,’1’,’2’];
dxo.isComboBoxList = true;
dxo.hoverClasses=[‘dxeListBoxItemHover_Aqua’];
dxo.selectedClasses=[‘dxeListBoxItemSelected_Aqua’];
dxo.disabledClasses=[‘dxeDisabled_Aqua’];
dxo.InlineInitialize();
//—>
</script>
</td>
</tr>
</tbody></table></td>
</tr>
</tbody></table>
</div><script type=”text/javascript” id=”dxss_682451067”>
<!—
var dxo = new ASPxClientPopupControl(‘ctl00_phContent_lbSelectionMode_DDD’);
window[‘ctl00_phContent_lbSelectionMode_DDD’] = dxo;
dxo.uniqueID = ‘ctl00$phContent$lbSelectionMode$DDD’;
dxo.Shown.AddHandler(function (s, e) { aspxDDBPCShown(‘ctl00_phContent_lbSelectionMode’, e); });
dxo.adjustInnerControlsSizeOnShow=false;
dxo.closeAction=’CloseButton’;
dxo.popupHorizontalAlign=’LeftSides’;
dxo.popupVerticalAlign=’Below’;
dxo.isPopupPositionCorrectionOn=false;
dxo.shadowVisible=false;
dxo.width=0;
dxo.height=0;
dxo.InlineInitialize();
//—>
</script>
<script type=”text/javascript” id=”dxss_949748170”>
<!—
document.getElementById(“ctl00_phContent_lbSelectionMode_I”).setAttribute(“autocomplete”, “off”);
aspxAddHoverItems(‘ctl00_phContent_lbSelectionMode’,[[[‘dxeButtonEditButtonHover_Aqua’],[”],[‘B-1’]„[[{‘spriteCssClass’:’dxEditors_edtDropDownHover_Aqua’}]],[‘Img’]]]);
aspxAddPressedItems(‘ctl00_phContent_lbSelectionMode’,[[[‘dxeButtonEditButtonPressed_Aqua’],[”],[‘B-1’]„[[{‘spriteCssClass’:’dxEditors_edtDropDownPressed_Aqua’}]],[‘Img’]]]);
var dxo = new ASPxClientComboBox(‘ctl00_phContent_lbSelectionMode’);
window[‘ctl00_phContent_lbSelectionMode’] = dxo;
dxo.autoPostBack = true;
dxo.uniqueID = ‘ctl00$phContent$lbSelectionMode’;
dxo.RequireStyleDecoration();
dxo.styleDecoration.AddStyle(‘F’,’dxeFocused_Aqua’,”);
dxo.InlineInitialize();
//—>
</script>
</td>
Now, if I walked into a startup and presented that 92-line table-based chunk as an example of how to code a HTML dropdown list, I guarantee you that I would not be getting a return call. The code above obviously violates web standards on many levels.
The difference between .NET developers and startup developers goes deeper than just “culture”. Every culture has values. Startup developers (at least web startups) value the web as a native platform with its own technologies (HTML, CSS, Javascript). A lot of .NET web projects, on the other hand, appear to me to be attempts to create 1980’s-era client-server applications and then smush them and squash them until they run inside a web browser. Since many corporations require the use of Internet Explorer, .NET projects are typically only tested on IE. Startups have a more diverse audience and aim for quality across all browsers.
It’s not so much about systems vs. products. It’s about valuing the web as a platform in its own right vs. valuing Microsoft as the platform and considering the web browser as just another delivery mechanism, an afterthought.
When .NET can generate the same kind of clean, semantic HTML, CSS, and Javascript that I can code by hand, then web startups might consider adopting it. Until then, .NET will remain inside the gray cubicle walls of the enterprise.