Training Review: Force.com Training on Pluralsight.com

Anyone that reads my blog knows that I am big fan (and regular subscriber) of the Pluralsight training videos. I cannot imagine staying up to date as a programmer without them. At this time, there are only a limited number of courses that cover the Force.com platform (8 to be exact), but I expect new titles will be added very soon. logo-v4

I really think that viewing these courses can be beneficial to anyone studying for the basic or advanced developer certification, or just people working with the Salesforce.com platform in general. These courses can also be valuable to developers (of any platform) that want to determine whether learning more about the Force.com platform is beneficial to them.

Pluralsight offers a free trial that allows you to view 10 days and up to 200 minutes of training. That would allow you to view for free at least one, but maybe two of the courses I describe in this post. Below, I will summarize which courses you should view, depending on where you are coming from and what you are trying to achieve.

First of all, if you only have time to watch one of these courses, I would watch this one:

Force.com Platform: The Big Picture by Don Robins – This is a high-level course that would be very useful for someone brand new to the platform. It is short (1 hours and 24 minutes) and would also be of great interest to experienced developers that have not worked with the platform for long. Robins includes a lot of history about Salesforce and does an excellent job of describing the “Perspective Shift” that is necessary for developers that want to be successful on the platform.

If you are studying for the First-Level Salesforce Developer Exam, I recommend viewing the following course:

Force.com For Developers by Richard Seroter – This is the longest course in the series (5 hours and 47 minutes), but it is also the most thorough. It provides a good overview of the entire platform in a very clear and easy to understand way. Seroter covers many topics that are covered on the 401 Dev exams, such as Reports, Workflows and Approval Processes. He also covers topics on the 501 Advanced Developer Exams, so this course would be good for people studying for that exam as well.

If you are studying for the Second-Level Salesforce Advanced Developer Exam, I recommend viewing the following courses:

Force.com Design Patterns – Part 1 by Adam Purkiss – This course is definitely not for beginners or anyone new to the platform. Purkiss talks about advanced topics such as the use of wrapper classes to get around some of the inherent limitations of SOQL. Some of the code walk-throughs were unpolished and appeared to have not been practiced in advance, but the beginning of each section was very good. My favorite section was the one on Trigger Design Patterns.

Force.com Design Patterns – Part 2 by Adam Purkiss – This course has three distinct segments and I can see the first two (Test Design Patterns and VisualForce Architecture) being especially valuable to anyone pursuing the Advanced Developer Certification. I actually enjoyed this course more than the preceding Part 1, because the examples were more general and the author did not have to waste a lot of time describing how the sample application worked. Purkiss includes many best practices that if you follow will ensure that your code stands the test of time. I really enjoyed the section on how to use Knockout.js to do JavaScript Remoting to create an HTML page that saved custom settings directly to Apex.

Introduction to Visualforce by Matt Lacey – This was my least favorite course, mostly because the speaker had a heavy accent that was hard to understand. He also rushed through the content and the general audio quality of the video was bad. However, the course did provide useful content that would be relevant to anyone studying for the Advanced Developer exam.

If you are an Experienced Software Developer that wants to understand more about the Force.com platform, I recommend viewing the following courses:

Force.com for .NET Developers by Dan Appleman – This course does a very good job of describing the Force.com fundamentals in way that makes sense to .NET developers specifically. Appleman is an experienced author who spent many years creating content for the .NET community, but a few years ago he switched (almost primarily) to working with the Force.com platform. Like myself, Appleman does not dismiss the .NET platform and certainly sees it as still viable, but he also can see the alluring reasons to understand the Force.com platform as well.

Force.com and Apex Fundamentals for Developers by Dan Appleman – Unlike the last course that was specifically designed for .NET developers, this course was designed for developers coming from any platform. It is not a course for people new to programming, but attempts to give experienced software developers a head start to writing “GOOD” code on the Force.com platform. Appleman will tell you about best practices and describe real-world scenarios that only come from hard-earned experience. Most importantly, he covers why design patterns used in other languages do not always apply in Force.com. He focuses on the 4 most important concepts (Execution Context, Use of Static Variables, Limits and Bulk Patterns) that you need to know to start working safely and efficiently in Force.com.

Patterns of Cloud Integration by Richard Seroter – This is NOT a course specifically about Force.com and instead focuses on many technologies that can be used to accomplish integration with cloud applications (on any platform, Force.com included). This course would be of great interest to any technical architects that need to understand to complexities involved with integrating cloud-based applications. Seroter is no doubt an expert in this field and he covers a variety of tools and platforms (such as Biz Talk Server, Windows Azure Service Bus, Mule Cloud Hub and custom code using .NET, node.js, Java, etc) used to integrate Ground to Cloud, Cloud to Cloud, or Cloud to Ground scenarios.

Google Charts and ASP.NET

I recently had the opportunity to redesign a very small web application that was used to display residential housing statistics. The previous application was created over 10 years ago and as you can imagine, now leaves a lot to be desired. It was an ASP.NET application that used many post back operations to render charts using a very limited 3rd party charting tool. It performed slowly and lacked a lot of the key functionality the client wished for (namely the ability to display data for multiple subdivisions within the same chart).

My mission was to create a new ASP.NET solution that performed well on all devices (as this is critical for a web applications success), and was easy to use, yet delivered as much information as possible on a single page. After much consideration, I decided to use the Google Charting API to render the charts. Google Chart tools are simple, free and interactive.

I also utilized Bootstrap to create a modern and responsive design and JQuery to enable a fast and asynchronous user interface. Since this post is titled, “Google Charts and ASP.NET”, I will only focus on the code used to render the actual charts. The solution (as seen below) is what I ended up with.

MLSStats

As this is a technical blog, I will now share with you some of the code used to create this solution. The amount of HTML markup used in the ASP.NET page is actually quite small. The code that is used to render the Google Charts is created dynamically in server-side code and is written back to the web page inside of individual div blocks for each data metric.

To use the application, the user selects a subdivision using any one of the four criterias provided (Parish, Area, City, or Zip).  If the user selects a certain value (for example, “East Baton Rouge” as the Parish), then JQuery and an Ajax call is used to populate the subdivision select box with only the subdivisions for that parish. The user can add as many subdivisions as they want and once all the charts are rendered (which takes only a few seconds), they can flip between each data metric by selecting one of the tabs across the top.

When a user clicks the “Add a Subdivision” button, a server-side call is made to a method which collects all the search criteria and then passes this off to a function called renderChart in a class called Chart. The code (which is seen below) will call the renderChart once for each data metric displayed and will return a string that contains the JavaScript code needed to render that particular Google Chart.

var sc = new SearchCriteria();
sc.parish = ddlParish.Value.Trim() == "" ? null : ddlParish.Value;
sc.area = ddlArea.SelectedValue.Trim() == "" ? null : ddlArea.SelectedValue;
sc.city = ddlCity.SelectedValue.Trim() == "" ? null : ddlCity.SelectedValue;
sc.zip = ddlZip.SelectedValue.Trim() == "" ? null : ddlZip.SelectedValue;
sc.sub = Request.Form[ddlSubdivision.UniqueID];
sc.timeFrame = ddlTimeframe.Value;
if (this.optParish.Checked) sc.type = "parish";
if (this.optArea.Checked) sc.type = "area";
if (this.optCity.Checked) sc.type = "city";
if (this.optZip.Checked) sc.type = "zip";

var chart = new Chart();
ltAvgPriceSqFt.Text = chart.renderChart("AvgPriceSqFt", sc);
if (chart.blnDataFound)
{
     ltAvgSalesPrice.Text = chart.renderChart("AvgSalesPrice", sc);
     ltMedSalesPrice.Text = chart.renderChart("MedSalesPrice", sc);
     ltAvgSPLP.Text = chart.renderChart("AvgSPLP", sc);
     ltAvgSPOLP.Text = chart.renderChart("AvgSPOLP", sc);
     ltAvgDOM.Text = chart.renderChart("AvgDOM", sc);
     ltTotalListings.Text = chart.renderChart("TotalListings", sc);
}

Each time a subdivision is added to a chart, it is also added to a Subdivision List stored in the HTTP Cache. Since it is possible for the user to click Add Subdivision more than once, without changing what subdivision is selected, we want to prevent the same subdivision from being added to the cache multiple times. The following code is the first thing executed in the renderChart function:

List lst = new List();
Cache cache = HttpContext.Current.Cache;
if (cache["selectedSubs"] != null)
{
    lst = (List)cache["selectedSubs"];
    if (lst.Count > 0)
    {
        //Make sure the selected subdivision is not the same as one
        //of the ones already cached
        int idx = -1;
        idx = lst.FindIndex(x => x.SubdivisionName == sc.sub && x.Parish == sc.parish
                    && x.City == sc.city && x.Zip == sc.zip);
        if (idx > -1) lst.RemoveAt(idx);
        if (lst.Count > 0) blnMultipleSubs = true;
    } 
}

The next thing to do is to get the data used to render the charts. The renderChart function makes a call out to one of two other functions (either GetSqlDataForMultipleSubs or GetSqlDataForSingleSub) within the Chart class to do this. The code below, which returns a DataTable shows this:

if (blnMultipleSubs)
{
    dt = GetSqlDataForMultipleSubs(numberToReturn, sc, lst);
}
else
{
    dt = GetSqlDataForSingleSub(numberToReturn, sc);
}

The last thing to do is to loop through the data in the DataTable variable named dt and build a string that will be returned by the function. The code below will accomplish this:

if (dt.Rows.Count > 0)
{
    blnDataFound = true;
    str.Append(@"
    google.load(*visualization*, *1*, { packages: [*corechart*] });
    google.setOnLoadCallback(drawChart);
                                
    function drawChart() {
        var data = new google.visualization.DataTable();
        data.addColumn('string', 'Date');");

    if (blnMultipleSubs)
    {
        foreach (Subdivision sub in lst)
        {
            str.Append(" data.addColumn('number', '" + sub.SubdivisionName + "');");
        }
    }

    str.Append(" data.addColumn('number', '" + sc.sub + "');");
    str.Append(" data.addRows([ ");

    for (int i = 0; i <= dt.Rows.Count - 1; i++)
    {
        str.Append("['" + dt.Rows[i]["date"].ToString() + "', ");
        if (blnMultipleSubs)
        {
            foreach (Subdivision sub in lst)
            {
                str.Append(dt.Rows[i][sub.SubdivisionName].ToString() 
               == "" ? "null," : dt.Rows[i][sub.SubdivisionName].ToString() + ",");
            }
            str.Append(dt.Rows[i][sc.sub].ToString() == "" ? "null]" : dt.Rows[i][sc.sub].ToString() + "]");
        }
        else
        {
            str.Append(dt.Rows[i]["number"].ToString() + "]");
        }

        if (i + 1 < dt.Rows.Count)
        {
            str.Append(", ");
        }
        else
        {
            str.Append("]);");
        }
    }

    str.Append(@"
            var options = {width: 850, height: 400, 
           pointSize: 10, chartArea: {left: 80}, curveType: *function*, ");
                    
    if (numberToReturn == "AvgPriceSqFt")
    {
        str.Append(@"vAxis: { format: '$#,###' }, 
        title: *Average Price Per Square Foot for " + sc.timeFrame + "*}; ");
    }
    else if (numberToReturn == "AvgSalesPrice")
    {
        str.Append(@"vAxis: { format: '$#,###'}, 
        title: *Average Sales Price for " + sc.timeFrame + "*}; ");
    }
    else if (numberToReturn == "MedSalesPrice")
    {
        str.Append(@"vAxis: { format: '$#,###' }, 
        title: *Median Sales Price for " + sc.timeFrame + "*}; ");
    }
    else if (numberToReturn == "AvgSPLP")
    {
        str.Append(@"vAxis: { format: '#%' }, 
        title: *Average Sales Price/Listing Price for " + sc.timeFrame + "*}; ");
    }
    else if (numberToReturn == "AvgSPOLP")
    {
        str.Append(@"vAxis: { format: '#%' }, 
        title: *Average Sales Price/Original Listing Price for " + sc.timeFrame + "*}; ");
    }
    else if (numberToReturn == "AvgDOM")
    {
        str.Append(" title: *Average Days On Market for " + sc.timeFrame + "*}; ");
    }
    else if (numberToReturn == "TotalListings")
    {
        str.Append(" title: *Total Listings for " + sc.timeFrame + "*}; ");
    }

    str.Append(@" 
        var chart = new google.visualization.LineChart(
             document.getElementById('" + numberToReturn + @"'));");

    if (numberToReturn == "AvgPriceSqFt" || numberToReturn == "AvgSalesPrice"
        || numberToReturn == "MedSalesPrice")
    {
        str.Append(@"
            var formatter = new google.visualization.NumberFormat(
                {prefix: *$*, negativeColor: *red*, negativeParens: true});
            formatter.format(data, 1);");
    }

    str.Append(@" 
        chart.draw(data, options); }");

    str.Append(@" 
    

NOTE: Hover over dots in chart to see individual data points

"); return str.ToString().Replace('*', '"'); } else { blnDataFound = false; str.Append(@" hidestuff('startInfo');

ATTENTION:
No data was found for the " + sc.sub + " subdivision. Please select another subdivision or a different timeframe.

"); return str.ToString().Replace('*', '"'); }

The end result for a call to renderChart will be a string of JavaScript code that will be written back to the HTML page inside of one of the predefined Literal placeholders. For example, a call to renderChart in which there are no other subdivisions in the cache and the search criteria was Parish = “EBR”, Subdivision was “Broadmoor East” and time frame was “5 years”, would produce the following output for just one of the data metrics (in this case the AvgPriceSqFt):


google.load("visualization", "1", { packages: ["corechart"] });
google.setOnLoadCallback(drawChart);


function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Date'); data.addColumn('number', 'BROADMOOR EAST'); data.addRows([ ['2009', 78.36], ['2010', 68.38], ['2011', 61.25], ['2012', 55.76], ['2013', 71.61]]);
var options = {width: 850, height: 400, pointSize: 10, chartArea: {left: 80}, curveType: "function", vAxis: { format: '$#,###' },
title: "Average Price Per Square Foot for 5 Years"};
var chart = new google.visualization.LineChart(document.getElementById('AvgPriceSqFt'));
var formatter = new google.visualization.NumberFormat(
{prefix: "$", negativeColor: "red", negativeParens: true});
formatter.format(data, 1);
chart.draw(data, options); }

I really enjoyed working with Google Charts and found it to be very lightweight and flexible. I did not find it necessary to use the Google .NET Wrapper to work with it and ASP.NET. In fact, I will do a separate post about this since it will take a while to go into why this is the case and this post is already too long.

Hope this helps someone. I will try to save all the code to files and post links to them in the post later.

Why a .NET Developer Loves Force.com

When I graduated from College 20 years ago, I had no idea how much would change in the world of Software Development. Back then, the college I attended taught students COBOL as the primary language (and yes, I realize that some people reading this will not even know what that is).

It is lucky for me that I love learning new things. My entire career has been one VERY long lesson – one that changes on an almost daily basis. Blink and you’ll miss the next great language, platform or tool.

While learning new things never bothered me, the other day a simple exercise demonstrated to me how much of a hit my productivity has taken as a result of all the constant big changes in the .NET world of development.

I have been focused on .NET development ever since it emerged and before that, I was a big Visual Basic developer. A little over two years ago, I was introduced to the world of Force.com. One of my clients was using Salesforce and they needed to make it work well with the .NET-based Portal platform they were using.

Despite some initial hesitations, I found myself liking the platform more and more. I loved how stable it was and how I did not have to waste days tracking down crazy server configuration issues (like I did so often when deploying .NET applications). So over the past two years, I have spent as much time as possible learning all about it. A few months ago, I earned the Developer certification and I am currently studying for the advanced certification.

I really came to appreciate the platform when the other day I decided to use it to build a prototype application for a new client. The client was unsure about whether to go further with a project to replace their membership management system. In less than two days (10 hours total), I was able to put together a bare-bones membership management system using a free developer edition.

gbrarams

The prototype application (which has been intentionally blurred to hide sensitive data) included tabs for Documents, Reports, Dashboards, Chatter and Ideas, right off the bat. No programming required. Not a single line of code had to be written. All I did was use the declarative features of the platform to build the app and then I used the Apex Data Loader to import a large group of production member data into the new system. This really helped the client to see the potential of the platform.

I could have never put together something like this on the .NET platform so quickly. The reality is that it would have taken weeks to have put together a .NET prototype with the same amount of functionality. Now, do not get me wrong. I Still love .NET and I am not trying to put it down in any way. But, I have to be honest when I acknowledge that being a .NET developer these days can be a tad bit overwhelming. It seems like just when you have some new tool or language figured out, it has become obsolete and no one is using it any more.

I doubt I will ever get to the point where I am focused solely on any one platform (Force.com or .NET). I think the trick to being valuable as a developer is to keep an open mind and have as vast a skill set as possible. There is never one tool for every job in this business.

I would love to hear what you think???

Book Review: Visualforce Development Cookbook

Not a book for beginners, but GREAT for seasoned Apex developers

I recently had the honor of reviewing the recently published, Visualforce Development Cookbook. The code recipes are great and could really go far in demonstrating the potential of the platform. It is obvious that the author, Keir Bowden has implemented many, if not all of these recipes in real-world scenarios. However, I think this is a dangerous book for developers new to the Force.com platform. In fact, I would not recommend it to anyone who has not worked with the platform for at least one year.

While step by step instructions are provided, along with occasional notes about real-world considerations that should be made, the author does not go into detail about these considerations. For example, on page 36, the author advises readers to use a Utility class to handle creating the data, but does not go into how to actually do this.

Also, the author only provides test code for one of the recipes in the first chapter and then never mentions testing again. Anyone that has worked with the platform for a while knows that writing test code can sometimes take longer and be more difficult than writing the actual code. I could see someone new to the platform using this book to create many changes in their development org and get everyone excited about using the stuff and then never be able to get all the required unit test code together in order to deploy.

The sample code that was provided was easy to download and well organized. It was also formatted properly so that you could cut and paste it straight into your development org. Very little sample code is included in the actual book, which I think helps to ensure that the book stays up to date. As long as the publisher and author continue to update the sample code with each new Salesforce release, the code should stay viable as the platform inevitably changes.

I REALLY liked the chapters on JavaScript, Force.com Sites and Mobile Development and cannot wait to try out some of the recipes included for my clients. My favorite part of the whole book was the fact that the author utilized the Google Hosted Libraries Content Delivery Network rather than static resources for the jQuery code. This was a very smart move and helps to ensure that the code stays viable in the future and also makes use of the latest industry standards.

Some of my favorite Javascript recipes included the tooltips (which featured a slick slidedown effect), the collapsible list elements and the scrolling news ticker. This chapter really demonstrated to me the power of Visualforce and how you can use it to make some powerful and dynamic pages that are unique to your brand.

I really appreciated the final chapter on jQuery Mobile. In fact, if you read only one chapter in this book, read this one. As the author explains, the book is about Visualforce and not mobile development, so it focuses on using HTML5 and the jQuery Mobile Framework to provide the interface code. My favorite recipe in this chapter was the one on navigation and transitions. The author includes transition examples that pop, flip, turn, flow and slide the user from one page to the next. Sweet!!! I will warn you that the code did not display well on my iPhone, but I plan on looking into this further and if I find out the reason why, I will do a separate post about this.

I did find a few inevitable errors in the book as I worked through the code recipes, but the errors were minor and I got past most of them easily. I will report the ones I found to the publisher as errata.

In short, this is an invaluable resource for seasoned Force.com developers, but should be approached with caution for newbies. Force.com is a powerful platform. Much more powerful than most people give it credit for. While this book does include recipes that clearly demonstrate that power, I think experience is needed to help the reader apply the knowledge from this book in the best way possible.

Custom Components Not Rendering Properly

After much searching, I have finally figured out what was causing two frustrating issues I have run into several times and thought I would share it with everyone. Both issues involve creating a Custom Component that includes HTML.

If you use an iframe tag to reference an existing Visualforce page and do not include a certain switch in your URL, the component will not be rendered properly and instead of seeing the rendered Visualforce page, you will just see code in the area where your custom component should be (see top left home component of image below)

CustomComponentsShot1

To avoid this issue, you must add a parameter to the url attribute for your iframe tag. For example, the component titled, Case Count By Status was referencing a Visualforce page named CasesSidebar using an iframe tag. Instead of using src attribute that looks like the following:

src="/apex/CasesSidebar"

you will need to include a switch after the page name called isdtp. The src attribute should instead look like the following:

src="/apex/CasesSidebar?isdtp=lt"

A second issue involves how you enter the HTML for your custom component. If you are not careful about how the HTML is entered, your component will end up displaying the actual HTML code and not the rendered result. For example, if you were to add a Custom Component to the Home page by going to Setup | Customize | Home | Home Page Components and clicking New, you will be brought to a page that looks like the following:

CustomComponentsShot2

If you were to start entering HTML code into the editor below and THEN click Show HTML, you will have a problem when the component renders. Instead of displaying the rendered iframe, you will just see the iframe HTML where your component should be.CustomComponentsShot3

You MUST click the Show HTML checkbox BEFORE you type or paste any code into the editor area. I personally think this is a bug and it should not matter when you click the Show HTML checkbox, as long as you do so before clicking Save.

Perhaps Salesforce will fix this at some point in the future, but in the meantime, I wanted to post this and hopefully it will be found by someone encountering the same issue.

Anatomy of a Great System Document and Why you should Bother

As a professional writer, I admit that I probably focus on documentation more than your average software developer. Over the years, I have learned quite a bit about what goes into making a GREAT system document. I have also noted the extreme lack of good quality system documentation at many of my client locations.

Unfortunately, next to initial design and testing, documentation probably comes in last as far as the amount of time allocated to it for development projects. I have met plenty of programmers who think that the only documentation they have to provide is the occasional comment in their code. By the time the project is over, very few people take the time to go back and create a proper system document.

What most novice programmers fail to realize is that good system documentation is not just a benefit for the client or even for other programmers. It is also not just for large or commercially-based projects. A system document should be created for any size software development project, whether that be for a commercial-based project or just a single-man project done in a small IT department.

Why Bother?

If done properly, a system document can serve many purposes – most of them benefiting the person that created the document. I have been creating system documents for all my software projects for the past 20 years and I have benefited in the following ways:

  • A GREAT system document serves as a calling card for you. It demonstrates that you are a quality worker and that you are attentive to detail. It also reminds people about the work you have done long after you have left a place. This is especially important for software consultants. I actually had a former boss recently contact me for a consulting job, all because he ran across a system document I produced 10 years ago.
  • You can refer to some of your best ones when trying to land a new job or consulting gig. Unless you work exclusively with public facing web sites, it is not always easy to provide a direct link to some of your past work.

    If you keep copies of all the system documents you have produced for employers or clients, you can use these as examples of your quality work. I can promise that offering or producing them for an employer WILL set you apart from the rest of the developers.

  • It can save you LOTS of time. I cannot tell you how many times I have gone back to reference system documentation I have wrote for one project when working on another. In many cases, the stuff I read (even just 6 months later) seems entirely brand new to me and is often very helpful in pointing me in the right direction for resolving a problem or coming up with a good idea.

What Should it Contain? SystemDocTemplate

After years of creating system documents, I have learned a thing or two about what works best. For example, simple and straight to the point language is the best. It should NOT read like a White Paper or some graduate student thesis. It should not even resemble professional software documentation.

If you are creating a system document for a project that involves using some other piece of software, do not include information that could be found in the manual for that software. For example, I created a system document for a large integration project that I worked on. The project involved using a software tool called Scribe to create data transformation scripts. Scribe already has extensive documentation that covers how to use that product. There was no need to include any of that. In fact, my document included a section that stated this fact and pointed the reader to where the online Scribe documentation was located.

The system document you create should contain the kind of information that is not obvious. Get to the point and stick to only including things that someone like you, someone who knows the project intimately would know. The exact length of the document will vary depending on the complexity of the project.

Your document should always include a Last Updated area in the header. This should include a date time that is updated automatically when the document is opened and saved.

As far as what sections to include, I suggest some of the following:

  • What is this about?
    This section is required and should be the first section in every system document you produce.  It should contain information about who originated the project and provide some reasoning for why it was done. The system may be multifaceted and involve multiple applications and scripts, so all of these pieces should be referenced in this section.
  • How do I use or access it?
    This should provide a basic overview of how to use or access the system. If the application is web-based, it should contain a link to it. If it is a desktop or console application, it should specify where the installation files are located. It should also include any special logins and passwords that may be needed.It should assume the reader knows nothing about the system and they are just getting started using it. Including screenshots of the application can be very helpful. This should not be as extensive as a complete user document, but it should at least get the reader logged in to the system and familiar with the basic layout.
  • How do I get started supporting or modifying it?
    This should contain information that a software developer would need to know to access the system as quickly as possible. If the system consists of more than one application, then it should contain links or paths to where the code is located for all applications. If working with the software involves installing any other special software, it should include information about that and what is needed.
  • What if it does not work right?
    Hopefully, the person creating this document has kept notes while working with the system and has undoubtedly encountered issues while testing and deploying. These notes will be helpful in building this section, which should be a bulleted listing of what these issues are and what can be done to resolve them. Remember, the reader of this document is someone who will be tasked with supporting the system and they will likely not be familiar with all the problems you faced creating the system.
  • What kind of changes will I need to make to the system?
    Ask yourself what kinds of changes will likely need to be made to the system and use this section to list those areas. For example, what if the system needs to be moved to different servers? What if the person supporting the application needs to change configuration or database settings?

When should it be created and how much time will it take?

Ideally, you should allocate time in every software project for creating system documentation. The amount of time you allocate is proportional to the size of the project and in my experience is usually about 10% of the total project time. So, if a project takes 100 man hours to design, code, test and deploy, 10 hours should be allocated to creating system documentation.

NOTE that this is separate from any user documentation that you may have to create. The time required to produce user documentation should be included in the total project time. The reader of the system document is someone who will be tasked with supporting or modifying the application. They are likely a software developer and you should assume that they are brand new to the organization.

I understand that creating system documentation like this is not something that comes natural to most developers. But, I can promise that the more you do it, the easier it gets. And, I can also promise you that if you take the time to do it right, you will thank yourself for doing it one day.

Clean Code: Writing Code for Humans

I am a proud monthly subscriber of the online training website Pluralsight. I cannot imagine staying up to date in this field without that subscription. Since my blog focuses on Salesforce concepts, I will tell you that Pluralsight offers several brilliant courses that cover Salesforce.

CleanCodeBut, this post is titled “Clean Code: Writing Code for Humans” by Cory House, a brand new course just offered on Pluralsight. The course is described as the following:

“Anyone can write code a computer can understand, but professional developers write code *humans* can understand. Clean code is a reader-focused development style that produces software that’s easy to write, read and maintain.”

If you are new to programming (of ANY language), then this course if for YOU!

Even if you are an experienced programmer (of ANY language), then this course is for YOU TOO!  I have been doing software programming for over 20 years and have regularly espoused many of the concepts covered in this class, and I learned plenty by watching it. We are ALL prone to writing dirty code and this course has great practical advice for how to avoid this.

If your goal is to remain a programmer (more specifically, a productive and respected programmer), then this course is definitely for YOU!!!!!

Even if you do not already have a subscription to Pluralsight, never fear, they offer a free 10-day trial subscription. So, you really have no excuse. Go and see it I tell you.

Proper Use of ActionStatus component

In preparation for the Advanced Developer exam, I have been painstakingly going page by page through the Visualforce Developers Guide (which can be found online here). Almost every single person that has passed the exam has suggested that you become intimate with this document, but I wonder how many people truly are. I keep finding that the code listed in the tutorials does not work as it should. My last post was about one such error and now I have another big one.

On page 44 of the guide, they provide an example of using the ActionStatus component to provide a status for Ajax operations. Great! It is an awesome tool, but unfortunately, the code example they provide on that page does not work. If you copy the code from this tutorial and use it in a page and then try to see the text, you will not see it.

You can however, make two simple code changes to the code they provide and it will work as promised. But, only if you do this, will it work. So, the code that does work is seen below. What the tutorial authors missed was that an id attribute is needed for the ActionStatus component and that id value must be referenced in the status attribute of another component on the page.

ActionStatusProblemCode

Hope this helps someone else from not being confused about how ActionStatus is supposed to work. At first, I thought I was just not seeing it quickly enough (silly me…)

Setting Tab Order – Use TabOrderHint instead of TabIndex

In the last few days, I have been preparing for the Advanced Developer Certification by going page by page through the recommended Salesforce Developers Guide. I was shocked when I received an error trying to save a sample page using the code supplied in the online guide (page 39). The sample page involved setting the tab order for fields in a form and the code referenced an attribute named TabIndex. When I attempted to save the sample page, I got the following error:

Unsupported attribute tabIndex in <apex:inputField> in myPage at line 5 column 56

In my experience so far, Salesforce has been excellent about keeping their docs up to date, but I am afraid this one may have slipped through the cracks. After doing a search through some forums, I discovered that the tabIndex attribute was replaced with a new attribute named tabOrderHInt in Winter 12. So, any code created since then (which is about a year at this point), will not work using the code example supplied in their online Developers Guide.

Updated Podcasts of Apex Training

UPDATE: According to Chris Barry , the instructor in these pod casts, Salesforce has removed them because they are now focusing on new/better low cost training. As soon as I learn more about what that is, I will post about it here.

For anyone studying for the Salesforce Advanced Developer Certification, I strongly suggest you check out the following recently refreshed series of Podcasts posted on ITunes. They are recorded sessions of a fairly recent (from the Spring 2013 time frame) class given by Chris Barry at Salesforce.

There are some differences between the online premier training and the in-class training, but for the most part, you could follow the notes posted on this blog as you watch the Podcasts. Just keep mind that the episode about the Developer Console is very out of date, since the Developer Console has changed dramatically in the Summer release.