Tech Company Mentality in Fresno

My friend Robert Schultz recently gave his opinion on software programmer mentality in Fresno. I personally think it speaks to a larger issue going on with tech companies themselves in the Fresno/Clovis area.

I was born and raised in Fresno, and for at least 90% of the last 12 years I’ve been a full-time software developer for 6 different companies in the area. I hate to say it, but with most of them it was only about a year or two before I had to put in my resignation. They all had great people and great potential. But there was always some big setback that eventually caused me to leave.

Most recently my issues with these companies have been with both business direction and how they valued their developers. As engineers, we want to create and have our ideas listened to and our accomplishments valued. Lack of this is the main fault of most of the places I’ve worked for in Fresno (some more than others of course). Developers should never be treated as just “task monkeys” and handed a to-do list of specific items to check off. Many fall into that trap simply because that’s how it’s been for them for so long. At the point that it becomes “just a job” and they can’t wait until the clock hits 5 or 6 every day, and that’s only if they’re lucky and not forced into overtime.

Some of us have entrepreneurial aspirations and some do not, and that’s fine. But I think all developers want to contribute ideas and be in on the decision-making process wherever we work. We want to innovate all the time, and from my experience companies around here give little effort if at all to encouraging this process. At companies like Google it’s part of your job description. It’s no secret that sometimes half their new services came out of their “innovation time” policy. Plenty of startups elsewhere do something similar. Managers and company owners need to be open with their business goals and ask their people to openly discuss ideas and company direction. I know I would enjoy my job more if that was part of my responsibilities.

And I don’t think companies realize this, but with poor developer treatment they are taking a huge hit in efficiency. Projects start going in the wrong direction because they’re not listening to their people. In turn employees start working at a 25% motivation level because they don’t feel valued. The company starts falling way behind in current technology. Then developers stuck in this old technology realize they’re not going anywhere with their skills. It’s a vicious cycle. Developers that get fed up start looking elsewhere for something better, and when they have a tough time finding a better job around Fresno, they leave. That’s part of the “brain drain” we hear about.

Back to company mentality, we’re still behind in technology for the most part in Fresno from what I’ve experienced. Where are the companies really using social media or blogging regularly? Why do I still hear more about building Windows apps than mobile apps? Why do all these local companies spend so much time and money hosting their own servers (for internal use or external clients) instead of co-locating? It isn’t new news anymore that using cloud services (Google, Amazon or otherwise) are much more reliable, speedier and secure. Why are people still maintaining Exchange servers and installing Office on every workstation? Even Microsoft, who benefits from all the companies sticking with “classic” Exchange and Office setups realizes this is inevitable. They can host Exchange for you and are coming out with a browser-based version of Office 2010. Even Washington DC moved to Google Apps. At least consider What Would Google Do? This is 2009 people!

Myself and a handful of good developers I know in Fresno are very rooted here and thus determined to find the best place to work that they can. (That or start their own company). For me it’s because family and friends around here come before my career. Take that away from me and I’m out to bigger “tech hubs.” I know personally some good developers here that aren’t as rooted are just waiting for the right opportunity to leave. The business case for local startups Plastic Jungle (only local company I’ve seen on TechCrunch) and Vine Global (winner of last year’s Start-It-Up contest) to stay put were not enough, so recently they both left.

On behalf of all software developers in Fresno and Clovis (let alone the startup scene and effect on the economy locally), I sure hope this trend turns around soon.

Post to Twitter Post to Digg Post to Facebook

Drag and Drop Categorized Item List with jQuery and ASP.NET MVC – Part 2

Database and Model Classes

This is part two of a series. In this part I’ll describe the database structure and create the model classes needed for basic database interaction.

To keep things simple, I went with a SQL Server 2005 Express database as it’s free and easy to create within Visual Studio 2008. To create one, simply right-click on the App_Data folder and select SQL Server database. I named mine ListDemo.mdf.

After the database has been created, double-click on the new .mdf file to open it up. I created three tables: Lists, Sections and Items. Here’s the final database structure:

2009-07-15_db_diagram

Make sure to set the keys and relationships appropriately. The first ID field of each table should be the primary key and set to auto-increment. I also recommend turning on cascade delete to make deleting whole sections or lists easier. I’ll get into tying the lists table to a users table later.

In the Sections table, the ColumnNum field is to indicate which of the four DIV columns each section resides in. Values must be between 1 and 4. Once narrowed down to a column, sections are sorted by their SortOrder value. Likewise, in the Items table items are sorted within sections by their SortOrder value.

For now I manually created one record in the List table and named it “Demo List 1”.

2009-07-15_list_table

On to the “M” (models) in MVC. Again to keep it simple and quick, I chose to use LINQ to SQL even though you could argue I should use LINQ to Entities. I added a “LINQ to SQL Classes” item to the Models folder and named it ListDemo.dbml to match the database file. At this point the LINQ to SQL designer should pop open. Just drag the Sections, Lists and Items tables from the database view in the Server Explorer to the designer. When you click Save the LINQ to SQL code is generated for you behind behind the scenes. To view it look at the code-behind file for ListDemo.dbml.

Following a simple MVC convention, I created a model class for each table with the name ending in “Repository.” Specifically, ListRepository.cs, SectionRepository.cs and ItemRepository.cs (saved to the Models folder). Declared at the top of each class is a variable that references the data context. In each of the three classes I needed a method to retrieve a single record by ID. I called this GetById and used the Lambda/Method syntax of LINQ. It’s virtually the same in all three classes, but here’s the code for SectionRepository.cs:

public class SectionRepository
{
    private ListDemoDataContext db = new ListDemoDataContext();

    public Section GetById(long id)
    {
        return db.Sections.Single(s => s.SectionId == id);
    }
}

For now I’m going to ignore the ListRepository class since I’m just dealing with the single List record for now. In the Section and Item classes, next I coded up the Insert, Delete and Save methods. In all 3 methods I’m referencing the DataContext object, which has the already generated InsertOnSubmit(), DeleteOnSubmit() and SubmitChanges() methods (among others) in the LINQ to SQL auto-generated code. Here’s the code in SectionRepository.cs, but again it’s very similar in ItemRepository.cs:

public void Insert(Section sec)
{
    sec.SortOrder = GetNextSectionSortOrderValueByListIdColumnNum(sec.ListId, sec.ColumnNum);
    db.Sections.InsertOnSubmit(sec);
}

public void Delete(Section sec)
{
    //Items deleted via SQL cascade delete
    db.Sections.DeleteOnSubmit(sec);
}

public void Save()
{
    db.SubmitChanges();
}

When a Section or Item record is inserted, it needs to have a SortOrder value that is one higher than the max SortOrder value that already exists within it’s group (all items within a section, or all sections within a column). Using LINQ I created a private method in each of these two classes to retrieve this value before saving the record. In SectionRepository.cs:

private int GetNextSectionSortOrderValueByListIdColumnNum(long listId, int colNum)
{
    //Max value is null if no items yet
    int? highestSortValue = (from s in db.Sections
                             where (s.ListId == listId) && (s.ColumnNum == colNum)
                             select (int?)s.SortOrder).Max();

    return (highestSortValue ?? 0) + 1;
}

When we drag sections or items around, we are basically re-ordering the SortOrder value (and possibly changing the ColumnNum value for sections). jQuery can pass a string of separated ID values when posting to the server via AJAX, so I created the method UpdateSortOrder with a ColumnNum (for Sections) or SectionId (for Items) parameter along with a string array parameter in the two repositories. In SectionRepository.cs:

public void UpdateSortOrder(int columnNum, string[] sectionIds)
{
    for (int i = 0; i < sectionIds.Length; i++)
    {
        Section section = GetById(long.Parse(sectionIds[i]));
        section.ColumnNum = columnNum;
        section.SortOrder = i + 1;
    }
}

To see the final code for all three repository classes, download the sample project at the end of this post.

I know there’s no UI updates in this part of the series, but it’s important to get the database and model classes established before moving on.

Download the source code (requires Visual Studio 2008 and ASP.NET MVC 1.0)

Post to Twitter Post to Digg Post to Facebook

Drag and Drop Categorized Item List with jQuery and ASP.NET MVC – Part 1

Initial Layout and jQuery Setup

There are plenty of to-do lists out there where you can drag and drop to sort individual items, but I wanted to take it a step further and introduce categories. I wanted the categories containing the items to be sortable themselves, and not just within one column but several so it would maximize use of the web page layout’s width. The main use case I had in mind was for a grocery list, where type of food would be the categories. But it could be used for other things like a movie collection (genres as categories) or a sports league player roster (team names as categories).

This is part one in a series. In this post I’ll go through the initial layout and jQuery setup. In future posts I’ll go through the ASP.NET MVC setup in detail along with the database interaction.

For starters I kicked off an ASP.NET MVC project in Visual Studio 2008. I wanted a simple 4-column layout, so I added the CSS files from the excellent 960 Grid System and cleared out the existing Site.css file.

I’m using both jQuery and jQuery UI’s Sortable functionality, both of which can be referenced on Google’s CDN to reduce the page load time. I also added a new javascript file in the Scripts folder for custom functions.

With all these references the <head> section of the master page (/Views/Shared/Site.Master) now looks like this:

<head runat="server">
    <title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>

    <link href="../../Content/reset.css" rel="stylesheet" type="text/css" />
    <link href="../../Content/text.css" rel="stylesheet" type="text/css" />
    <link href="../../Content/960.css" rel="stylesheet" type="text/css" />
    <link href="../../Content/Site.css" rel="stylesheet" type="text/css" />

    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" type="text/javascript"></script>
    <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js" type="text/javascript"></script>
    <script src="../../Scripts/Custom.js" type="text/javascript"></script>
</head>

Since we’re not going to delve into the ASP.NET MVC project structure for now, I created a new View simply called “Main” in the /Views/Shared folder, which in turn references the master page. This will contain all the content HTML for the time being. Before I started this blog post I called the categories sections, so bear with me on the terminology switch from here on out.

Using the 960 Grid System’s structure I laid out the 4 columns. For now I just added placeholders for two sections in the first column, and one section each under the 2nd and 4th columns. Here’s the layout in Main.aspx so far:

<div class="container_12">

    <div class="clear"></div>

    <div class="grid_12" id="headerText">
        <h4>Categorized List Demo</h4>
    </div>

    <div class="clear"></div>

    <div class="grid_3 listColumn" id="col_1">
        <div class="secBox">
            <div class="secHeader">
                <h2 class="secName">Vegetables</h2>
            </div>
        </div>
        <div class="secBox">
            <div class="secHeader">
                <h2 class="secName">Fruit</h2>
            </div>
        </div>
    </div>

    <div class="grid_3 listColumn" id="col_2">
        <div class="secBox">
            <div class="secHeader">
                <h2 class="secName">Meat</h2>
            </div>
        </div>
    </div>

    <div class="grid_3 listColumn" id="col_3">
    </div>

    <div class="grid_3 listColumn" id="col_4">
        <div class="secBox">
            <div class="secHeader">
                <h2 class="secName">Dairy</h2>
            </div>
        </div>
    </div>

    <div class="clear"></div>

</div>

Within each section I added 3 items in an unordered list. Each section now follows this pattern:

<div class="secBox">
    <div class="secHeader">
        <h2 class="secName">Vegetables</h2>
    </div>

    <div class="itemBox">
        <ul class="itemList">
            <li class="itemRow">
                <span class="itemName">Broccoli</span>
            </li>
            <li class="itemRow">
                <span class="itemName">Spinach</span>
            </li>
            <li class="itemRow">
                <span class="itemName">Zuchinni</span>
            </li>
        </ul>
    </div>
</div>

CSS markup was added for simple styling. Here’s a screenshot:

2009-06-18_initial_layout

To make sure the root of the site brings up the view “Main”, go to /Controllers/HomeController.cs and make sure the Index action returns this view.

public ActionResult Index()
{
    return View("Main");
}

Next up is coding the javascript to enable drag and drop on both the sections and items. When making the sortable() call, sections must use the connectWith attribute to link to the 4 different columns, and items must use the same attribute to link to different sections.

For sections, I also set a handle so the user is forced to use the header to drag the sections around. If this isn’t included, there would be a conflict when dragging items since they already exist within the sections. Dragging a section by it’s header is also common among popular personalized home page sites such as iGoogle and PageFlakes. Other than that there are just some visual attributes set (cursor, opacity, placeholder) along with containment so the user can’t scroll off the page dragging things around. Here’s the javascript so far:

$(document).ready(function()
{
    InitSectionSorting();
    InitItemSorting();
});

function InitSectionSorting()
{
    $(".listColumn").sortable(
    {
        connectWith: ".listColumn",
        containment: "document",
        cursor: "move",
        handle: ".secHeader",
        opacity: 0.8,
        placeholder: "secBoxPlaceholder"
    });
}

function InitItemSorting()
{
    $(".itemList").sortable(
    {
        connectWith: ".itemList",
        containment: "document",
        cursor: "move",
        opacity: 0.8,
        placeholder: "itemRowPlaceholder"
    });
}

Here’s what it looks like dragging a section:

2009-06-18_section_drag

…and an item:

2009-06-18_item_drag

That’s about it for the layout and sorting functionality. In future posts I’ll tackle adding, editing and deleting using jQuery’s AJAX calling ASP.NET MVC methods, which in turn access a SQL Server database.

Final note: The styling seems to get messed up in IE. Should look OK in FF, Chrome and Safari though.

Download the source code (requires Visual Studio 2008 and ASP.NET MVC 1.0)

Post to Twitter Post to Digg Post to Facebook

Series for Drag and Drop Categorized Item List with jQuery and ASP.NET MVC

From part one…

There are plenty of to-do lists out there where you can drag and drop to sort individual items, but I wanted to take it a step further and introduce categories. I wanted the categories containing the items to be sortable themselves, and not just within one column but several so it would maximize use of the web page layout’s width. The main use case I had in mind was for a grocery list, where type of food would be the categories. But it could be used for other things like a movie collection (genres as categories) or a sports league player roster (team names as categories).

Throughout this series I’ll describe how I’m building this app in ASP.NET MVC and jQuery.

Post to Twitter Post to Digg Post to Facebook

Using the PBworks API with ASP.NET MVC and jQuery

Recently my company went with PBworks (formerly PBwiki) to use for internal collaboration. One of my projects is building a “dashboard” web app to bring in data from different sources, and the first thing users want to see in it is the recent activity log from the wiki. Here’s how I tapped into the PBworks API and brought it into the web app, which is being built using ASP.NET MVC and jQuery.

Since I can’t display my company data, I created a demo project using the jQuery UI design & planning wiki (a great resource in itself), since it’s a public wiki. The jQuery UI wiki is already enabled for API use. If you want to enable your own wiki, go to Settings > Developer Interface. Also note your three API keys as they’ll need to be passed along depending on your security settings.

Looking through the PBworks API documentation you’ll notice that they return all data in JSON. Naturally I thought the quickest route to retrieving that data would be call it’s URLs directly using jQuery’s getJSON call.

In my ASP.NET MVC project, for now I just wanted to see the PBworks data on the default view. So I simply went to /Views/Home/Index.aspx, cleared out the default content and added a custom div tag. The plan was to populate the div tag via AJAX using jQuery. Later this might make sense to move to a PartialView.

Directly after the div tag I added javascript to fill the div with the data returned from the PBworks API call. In this case I’ll use the GetChanges call to start and do a test to see if the getJSON call even executes. Here’s the code for the MainContent section of the view:

<div id="pbWorksData">
</div>

<script type="text/javascript">

    $(document).ready(function() {
        $.getJSON("http://jqueryui.pbworks.com/api_v2/op/GetChanges/_type/jsontext", function(data)
        {
            $("#pbWorksData").append("data goes here");
        });
    });

</script>

Since we’re using jQuery we need to add a reference to it in the main head tag. I added mine to the master page at /Views/Shared/Site.master.

<script src="../../Scripts/jquery-1.3.2.min.js" type="text/javascript"></script>

Unfortunately this first attempt didn’t work, which confused me for a while. The same type of call works with the Flickr API using the sample code in the jQuery getJSON docs. The URL also works if you navigate to it straight. And for this public wikis you don’t need to pass any API keys in the URL.

Further inspection with the excellent Firebug add-on reveals a security error.

20090512-jsonsecurityerror.png

Turns out the PBworks folks aren’t allowing cross-domain javascript calls, even using JSONP which is supported in jQuery as of version 1.2. This was confirmed in an email to them, reasons being for security. Notice also we’re not passing in a

To get around the cross-domain issue, we’ll just access the API via server-side code in a model class using the WebRequest and WebResponse classes. In fact we’ll just pass the JSON straight to the controller with little modification.

Here’s the complete PBworks model class. Notice at the end we had to strip out some surrounding text (/* -secure- */). If you don’t do this it won’t be recognized as JSON. PBworks informed me that it was in there to prevent the hijacking of credentials over browsers, and that they’re working on an alternative method to remove the need for this extra text.

using System.IO;
using System.Net;

namespace PbApiDemo.Models
{
    public class PBworks
    {
        public string GetChanges()
        {
            string url = "http://jqueryui.pbworks.com/api_v2/op/GetChanges/_type/jsontext";

            WebRequest request = HttpWebRequest.Create(url);
            WebResponse response = request.GetResponse();
            string jsonResponse = "";

            using (StreamReader sr = new StreamReader(response.GetResponseStream()))
            {
                jsonResponse = sr.ReadToEnd();
            }

            //Strip out surrounding /* -secure- */ text to keep it recognized as JSON
            jsonResponse = jsonResponse.Replace("/*-secure-", "");
            jsonResponse = jsonResponse.Replace("*/", "");

            return jsonResponse;
        }
    }
}

In the controller class (PBworksController), I just created an instance of the PBworks model and passed the JSON through as text, setting the browser’s page type to application/json.

using System.Web.Mvc;
using PbApiDemo.Models;

namespace PbApiDemo.Controllers
{
    public class PBworksController : Controller
    {
        private PBworks pbw = new PBworks();

        public ActionResult GetChanges()
        {
            return Content(pbw.GetChanges(), "application/json");
        }
    }
}

Now that the correct JSON is returned from a controller in the project, back in our default view we just change the URL in the javascript code.

$(document).ready(function() {
    $.getJSON("/PBworks/GetChanges", function(data)
    {
        $("#pbWorksData").append("data goes here");
    });
});

Ran the project now and sure enough the test text inside the getJSON call shows up. Now we’re in business.

Now that I had the complete JSON object, I needed to iterate over each item returned and render them appropriately on the page. To quickly see what’s available I pasted the JSON into this cool JSON 2 HTML tool.

For use in jQuery, the parent object we’re concerned with is actually contained in the changes collection. From each item within changes, I wanted to display and link the page, author, action taken on that page, and show the lasted edited date/time. I appended all this html via jQuery doing some formatting and manipulation to get the links and date/times right. Later on we might want to move the javascript to another file and optimize it a bit, but it works for now. Here’s the final javascript contained in the default view:

<script type="text/javascript">

    $(document).ready(function() {
        $.getJSON("/PBworks/GetChanges", function(data)
        {
            //Create an unordered list to hold all the entries
            $("#pbWorksData").append($("<ul/>"));

            $.each(data.changes, function(i, item)
            {
                if (item.page != null)
                {
                    //Get date/time from "epoch" number
                    var editDate = new Date(item.time * 1000);

                    $("#pbWorksData ul")
                        .append($("<li/>")
                            .append($("<a/>")
                                //Page name and link
                                //Replace spaces with dashes in url
                                .attr("href", "http://jqueryui.pbworks.com/" + item.page.replace(/ /g,"-"))
                                .append(item.page))
                            .append(" - ")
                            //Page "action"
                            .append(item.op_word)
                            .append(" by ")
                            .append($("<a/>")
                                //Page author and link
                                .attr("href", "http://jqueryui.pbworks.com/user/" + item.user_id)
                                .append(item.user_name))
                            .append(" on ")
                            //Last edited date
                            .append(editDate.toLocaleString())
                        );
                }
            });
        });
    });

</script>

The final rendering looks like this:

20090513-blog-pbworks-api-1.png

Hopefully this helps anyone else out there working with the PBworks API.

Download the demo project (requires Visual Studio 2008 and ASP.NET MVC)

Post to Twitter Post to Digg Post to Facebook

   Newer→