The Code Spaghetti generation is back


Over the last few months, I try to read and prepare some book reviews regarding ASP.NET 2.0. So with all my personal subjectivity, I found myself embroiled in some sort of conspiracy by the C.S.G. aka the Code Spaghetti Generation.

I was quite sure this was an extinct cult from the Asp 3.0 time circa 1999. They are now invading our brains in every book or article I read and this look like a revival cult of some kind or a pervasive plot to conquer the developers world.

See this piece of code (Warning: if you are a DBA or a Business Object guru this might hurt and make you scream):

<%@ Page Language="VB" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Chapter 5 Product List</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Image ID="Image1" runat="server" ImageUrl="~/Images/banner.jpg" /><br />
        <br />
        <table>
          <tr>
            <td width="300px" valign="top">
              <asp:GridView ID="GridView1" runat="server"
                  AllowSorting="True" AllowPaging="True"
                  DataKeyNames="ProductID" DataSourceID="SqlDataSource1"
                  AutoGenerateColumns="False" SelectedIndex="0"
                  CellPadding="4" GridLines="None" ForeColor="Black">
                  <Columns>
                    <asp:BoundField DataField="ProductID" HeaderText="ID"
                        ReadOnly="True">
                      <HeaderStyle HorizontalAlign="Left" />
                        <ItemStyle Width="75px" />
                    </asp:BoundField>
                    <asp:BoundField DataField="Name" HeaderText="Name">
                      <HeaderStyle HorizontalAlign="Left" />
                        <ItemStyle Width="200px" />
                    </asp:BoundField>
                    <asp:BoundField DataField="CategoryID" HeaderText="Category" />
                    <asp:CommandField ButtonType="Button" ShowSelectButton="True" />
                  </Columns>
                  <HeaderStyle BackColor="Silver" Font-Bold="True"
                      ForeColor="White" />
                  <RowStyle BackColor="White" ForeColor="Black" />
                  <AlternatingRowStyle BackColor="WhiteSmoke" ForeColor="Black" />
                  <FooterStyle BackColor="Silver" Font-Bold="True" ForeColor="White" />
                  <PagerStyle BackColor="Silver" ForeColor="Blue"
                      HorizontalAlign="Center" />
              </asp:GridView>
              <asp:SqlDataSource ID="SqlDataSource1" runat="server"
                  ConnectionString="<%$ ConnectionStrings:HalloweenConnection %>"
                  SelectCommand="SELECT [ProductID], [Name], [CategoryID]
                      FROM [Products] ORDER BY [ProductID]">
              </asp:SqlDataSource>
            </td>
            <td width="400px" valign="top">
                <asp:DetailsView ID="DetailsView1" runat="server"
                    DataSourceID="SqlDataSource2"  DataKeyNames="ProductID"
                    Height="50px" Width="400px" AutoGenerateRows="False"
                    BackColor="White" BorderColor="White" BorderStyle="Ridge"
                    BorderWidth="2px" CellPadding="3" CellSpacing="1"
                    GridLines="None">
                    <RowStyle BackColor="#DEDFDE" ForeColor="Black" />
                    <Fields>
                        <asp:BoundField DataField="ProductID" HeaderText="Product ID:"
                            ReadOnly="True" SortExpression="ProductID">
                            <HeaderStyle HorizontalAlign="Left" Width="150px" />
                            <ItemStyle Width="250px" />
                        </asp:BoundField>
                        <asp:BoundField DataField="Name" HeaderText="Name:">
                            <HeaderStyle HorizontalAlign="Left" Width="150px" />
                            <ItemStyle Width="250px" />
                        </asp:BoundField>
                        <asp:BoundField DataField="ShortDescription"
                           HeaderText="Short Description:">
                            <HeaderStyle HorizontalAlign="Left" Width="150px" />
                            <ItemStyle Width="250px" />
                        </asp:BoundField>
                        <asp:BoundField DataField="LongDescription"
                            HeaderText="Long Description:">
                            <HeaderStyle HorizontalAlign="Left" Width="150px" />
                            <ItemStyle Width="250px" />
                        </asp:BoundField>
                        <asp:BoundField DataField="CategoryID"
                            HeaderText="Category ID:">
                            <HeaderStyle HorizontalAlign="Left" Width="150px" />
                            <ItemStyle Width="250px" />
                        </asp:BoundField>
                        <asp:BoundField DataField="ImageFile"
                            HeaderText="Image File:" SortExpression="ImageFile">
                            <HeaderStyle HorizontalAlign="Left" Width="150px" />
                            <ItemStyle Width="250px" />
                        </asp:BoundField>
                        <asp:BoundField DataField="UnitPrice"
                            HeaderText="Unit Price:"  DataFormatString="{0:c}">
                            <HeaderStyle HorizontalAlign="Left" Width="150px" />
                            <ItemStyle Width="250px" />
                        </asp:BoundField>
                        <asp:BoundField DataField="OnHand" HeaderText="On Hand:">
                            <HeaderStyle HorizontalAlign="Left" Width="150px" />
                            <ItemStyle Width="250px" />
                        </asp:BoundField>
                        <asp:CommandField ButtonType="Button"
                            ShowDeleteButton="True"
                            ShowEditButton="True"
                            ShowInsertButton="True" />
                    </Fields>
                    <HeaderStyle BackColor="Silver" Font-Bold="True"
                        ForeColor="Black" />
                    <EditRowStyle BackColor="Blue" Font-Bold="True"
                        ForeColor="White" />
                </asp:DetailsView>
                <asp:SqlDataSource ID="SqlDataSource2" runat="server"
                    ConflictDetection="CompareAllValues"
                    ConnectionString="<%$ ConnectionStrings:HalloweenConnection %>"
                    SelectCommand="SELECT [ProductID], [Name], [ShortDescription],
                          [LongDescription][CategoryID][ImageFile]
                          [UnitPrice][OnHand]
                        FROM [Products]
                        WHERE ([ProductID] = @ProductID)"
                    DeleteCommand="DELETE FROM [Products]
                        WHERE [ProductID] = @original_ProductID
                          AND [Name] = @original_Name
                          AND [ShortDescription] = @original_ShortDescription
                          AND [LongDescription] = @original_LongDescription
                          AND [CategoryID] = @original_CategoryID
                          AND ( [ImageFile] = @original_ImageFile
                           OR ImageFile IS NULL AND @original_ImageFile IS NULL )
                          AND [UnitPrice] = @original_UnitPrice
                          AND [OnHand] = @original_OnHand"
                    InsertCommand="INSERT INTO [Products] ([ProductID], [Name],
                          [ShortDescription][LongDescription][CategoryID]
                          [ImageFile][UnitPrice][OnHand]
                        VALUES (@ProductID@Name@ShortDescription,
                          @LongDescription@CategoryID@ImageFile
                          @UnitPrice@OnHand)"
                    UpdateCommand="UPDATE [Products] SET [Name] = @Name,
                          [ShortDescription] = @ShortDescription
                          [LongDescription] = @LongDescription
                          [CategoryID] = @CategoryID
                          [ImageFile] = @ImageFile
                          [UnitPrice] = @UnitPrice
                          [OnHand] = @OnHand
                        WHERE [ProductID] = @original_ProductID
                          AND [Name] = @original_Name
                          AND [ShortDescription] = @original_ShortDescription
                          AND [LongDescription] = @original_LongDescription
                          AND [CategoryID] = @original_CategoryID
                          AND ( [ImageFile] = @original_ImageFile
                           OR ImageFile IS NULL AND @original_ImageFile IS NULL )
                          AND [UnitPrice] = @original_UnitPrice
                          AND [OnHand] = @original_OnHand">
                    <SelectParameters>
                        <asp:ControlParameter ControlID="GridView1" Name="ProductID"
                            PropertyName="SelectedValue" Type="String" />
                    </SelectParameters>
                    <DeleteParameters>
                        <asp:Parameter Name="original_ProductID" Type="String" />
                        <asp:Parameter Name="original_Name" Type="String" />
                        <asp:Parameter Name="original_ShortDescription" Type="String" />
                        <asp:Parameter Name="original_LongDescription" Type="String" />
                        <asp:Parameter Name="original_CategoryID" Type="String" />
                        <asp:Parameter Name="original_ImageFile" Type="String" />
                        <asp:Parameter Name="original_UnitPrice" Type="Decimal" />
                        <asp:Parameter Name="original_OnHand" Type="Int32" />
                    </DeleteParameters>
                    <UpdateParameters>
                        <asp:Parameter Name="Name" Type="String" />
                        <asp:Parameter Name="ShortDescription" Type="String" />
                        <asp:Parameter Name="LongDescription" Type="String" />
                        <asp:Parameter Name="CategoryID" Type="String" />
                        <asp:Parameter Name="ImageFile" Type="String" />
                        <asp:Parameter Name="UnitPrice" Type="Decimal" />
                        <asp:Parameter Name="OnHand" Type="Int32" />
                        <asp:Parameter Name="original_ProductID" Type="String" />
                        <asp:Parameter Name="original_Name" Type="String" />
                        <asp:Parameter Name="original_ShortDescription" Type="String" />
                        <asp:Parameter Name="original_LongDescription" Type="String" />
                        <asp:Parameter Name="original_CategoryID" Type="String" />
                        <asp:Parameter Name="original_ImageFile" Type="String" />
                        <asp:Parameter Name="original_UnitPrice" Type="Decimal" />
                        <asp:Parameter Name="original_OnHand" Type="Int32" />
                    </UpdateParameters>
                    <InsertParameters>
                        <asp:Parameter Name="ProductID" Type="String" />
                        <asp:Parameter Name="Name" Type="String" />
                        <asp:Parameter Name="ShortDescription" Type="String" />
                        <asp:Parameter Name="LongDescription" Type="String" />
                        <asp:Parameter Name="CategoryID" Type="String" />
                        <asp:Parameter Name="ImageFile" Type="String" />
                        <asp:Parameter Name="UnitPrice" Type="Decimal" />
                        <asp:Parameter Name="OnHand" Type="Int32" />
                    </InsertParameters>
                </asp:SqlDataSource><br />
                <asp:Label ID = "lblError" runat="server" ForeColor="Red"
                    EnableViewState="False"></asp:Label>
            </td>
          </tr>
        </table>
    </div>
    </form>
</body>
</html>
Generated using PrettyCode.Encoder

So if you are reading this line, and you are still alive, stop reading here.

Well for many years I was told this was a bad practice to mix presentation layer and data layer. So why the C.S.G. is back again? To please the beginners? Any typing mistake when you want to update your HTML code on this page will doom your worthy application.

So please can all the ASP.NET 2.0 writers add a small comment on this kind of thing and say something like 'Don't do it kids it's cool but it's really bad practice and it will send you to code hell'.

I propose a new logo to ban all the C.S.G. people from our web applications.

 

14 Comments

  • Thank God I'm not the only one who's thinking this right now. I noticed it a lot with ASP.NET books, too.



    I think that the authors of most of these books are not as smart as they think they are. Some of the books are amazing, others are textbook examples of what not to do.

  • I think of it this way: The framework doesn't tie you to a specific level of programming. You can perform the task using well-designed layers and conform to best practices and such. But also, the framework provides this level of 'spaghetti' programming because there are programmers out there who are more familiar with this kind of code.

  • SqlDataSource should die!

  • Amen! The Microsoft Quickstarts are full of examples like this. It's *really* shameful. Code-behind isn't a great solution but it's a hell of a lot better than this crap.

  • Thanks for speaking out on this issue.



    It is quite shameful that one keeps seeing this everywhere.



    Reading this books is simply boring, and I guess writing them

    must be even more boring, how do they stand it, or do they not

    know better.

  • Well Charles, I have to disagree with you. Over the last few years, many developers learned how to avoid the spagetti code, now it means that for newbies, forget everything we said before, it's good to produce junk code! At least I would like to see book writers a bit more responsible and not just swallow what Microsoft say like if it was the word of god.

    I have no problem to see this code but it should be followed by some warning note.

    I stuck to the code behind even if it's not perfect because I can't imagine my SQL procedures screwed by some mistakes in my HTML code! And as an 'old' coder I don't see any advantages to produce this monstruosity. And the example I show here is very basic, add to that all the CSS, the static HTML code and eventually some Javascript DHTML code and try to swallow that :-) Good luck if you have to change something!

  • &quot;SqlDataSource should die!&quot;



    SqlDataSource in itself seems legit to me; it is the implementation and usage that requires questioning. As I mentioned previously, I think it's perfectly acceptable to use the sample given as these are *quick*starts, not &quot;long drawn out lenghty exercies that require a computer science degree and masters in software engineering&quot;.



    One interesting use of SqlDataSource would be to pair it up with a Factory pattern so that each page doesn't declaratively create a SqlDataSource, but has access to some sort of Factory object which builds the requisite SqlDataSource based on some inputs and returns it to the page for databinding.



    Admittedly, it's a shortcut to building a true object oriented design, but a true object oriented design isn't always necessary or called for; just like take out is a shortcut to a homecooked meal, but a four course homecooked meal isn't always necessary.

  • Different features are useful for different scenarios and different classes of developers. One of the things that we've tried to-do with ASP.NET is layer the architecture so that developers can use different capabilities in a flexible way, and choose what is &quot;right&quot; for them.



    For example, some developers want more flexibility than .aspx pages give them, and so write to the low-level IHttpHandler APIs which provides ultimate flexibility (but requires a lot more discipline and effort to use). That doesn't mean one approach is &quot;bad&quot; or &quot;good&quot; -- the ultimate value/usefulness of it depends on the scenario and developer.



    In terms of datasources, there is a base datasource class that all ASP.NET datasource controls derive from (including ObjectDataSource, SiteMapDataSource, SqlDataSource and XmlDataSource). You can also build your own datasource control that derives directly from the base class for ultimate flexibility.



    For the most maintainable and clean code, we recommend using the ObjectDataSource and encapsulating your data access code within either a DAL (data access layer) class ideally wrapped by a business layer class (and that has no concept of UI). This provides a nice, very clean, OO abstraction -- and still saves a lot of time and effort over V1.1.



    For simpler reporting scenarios, or cases where developers don't understand OO concepts like classes, the SQLDataSource control can also be used. This has the downside which is that the data access code can't be re-used across pages, classes or projects. The data code also isn't factored cleanly. But for cases where you are looking to build something quick and dirty, or where a developer doesn't understand OO concepts, it can help get things done. Note that the UI code is the same regardless of whether a developer is using a SqlDataSource or ObjectDataSource -- so it is possible to move the data code out from a Sqldatasource implementation into a BLL/DAL implementation using ObjectDatasource without having to change existing UI code.



    In terms of samples -- the ASP.NET QuickStarts show lots of different scenarios, and they include samples of both the ObjectDataSource and SQLDataSource. All of the ASP.NET Starter Kits, which are more full fledged samples, use the ObjectDataSource control.



    Hope this helps,



    Scott

  • What *really* peeves me about this new model is that with the 1.1 bits it was 100% possible to write an entire web application with NO markup. This is no longer the case. In 2.0 if you want to 2-way databind, get ready to deal with markup. It simply isn't possible (if anyone finds a way, please kick me a mail)

  • In answer to Paul's comment:



    Anything stored in a .aspx file can also be represented in a code-behind file as procedural code. If you want an ObjectDatasource definition defined in your code-behind file, just add an event handler for the page/control's initialize or init event and manually create the control, set properties, and add it into the page tree.



    The ObjectDatasource needed to be implemented as a control vs. a standalone component, because the only way to add support for 2 way data-binding is to have a class that intimately understands the control model (which is why this is implemented as a control).



    Hope this helps,



    Scott



    P.S. It is worth mentioning that 2-way databinding doesn't exist in V1.1, so this is a new thing -- not something easily done before.

  • While the addition of the declartive type controls are I'm sure a welcome addition for the amatuer developer, it would be nice if the advanced features were availible to developers that don't use the declartive style (i.e. GridView).

  • Microsoft has always pushed new products by showing &quot;new features&quot; that consist almost exclusively of things that you should never actually do in real life. Richard Tallent (I think?) made a great name for this smoke-and-mirrors demo practice: &quot;Gee-WYSIWYG&quot;.



    The demos are great for demo purposes (&quot;ooo... ahhh... look, I didn't write a single line of code!&quot;) but I have always found it sad and slightly disturbing that MS sells VS.NET using features that should never be used by the people that buy the product (with the exception of protypes, quick proof-of-concepts, and other apps you will later completely scrap and write from scratch with code).



  • To echo Joseph Cooney, this isn't spaghetti code. Spaghetti code was ASP 3.0, where you HAD to mix actual code (VBScript, whatever) with markup. I believe what the complaint is here is essentially two-tier data access, no?



    Jason Tucker, what features of the GridView are not available to developers who don't use declarative style?



    Paul D. Murphy, when you say &quot;no markup&quot; for 1.1, do you mean a) no HTML (aka markup), b) no declarative controls (e.g. &lt;asp:button&gt;, aka markup), or c) no declarative data access? For the life of me I cannot see the advantage of (a) for 99% of Web developers, and I still kinda wonder about (b).

  • I think M$ has given this for RAD development / small demo's which you need to prepare / mockup's / poc's to be developed in a short term. The same time, they've given, ObjectDataSource also, which can be used. The application needs to be designed in such a way that we use ODS, not SQL DataSouce controls.



    JiniShans

Comments have been disabled for this content.