Secret ingredients to quality software

Rules to Better Websites - Development - 42 Rules

  1. Do you know the right technology?

    Use .NET MVC over ASP.NET Web Forms .

        NavigateUrl="" CssClass="example"
        Text="Hello World"/>

    Figure: Bad example - Using Web Forms

    <a href="" class="example" id="Example1_HyperLink1">Hello World</a>

    Figure: Good example - Using MVC 5Read the Top 5 reasons why you should never use Web Forms again:

    1. Testability - MVC provides true separation of concerns, and makes it easy to test the whole application from Unit Tests to Coded UI Tests
    2. Instant Pages - Get your admin pages up and running faster than ever with improved scaffolding. Don't get bogged down doing Create, Edit, Update, Delete
    3. Better HTML Markup Control - Every layer of obstruction creates new problems down the track. When so much development now involves jQuery or other javascript libraries, MVC simplifies development by putting the developer back in charge of the HTML that is actually rendered
    4. Simpler Debugging - This means that instead of complicated Webform lifecycles, your code either goes into the Route, Controller or View, so you can jump right into coding without an intimate knowledge of the page lifecycle
    5. Mobile Support - With Adaptive Rendering, MVC allows the same User Interface to Render on Different Devices, so users can check it out on their PC, their Tablet or even their Smart Phone

    Or watch the video:

  2. In order to keep the content you add is healthy (doesn't have grammar or spelling mistakes), follow the below steps once you add a page:

    1. Check the rule in MS Word (or Grammarly) to see if it has spelling or grammar mistakes
    2. Run Link Auditor and Code Auditor on that page
    3. Check the report and fix the errors (if any)
      Repeat step 2 and 3 until Link Auditor and Code Auditor get all green ticks
  3. Do you have a structured website?

    The following structure allows you to keep your website clean of clutter:

    • /Images  - for all static images
    • /Images/Dynamic  - for all images used in dynamically generated pages  NOTE: the reason we use two images directories is so we can exclude images used by dynamically generated pages from our link checking program. This is so we can work out the TRUE orphan images (and believe me, like coat-hangers they multiply quickly ...)
    • /Includes  - for all include files
    • **/Bin ** - for mdb's, dll's and udl's
    • /Shop  - for the shopping basket and related pages
    • /Clients  - for the client login page and related pages
    • **/Reports ** - for any SQL Server Reporting Services
    • **/zsMaintenance ** - for the administration section to modify web site settings
    • /zsValidate  - for all web server status and validation checks

    The root directory should be clean, having only:

    • default (.aspx, .asp, .htm)
    • global.asa
    • **application.sln **
  4. Do you always have a default/index page?

    Many times a website contains directories that don't have an index page, and this means a user navigating via the URL, see a 404 error. You don't want this to happen, so make sure you always have an index page in every directory, even if it's just to show the files inside it.

    It is usually a default.aspx file, however depending on the webserver configuration; it might be index.html or index.php etc.

  5. A stylesheet file (.CSS) should be used to dictate how the fonts, headings, tables, captions and everything else on your HTML should be displayed.

    This makes your site very easy to maintain. If you ever want to change the entire look and feel you should only have to change one file.

  6. It is always better to make sure there are equivalent closing quotations for HTML attributes. A small mistake of missing a quotation could lead to undesired results on the web page.

    <span style="font-size:12pt; background: #ccc;>

    Figure: Bad code - Can you see the missing quote? Code Auditor can

    <span style="font-size:12pt; background: #ccc;">

    Figure: All OK

    As you can see from the above example, just missing a quotation makes the whole layout of the text different. So be very careful that you make sure you have closed all opening quotations of attributes with equivalent closing quotations.

    We have a program called SSW Code Auditor to check for this rule.

  7. Any website designer that needs to display code should be aware that there is a very simple method for simply formatting code, and there is a slow and complex method.

    The complex method requires formatting each line with HTML tags (such as <br> and  ) to ensure the code looks nice and pretty.

    The simpler method uses <pre> tags. Pre (standing for "preformatted") means that the code is formatted exactly as it is written in the HTML window. This means the page designer can format code in a very simple fashion, without worrying about tags.

    Note:  <code> tags should not be used because they only provide the font Courier - you still have to manually indent all of your code as in the bad code display example below.

    <font face="Courier, Times, Arial, Verdana" size="3">
    public class Configuration
    &nbsp;&nbsp;public static string MySetting

    Figure: Bad code display example - using <font>

    public class Configuration
    &nbsp;&nbsp;public static string MySetting

    Figure: Bad code display example - using <code>

    public class Configuration
    public static string MySetting

    Figure: Good code display example - using <pre>

    Tip:  Do not use auto-format (Ctrl-K, Ctrl-F) in Visual Studio when updating page with <pre> tags, or it will destroy all the code formatting. We have made a suggestion to Microsoft to fix this.

  8. You should  understand the hierarchy and try to use the heading tags (<H1>, <H2> or <H3>...) for titles and subtitles.

    It's also important to customize these headings via CSS, making the font bigger, bold or in a different color. This way page looks nice and organized.

    The following benefits of using heading tags:

    • Improves the ranking with the search engines (extra weighting is given to text in H1 and H2)
    • Makes cleaner and leaner HTML
    <p><span class="Heading">Introduction</span> 
    Lets chatter about...</p>

    Figure: Bad example - using span tags and CSS classes to put headings in


    Figure: Good example - using heading styles

  9. Do you chose efficient anchor names?

    These are the things you should consider when creating an anchor link:

    1. Meaningful - When you use named anchors in a web page, use meaningful names. When you are sending the URL by email it helps indicate what you are talking about, and in addition, list numbers often change. An anchor like "#13" becomes incorrect when the order changes.
    2. Case sensitive - Are "" and "" the same? The answer is "no" because they might be not case sensitive when they test in some browsers.
    3. No spacing - When you are defining an anchor name, make sure there are no spaces within the name.

    Bad: <a name="Some Anchor Name">

    Good: <a name="SomeAnchorName">

    1. Don't start with a # - When you are defining an anchor name you DO NOT use a #. When you are referencing an anchor you DO use a #. This is a common mistake because the # is used on the "href".

    Bad: <a name="#SomeAnchorName">

    Good: <a name="SomeAnchorName">

    We have a program called SSW Code Auditor to check for #3 and #4 on this rule.

  10. Google is by a country mile the most popular search engine in the world. It's popular because it seems to rank pages so accurately and quickly time and time again. The secret to its success is its top secret PageRank Algorithm. Google developed its page ranking system in an effort to increase the quality of search results and has left all of its competitors for dead. As a result search engine optimization (SEO) gurus are always looking to find new ways to increase their Google rankings.

    As we all know, a website is a pretty nifty thing to have for a myriad of different reasons. But the truth is that it's worth is derived from the people that surf it, and if no one is surfing it, then it becomes useless. So who's the biggest website referrer? The answer is Google in almost every case.

    So design your website with this in mind. In the eyes of a search engines, there are good and bad ways that you can design your website. Here's a list of suggestions to improve your Google ranking and other search engine optimization tips

  11. Google Analytics gives you a great insight into how, when and where your website is used. If you're not using an analytics package in your website, you're flying blind when it comes to understanding how, when and where your website is used.

    By using Google Analytics, you will be able to see what your visitors are viewing and what they aren't, what they spend large amount's of time on, what pages are causing errors, what pages are directing visitors to you, which browsers and devices are being used to see you site and more. All this information help you better structure your site to what your visitors like. It also allows you to compare site traffic from one month to another.

    The most useful reports:

    • Which are your most popular pages of your website
    • Which sites are referring the most hits to you
    • Which keywords are bringing users to your site
    • If you have downloads, which are the most popular

    To add Google Analytics to your website:

    1. Log into your Google account,
    2. Go to Admin ,
    3. Ensure both Account and Property
    4. Specify your website details,
    5. Find your Tracking Code,
    6. And add the script to your website

    ![Figure: Navigate to the Tracking Code property](20-08-2014-3-25-06-PM-compressor (1).png)

    From this page, you will be able to get a JavaScript snippet to include in your application.

    20 08 2014 3 30 55 PM compressor
    Figure: Include this JavaScript in your web application

    20 08 2014 10 53 15 AM compressor
    Figure: The JavaScript code in HTML

    Once deployed, this script will start tracking metrics and interacting with Google Analytics.

    You are good to go!

  12. Do you make your site easy to maintain?

    If you have database driven pages on your website, you need a way of updating the data quickly and easily. Each page should have an 'Edit' link - only visible when the site is running internally or in administrator mode - that takes you directly to the page for editing the content on that page. The exception to this is if you are using open-source data. SSW.People is a good example of this.

    Figure: "New" and "Edit" links allow SSW Employees to maintain testimonial entries easily

    wordpress edit
    Figure: "Edit" button on WordPress admin bar

    github edit
    Figure: Good Example - "Edit" button on an Open Source page

    From Github, you can edit and submit a pull request. See (SSW People) or (SSW Rules) for more details.

    This is better than sending a 'Change from X to Y' email ( as the work can be done immediately with less work and management requirements.

    Do you use Markdown to store your content?

  13. Error page, you say? You worked hard to make sure my site has no errors!! Well, surfers don't always type URLs accurately. No website is immune to such errors.

    A well-designed custom error page encourages surfers to remain in your site and help them to the right page. Although it's possible to redirect error codes straight to your homepage, that doesn't tell visitors what's going on. It's more user-friendly to explain that there was a problem and provide some alternatives. Supply a link to your home page or other links, or offer your site's search function if you have one.

    <customErrors mode="Off"></customErrors>

    Figure: This is the default code on web.config

    <customErrors mode="RemoteOnly" defaultRedirect="/ssw/ErrorPage.aspx">
    <error statusCode="404" redirect="/ssw/SSWCustomError404.aspx">

    Figure: this is the current code in the web.config of the SSW Site

    For ASP.NET website, the detailed information would be presented to the remote machines when an unhandled error occurs if the customErrors mode is off.

    This error information is useful for the developer to do debugging. However, it would leak out some confidential information which could be used to get into your system by the hackers. We can assume that if a SQL exception occurs by accident, which may expose database sensitive information (e.g. connection string; SQL script). So, to prevent these leaks, you should set the "mode" attribute of the tag <customerrors> to "RemoteOnly" or "On" in the web.config file and create a user-friendly customized error page to replace the detailed error information.

    <customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm"></customErrors>

    Figure: Turning on "customErrors" protects sensitive information against Hacker

    404 bad
    Figure: Bad example - Unhandled error

    404 good
    Figure: Good example - Custom error page

  14. Do you avoid changing the URL on a 404 error?

    When you request a URL of a file that doesn't exist, you will get an error message. You should make sure that the URL in the browser doesn't change. This way, it's easy for the user to correct.E.g. The user doesn't have to retype the whole URL if there is a spelling mistake or a forgotten/mixed up letter

    In .NET you are allowed to define a custom error page. When a user tries to access a URL which doesn't exist, .NET changes the URL and redirects to the custom error page. The original URL is passed as a parameter to the new URL.

    The advantage of this solution is, that the page looks nice and you can customize it according to the design and layout of your whole site.

    The disadvantage is, that .NET changes the URL. So if the user wants to correct the URL he entered, for example, because he just mixed up a letter, then this means quite a lot of work for him. He has to retype the whole URL or at least copy and paste the parameter out of the new URL. This is very uncomfortable for the user.

    Figure: Bad example - URL changes

    Our solution is to show the customized error page while not change the original URL. So if the user wants to do any corrections, e.g. a mixed up letter, he can do that by just editing the URL in the address bar.The advantages of this solution are, that the site looks nice and matches the design of the whole site and that the user can easily change the original URL he typed.

    You can try any page name that doesn't exist like xxx.asp on the URL and it will open our 404 error page. The original URL is not changed in the address bar. It should look like this:

    404 good
    Figure: Good example - Customized 404 error page without change the URL

    In order to show the customized error page while not change the original URL, you can use Server.Transfer() to keep the original URL.


    **Figure: Custom error page handler in Global.asax **

  15. ASP.NET injects many lines during page rendering, so if you are using inline JavaScript, the line numbers will change during client side JavaScript debugging in VS.NET, FireBug or IE8 developer Tools.

    Figure: Bad Code - Using Inline JavaScript

    Figure: Bad Code - On PostBack Line numbers are changed for Inline JavaScript

    Figure: Good Code - Using JavaScript on Separate file

    So you should always put JavaScript in a separate file. Then the line numbers will stay consistent during debugging.Keeping JavaScript in a separate file is also good for production as it improves performance due to browser caching.

    Note: During development, remember to hit CTRL-F5 to force the browser to re-fetch the files from the server or you may be debugging old version of the JavaScript file.

  16. Do you always use query strings?

    When you build a web application, any dynamic page you think a user may wish to bookmark directly should be controlled through query string values rather than form values. In other words, search mechanisms should use the HTTP GET Request and Querystring values, rather than a POST with Form values. This allows:

    • Bookmarking of the pages
    • Gives the user to the ability to change the query string values in the address bar, rather than having to go back to the input form.

    Figure: The URL should always have all the parameters the user enters. Here Google is a good example

    You may hear that query strings are bad and they leave you wide open to SQL Injection Attacks (especially when you use SQL statements in the URL). I don't subscribe to the security issues being the determining factor... if I am determined enough, I can write a little application to send POST data to the webpage instead of in the query string. Both methods are open to SQL injection and invalid parameters, so you need to code to prevent that either way.

    The bottom line is that if you are not giving appropriate parameters in the query string then you are reducing functionality.

    Note: We all agree bookmarks are useful - it's the same for query strings.

  17. **Rule 1: ** Whenever you have a data entry page you should always use the html maxlength attribute to limit number of characters to the length of the field in the table (except for numbers).

    Rule 2:  Whenever you have a situation where you are using the HTML textarea (does not have the maxlength property)

    Then you need to:

    • add the JavaScript function eg. ValidateLength(control)
    • add 2 properties to every data control  eg. dataType="char" onkeyup="validateLength(this)"
  18. When you are deploying an ASP.NET project (no matter it's a Web site or a Web application), do not copy all files of this project to the production server because source code will be deployed during this simple copy and it makes easier for others to access or tamper the source code of your site.

    Instead, please use 'Publish' utility to deploy your Web site or Web application. This utility can remove the source code from the site.

    1. Web Site Project

    Publish Web Site dialog box is designed to precompile and deploy your Web site to a new location (whatever it is, ftp://, http:// or drive:\path). During the deployment, source code are removed automatically. Besides, the precompilation process finds any compilation errors and identifies the errors in the configuration file.

    To access this dialog box, please open a Web site that you want to deploy and click Build menu, then click Publish Web Site .

    Figure: How to open Publish Web Site dialog box

    Figure: Publish Web Site dialog box

    See more about Publishing Web Sites.

    2. Web Application Project

    The Publish Web dialog box enables you to build and publish a Web application project to a new location. Like Publish Web Site dialog box, this utility can remove source code. However you have to select Only files needed to run this application to specify it. Other benefit of this utility is that potential errors and compile-time errors in the Web.config file and in other non-code files can be found.

    To access this dialog box, open a Web application project that you want to publish and click Publish ApplicationName on the Build menu.

    Figure: How to open Publish Web dialog ('WebApp' is the name of this application)

    Figure: Publish Web dialog box

    See more about How to Publish Web Applications.

  19. Do you avoid using UNCs in HREFs?

    Initially, errors of this nature would be picked up in the link checking utility. However, that is not the case because the link checker will not report any problems if you run it locally - which is the normal method. The reason it won't see the problems is because the link checking utility does not check hard coded links to local servers (e.g. localserver/ssw/Default.aspx). Therefore, it is testing a page that will exist internally, but the page will not exist when uploaded to the web (e.g.

    &lt;a href="//ant/ssw/LookOut.htm"&gt;

    Bad Example

    &lt;a href="/ssw/LookOut.htm"&gt;

    Good Example

  20. Do you check if your website is running?

    If you want to know your website is working or not, you need to add a ping check to the machine also an HTTP Content Scan to the website in WhatsUp. We use WhatsUp to do real-time monitoring.Follow these steps to check your website in WhatsUp:

    1. Add your website as a new device.
      Figure: New device
    2. Ping monitor is added automatically.
      Figure: Ping monitor
    3. Add an HTTP Content Scan monitor.
      Figure: HTTP Content Scan
    4. Edit the scan script. In the script, you can see 2 keywords "Send" and "Expect". "Send" expression is an HTTP request to your website. "Expect" expression is a regular expression to check the key word in response from your website.

    Figure: Edit scan script

    1. Add the monitor to your device.
      Figure: Add monitor

      Once a device is down or up, a WhatsUp action will tell SQL Reporting Services to send out a notification report. Our report looks like this:
      Figure: Website doesn't work

    Figure: Website works

  21. Do you have a PWA (Progressive Web App)?

    Progressive Web Apps have transformed the mobile web practices to provide a native app like experiences for the users. They work just like native apps and include features such as smoother navigations, offline modes and push notifications, but are much more economical and do not use the device storage.

    Progressive Web Apps are reliable which means they load instantly and the performance isn't compromised even if the network is shaky.

    On the mobile the 'Add to homescreen' option can be used to create an icon on you phone.

    PWAs also account for higher user engagements and conversions which is probably why many organizations are now adapting this technology to grow their businesses.

    In order to be a PWA, your app should:

    • Use a responsive design , so it works on desktop or mobile.
    • Be fast , using a service worker to precache the app resources (HTML, CSS, JavaScript, images) needed to run, and cache the data at runtime to improve performance.
    • Be installable , using a web app manifest and the beforeinstallprompt event to notify the user that it is installable.

    Examples of Progressive Web Apps can be seen at

    pwa bad example
    Figure: Bad Example - aliexpress get a mark of 6/12 (see tooltip) and cannot be used as a PWA

    pwa example
    Figure: Accessing a PWA on your mobile will prompt adding it on your Home screen. E.g.

    You can check the Progressive Web App score of your application using Chrome's Developer tools.

    Note: See how to generate a PWA report on

    PWA tools
    Figure: Good Example - Aim for a good Progressive Web App score

  22. If you are dealing with Content Management System (CMS), you are likely to play with pages with large amount of images and embedded videos. To improve the performance of those pages, and save bandwidth for the readers, loading content asynchronously (also called “lazy loading”) is recommended.

    It means the browsers will only load images and embedded videos in the visible area by default, then load the rest images and videos while users are scrolling down to them.

    On our rules web site, one of the pages’ initial loading size of images reduced from 4.8MB to 500KB after being applied “lazy loading” of images:

    load images 1
    Figure: Bad Example - load all images by default

    load images 2
    Figure: Good Example - Do not load all images by default, only load them when they are visible while scrolling down the browsers

    The page's initial loading size of JS scripts reduced from 2.3MB to 518KB after being applied “lazy loading” of embedded YouTube videos:

    load images 3
    Figure: Bad Example – load all embedded YouTube videos by default

    load images 4
    Figure: Good Example - Do not load all embedded YouTube videos by default, only load them when they are visible while scrolling down the browsers

    To implement lazy loading for image:

    1. Check if the browser supports IntersectionObserver, if the browser supports IntersectionObserver, we will only load images and videos in the areas are visible to users by default. If the browser doesn’t support it, we will have to load all images and embedded videos on the page immediately after the page is loaded.
    if (!('IntersectionObserver' in window)) {
        console.log("No Intersection");
    } else {
                   console.log("Support intersection");

    Note: You can use a polyfill library to add IntersectionObserver support to older browsers.

    1. If the browser supports IntersectionObserver, in your page html, change the “src” of “<img>” to “data-src” From
    <img alt="flight.jpg" 


    <img alt="flight.jpg" 
    1. Use the below Javascript to change “data-src” back to “src” for the <img> html objects, which become visible, so that those images will be loaded
    function onIntersection(entries) {
      // Loop through the entries
      entries.forEach(entry => {
        // Are we in viewport?
        if (entry.intersectionRatio > 0) {
          // Stop watching and load the image
    function preloadImage(target){
    if (target.getAttribute('data-src')) {
                target.setAttribute('src', target.getAttribute('data-src'));
    // Get images of class lazy
    const images = document.querySelectorAll('.sswRuleSummaryUCDiv img');
    const config = {
      // If image gets within 50px go get it
      rootMargin: '50px 0px',
      threshold: 0.01
    let observer = new IntersectionObserver(onIntersection, config);
      images.forEach(image => {
    1. More details can be found at

    To implement lazy loading for embedded YouTube videos:

    1. Use the same code as lazy loading images above, to check if IntersectionObserver is supported by browsers.
    2. In your page html code, convert “<iframe>” to “<div>” (width, height, src has been converted too):


    <iframe width="853" height="480" src="" frameborder="0"></iframe>


    <!-- (1) video wrapper in div instead of iframe -->
    <div data-iframewidth="853" data-iframeheight="480" data-iframecode="OhVYTOKCsWI" data-iframesrc="" frameborder="0">
        <!-- (2) the "play" button -->
        <div class="play-button"></div>      
    1. Use the below code to convert “<div>” to “<iframe>” to load the embedded videos when they are visible while scrolling down:
    var youtube = document.querySelectorAll( "div[data-iframesrc]" );
              for (var i = 0; i < youtube.length; i++) {
            var source = ""+ youtube[i].dataset.iframecode +"/sddefault.jpg";
            var image = new Image();
                    image.src = source;
                    image.addEventListener( "load", function() {
                        youtube[ i ].appendChild( image );
                    }( i ) );
                    youtube[i].addEventListener( "click", function() {
                        var iframe = document.createElement( "iframe" );
                                iframe.setAttribute( "frameborder", "0" );
                                iframe.setAttribute( "allowfullscreen", "" );
                                iframe.setAttribute( "width", this.dataset.iframewidth );
                                iframe.setAttribute( "height", this.dataset.iframeheight );
                                iframe.setAttribute( "src", this.dataset.iframesrc +"?rel=0&showinfo=0&autoplay=1" );
                                this.innerHTML = "";
                                this.appendChild( iframe );
                    } );    
    1. More details can be found at
  23. Do you know not to use LinkButton?

    If we want to refresh and data bind the same page from client side, we can use the javascript function calls "__doPostBack". We shouldn't fire this post back in LinkButton. Otherwise, there will be an error.

    Figure: Right click the link with __doPostBack event

    Figure: New window with incorrect URL

    <asp:Panel runat="server" ID="mUpdatePanel" OnLoad="mUpdatePanel_Load">
     <asp:Label runat="server" ID="lblTime" />
     <br />
     <asp:GridView ID="gvList" runat="server" AutoGenerateColumns="false">
     <asp:BoundField DataField="ID" HeaderText="ID" />
     <asp:BoundField DataField="Name" HeaderText="Name" />
     <br />
     ID:<asp:TextBox ID="txtID" runat="server"/>
     Name:<asp:TextBox ID="txtName" runat="server"/>
    protected void mUpdatePanel_Load(object sender, EventArgs e)
     lblTime.Text = DateTime.Now.ToLongTimeString();
     ArrayList mList = (ArrayList)ViewState["List"];
     if (txtName.Text.Length > 0)
     Client mClient = new Client();
     mClient.ID = Int32.Parse(txtID.Text);
     mClient.Name = txtName.Text;
     ViewState["List"] = mList;
     gvList.DataSource = mList;

    Sample Code

    <a href="javascript:__doPostBack('mUpdatePanel','');">Refresh</a>

    Bad Code

    <input type="button" onclick="javascript:__doPostBack('mUpdatePanel','');" value="Refresh" />

    Good Code

    We have a program called SSW Code Auditor to check for this rule.

  24. Do you know why you choose .NET Core?

    Cross platform

    .NET Core works on multiple platforms like MacOS, Linux and Windows. So developers can code on their operating system of choice using Visual Studio, Visual Studio for Mac or Visual Studio Code, working on the same code base as developers on a different operating system, and best of all they can also deploy to Linux.


    .NET Core is fast, and you get that performance out of the box.

    dotnet core performance
    Figure: ASP.NET Core easily trounces ASP.NET 4 in number of requests per second (view source)

  25. In a database-driven page, it is important that the name of the page is based on the data that the page contains. For example, if a page shows client details and is based on the Client table, then the page should be called Client.aspx.Other examples are:

  26. Do you provide modern contact options?

    The evolution of website development can be divided by:

    * 1990 - Cool website – content focus (static HTML content)
    * 1995 - Cool graphics – interface focus (dynamic HTML content)
    * 2000 - Nice flow – usability focus (focus on user experience)
    * 2005 - Good marketing – conversion focus (SEO and visitors to customers conversion)
    * 2010 - Happy customer– interactions focus (customer experience)

    It's important that your website is focused on CX (Customer Experience) which means you need modern contact options.

    moderncontact bad
    Figure: Bad example: the only way to contact the company is via email

    moderncontact good
    Figure: Good example - Chat is available along with other ways of contact, such as voip, IM, KB etc

    Zendesk explain how you can use mulitple channels of support to give your customers a better CX.

  27. The debug attribute in the web.config file is very useful for ASP.NET developers. When an error occurs the developer gets detailed error report containing the stack trace, line number and what the error is.

    But when debug attribute in the Web.config file is set to true it generates symbolic information (.pdb file) every time the compiler compiles your views as well as disables code optimization. So, it slows down the execution of every page.

    So if you are a developer remember to remove the debug attribute and instead use custom error messages for your web pages

    We have a program called SSW Code Auditor to check for this rule.

  28. Do you run load tests on your website?

    Once you have a website up and running, it is important to make sure that it keeps running under load. Local testing of the website will not always reveal the latent problems in the website when it is subjected to thousands of users. Typical issues that result from inadequate load testing are:

    • 503 Service Is Temporarily Unavailable
    • Very slow load times
    • Application Crashes due to:

      • Insufficient resources - so application pools are recycled
      • Too many concurrent users causing race conditions
      • Too many users trying to connect to the database

    Load Tests help you avoid these issues by prompting them before you go live. Some issues might be resolved by getting a better web server, while others might require code changes and optimizations.

    In Visual Studio 2005 - Software Testers Edition , there is a built-in Test Project to conduct load testing.

    1. From the Test menu select New Test
    2. Select Web Test and Create a new Test Project

    1. Name the Test Project <Namespace>.WebUI.Tests
    2. An Internet Explorer window will open with a recorder toolbar. Navigate to the web pages that need to be Load Tested

    1. Click Stop when you are finished recording the pages to be tested
    2. Click the Run button to make sure the tests run

    1. Add a new Load Test

    1. Follow the Load Test Wizard:

      • Load Pattern - Define the number of users hitting the site
      • Test Mix - Select the web test you recorded earlier
      • Browser Mix - Specify different types of browsers (leave as default)
      • Network Mix - Specify connection speeds of users (leave as default)
    2. Click Finish
    3. Click Run to run the load test

    1. This will kick off the load test and show a live graph of user load, requests per second and response time
  29. CSS Validation Service allows you to check your webpage against the W3C recommendations. When developing web pages you want to create a clean and valid web page. It makes it easier for someone else to read and add new parts to a web page. Every web language like CSS has its own Syntax it must follow in order to produce a clean and valid web page, CSS Validation Service allows you to achieve that goal.

    Go to CSS Validation Service:

    1. Enter the URL or ppload file or by Direct Input to check
    2. Review the results and make changes to fix errors
  30. Sending email from your application is easy, most programming languages allow you to send an email. Formatting and getting proper feedback and data on your emails is a bit more complicated.

    Enterprise software generally need to send emails for a range of reasons e.g. inviting users, multifactor authentication, registering users, marketing campaigns, so it is important to know the best ways to send an email.

    1. Built-In Email commands

    Generally, programming languages have a built-in way to send email e.g. PowerShell with Send-MailMessage and System.Net.Mail in .Net, and those commands generally use an SMTP server (external or internal).If you need a quick and dirty email, this is a good way.

    1. Microsoft Graph API - Microsoft Recommended

    Microsoft's recommended way of sending mail is through the Graph API. This is much more secure than just using any built-in commands and the command itself to send it is not much more complicated.You can check here how to send email through the Graph API -

    1. Sendgrid - Recommended if you need a lot of features

    Another way to send email is to use a third-party solution e.g. Sendgrid that gives you many more features over the normal email-sending mechanisms above e.g:

    • Integrated API
    • Click tracking
    • Spam management
  31. Do you use jQuery instead of JavaScript?

    jQuery is the MUST HAVE tool for web developers. There are 3 good reasons why you should use jQuery.

    1. Cross Browsers (IE 6.0+, Firefox 2+, Safari 3.0+, Opera 9.0+, Chrome)
    2. Powerful and easy to use

      • Same selectos as CSS
      • Designer can learn it fast
      • More readable JavaScript code
    3. Plug-ins - Tons of useful plug-ins and functionalities
    window.onload = function() { alert("Welcome"); }

    Figure: Bad Example - Using JavaScript 'onload' event

    $(document).ready(function() { alert("Welcome!"); });

    Figure: Good Example - using jQuery document 'ready' event

  32. Many developers work with sites that have grown large over time and have consequently become difficult to maintain. They fix problems as customer report bugs. A better approach is to use SSW Link Auditor, a tool that will analyze your whole site and report bad links and many other problems. 

  33. Do you use Markdown to store your content?

    You want users to easily edit content, so you put an "edit" button on the page. From there, you can choose between the power of HTML or the limitations of Markdown.

    edit button
    Figure: "Edit" button to encourage users updating the content

    HTML is frightening for most users, as one wrong tag or an inline styling can break the whole page view.

    Markdown is simpler and encourages more editing without breaking the page.

    The original spec for Markdown can be found at Although, it does not specify the syntax unambiguously – so there are different flavours of the spec available. Some popular ones include:

    The Markdown Cheatsheet is a great page to reference when learning Markdown.

    Depending on the markdown parser you choose, there are many plugins that allow you to extend it. SugarLearning and SSW.People provide more extensive cheatsheets which include a number of custom templates and plugins:



    Watch the video "Markdown - How to use it, What is it and Why Use it | Ask a Dev":

    Watch the video where Thiago explains the benefits of using Markdown:

    Don't store content as HTML - It's a trap

    Rich HTML Editors make your life easier at the beginning and produce content that looks nice and clean, but behind the scenes, it generates HTML which can get out of control quickly especially if you need to edit the source code (E.g. include a special style). It becomes incredibly difficult to maintain over time.

    Some examples of rich HTML editors that you can embed in your web applications:

    Note: None of these are recommended because of the HTML that is generated.

    HTML bad
    Figure: Bad example - HTML generated by a rich editor gets harder to maintain over time

    Store content in Markdown

    Content is typically either stored in files (eg. git) or a database. When stored in files, it is common to use a static site generator with a JAMStack approach. (eg. Gatsby, Vuepress, Hexo, etc) That is, you commit content into git and a CI/CD pipeline is executed. The resulting files (HTML and CSS) are then served from storage which is cheaper and typically more scalable than compute resources in the cloud. In this case, the workflow will be a development style workflow (commit to git, push, etc) and the editor will be the one you choose. (e.g. GitHub editor or VS Code) These editors are not likely to produce a rich editing experience, nor do they need to.

    For a non-technical audience, it helps to store your content as markdown in a database and convert to HTML on the fly. This removes the code repository/CI/CD pipelines and can feel more natural for a non-developer audience. In this case, you will provide an editor and it is recommended that this be a rich editor.

    Markdown rich editors

    The Markdown rich editors are not as good as the HTML ones, but at least the content they produce is maintainable over time.

    Some example of rich Markdown editors are:

    markdown good
    Figure: Good example - Markdown looks clean

    Markdown can have rich content too

    Markdown is simple and limited, but you can make it richer.

    One way is to use inline HTML, this allows you to use HTML tags that you are familiar with (only if you need to) and embed things like YouTube videos or JavaScript.

    use html in markdown
    Figure: OK Example – you can use raw HTML in your Markdown, and mostly it will work pretty well. But you can’t use Markdown’s syntactic sugar in the HTML

    The other way is to use templates or containers:

    danger html and markdown
    Figure: Bad Example – The danger of using HTML in your Markdown files is that you add too much formatting e.g. use Bootstrap classes that create a tight coupling between the content and the presentation

    A better way is to use a plugin (if your Markdown engine supports it).

    vuepress custom container
    Figure: Good Example – VuePress has a custom container that generates nice alert boxes like Bootstrap but without tying the presentation to the CSS framework in the content

    Unfortunately, Markdown does not support YouTube videos embedding out of the box. However, there is a workaround to embed it.

    [![What is SSW TV](](

    Figure: Good Example - Workaround to embed YouTube video using YouTube's generated thumbnail

    If your site is using "markdown-it" parser, you can also install "markdown-it-video" to allow YouTube videos directly embedded into the page, rather than providing just an image and a link.


    Figure: Better Example - YouTube video embedding using a plugin

    Markdown to HTML rendering processes

    markdown rendering
    Figure: The markdown rendered either Client-side or Server-side

  34. You should have a syntax highlighter to show pieces of code on your pages for a better readability.


    See this json file for all supported languages and their aliases we can use in SSW Rules.

    let iceCream = 'chocolate';
    if(iceCream === 'chocolate') {
      alert('Yay, I love chocolate ice cream!');    
    } else {
      alert('Awwww, but chocolate is my favorite...');    

    Figure: Bad Example - No syntax highlighting

    let iceCream = 'chocolate';
    if(iceCream === 'chocolate') {
      alert('Yay, I love chocolate ice cream!');    
    } else {
      alert('Awwww, but chocolate is my favorite...');    

    Figure: This JavaScript code block shows its syntax highlighted

    SSW CodeAuditor enforces this rule

    When the CodeAuditor box is ready, update the greybox above.

  35. Markup Validation Service allows you to check your web page against the W3C recommendations. When developing web pages you want to create a clean and valid web page. It makes it easier for someone else to read and add new parts to a web page. Every web language like HTML has its own syntax it must follow in order to produce a clean and valid web page, Markup Validation Service allows you to achieve that goal.

    Go to Markup Validation Service:

    1. Enter the URL or upload file to check
    2. Review the results and make changes to fix errors
  36. Open Graph is a metadata tag that allows you to control what content shows up when a page is shared on social media networks.

    It should be placed on the <head> section of your page. The most used properties are:

    <meta property="og:title" content="Your Custom Title" />
    <meta property="og:description" content="Your custom description of the page." />
    <meta property="og:image" content="https://www.YourCustomImage.jpg"/>

    open graph bad
    Figure: Bad example - Shared link has no image and the title was "guessed" by LinkedIn

    opengraph good
    Figure: Good example - Shared link has a nice image and title, both defined via Open Graph tags

    Note: For LinkedIn you might need to add the prefix as following:

    <metaprefix="og:" property='og:title' content="Microsoft Azure | SSW Consulting - Sydney, Brisbane, Melbourne"/>

    More information and other properties can be found at The Open Graph protocol.

  37. Do you use server side comments?

    Use server side comments:

    • Use <%-- Comment Here --%> instead of <!-- Comment Here --> (Does not get rendered to the client, saves us a few precious kilobytes)
    • Use CTRL + K, C to comment and CTRL + K, U to uncomment
  38. Do you use the best static site tech stack?

    Pure HTML pages are the fastest website around. However, server-side scripting languages enable richer functionality. Static sites solve this problem by providing the best of both worlds. Static sites are

    • Cheap
    • Easy to use
    • Fast

    On the other hand, complex functionality can be a bit more limited and time consuming to implement.

    Here are some popular static site generators:

    NameGatsby (Recommended)Next.jsScullyGridsomeStatiqJekyll
    Data HandlingGraphQLFully customisableFully customisableGraphQLFully customisableSource code data files
    Data SourcesFilesystems, CMS, APIs, Databases, Local filesFully customisableFully customisableSource Plugins, APIs, Local filesFully customisableLocal files
    GitHub Pages IntegrationSeamless deployment via config filesRequires setupDeployment via GitHub ActionsSeamless deployment via config filesDeployment via GitHub ActionsWorks out of the box
    Netlify CMS integration

    ssgs Figure: Google trends for the above SSGs. In a substantial lead is Gatsby, followed by Jekyll. The others are much lower, and Statiq is excluded as it has very low search numbers.

    Two examples of static sites in action are SSW People and SSW Rules.

    There are a few hosting options to choose from including:

  39. You don’t want to build solutions from scratch, so take what business value you can from a CMS: don't reinvent the wheel.

    A CMS allows business users to build and manage websites without having to write any code.

    Top 6 CMS vendors of 2021 by Market Share (including eCommerce and websites)

    These CMS platforms work really nicely for simple scenarios. If they fit your business case then use them.

    • WordPress
    • Joomla
    • Drupal
    • Shopify
    • Squarespace
    • Wix


    Top 5 CMS vendors for Enterprise websites (.NET based)

    When you have a complex business case, you need something more customizable. That's where enterprise CMSs come into play.

    • SiteCore ($$ - approx $50k per year - pricing non-transparent)
    • Kentico Xperience (Formerly Kentico EMS) ($$ - approx $20k per year per website -
    • Sitefinity ($$ - approx $40k per year - pricing non-transparent)
    • Umbraco (Open source) ($ -
    • DotNetNuke - DNN (Open source) (pricing non-transparent)

    Source: Top 5 .NET Based CMS Platforms For Your Business

    Figure: Google trends of the above .NET CMSs. The leading (but most expensive) is SiteCore, and in second is Umbraco (which is much cheaper)

    View current trend information for these products.

    Top 5 Headless CMS of 2021

    Source: 12 Best Headless CMS For 2021

    Figure: Google trends of the above Headless CMSs. The leading is the open-source Strapi, which is inexpensive, but not as feature rich as Contentful (second) and Kontent (third)

    View current trend information for these products.

    Headless CMS vs Traditional CMS

    Source: Traditional CMS vs Headless CMS

    A Traditional CMS is a monolith, which means it has both a front-end and back-end. It uses server side technology like PHP (Wordpress, Joomla, Magento) or ASP.Net (DNN, Umbraco, Sitefinity) and a single database. All pages are served by one or many backend servers.

    A Headless CMS deals strictly with the content. Created content is accessed via Application Programming Interfaces (APIs), which gives you full flexibility on how you build the front-end for your website. Headless CMSs are also very appropriate for JAMstack sites: see the State of Jamstack 2021 Report by Kentico for more information.

    For example, you can use a Headless CMS with a super fast Static Site Generator (SSG): see the rule on the best static site tech.

    Traditional CMSs like Sitecore and Kentico Xperience have their place, especially if you have no developers and you’re comfortable with serious vendor lock-in. Headless CMSs and static sites for the win. -Adam Cogan

    Here is a breakdown of Traditional CMS architecture vs Headless CMS architecture:

    cms architecture traditional
    Figure: Traditional CMS Architecture

    cms architecture headless
    Figure: Headless CMS Architecture

    ✅ Traditional CMS - Pros

    • Simple and fast - for setup and maintenance
    • Less reliance on developers - You won't be as reliant on developers to make changes, and may be able to forgo them completely for small-medium projects. More complex CMSs will require developer involvement but non-developers still have some customisation control.
    • Simple to control look and feel - using available themes and templates
    • Large community support
    • Out of the box integrations - payments, social media, etc.

    ❌ Traditional CMS - Cons

    • Performance is not amazing - the frontend is coupled with the backend.
    • Does not scale very well - all pages render server side, so you will need more servers if you have lots of traffic.
    • Locked-in - content is only available on browsers and not on native mobile apps.
    • Limited flexibility - you are limited to themes and templates, e.g. if you want to build a multi-step form.
    • You need developers with particular CMS skills - If you have a big website or are using complicated CMS features, you will need CMS developers - e.g. for SiteCore or Sitefinity.
    • It is not an API first solution

    ✅ Headless CMS - Pros

    • Super fast - fast initial load time when using Static Site Generator (SSG).
    • Scales very well - when using Static Site Generator, and the frontend can be cached via CDN.
    • Ultimate flexibility with how to use content - can use a Single Page Application (SPA), Static Site Generator (SSG) or even native mobile apps. Not restricted by themes, templates or vendor, and you can have multiple frontends with 1 headless CMS backend.
    • Many options to build frontend - NextJs, HUGO. Gatsby, React, Angular, etc. This makes it easier and cheaper to find developers.
    • Easy publishing - The same content can be published to different platforms at the same time (website, web app, native mobile app).

    ❌ Headless CMS - Cons

    • Very reliant on frontend developers - Anything beyond basic content changes will require frontend dev involvement.
    • Greater overhead - to maintain the code base, DevOps, etc.
    • Limited preview functionality - Kontent provides in-context editing via Spotlight, however most Headless CMSs do not. Netlify CMS can help in this case.

    Hybrid CMS

    Some CMSs (e.g. Optimizely offer a hybrid approach including both headless integration and a fully featured UI. As such, you can get the best of both worlds by going down this route. However, pursuing this option comes at a premium with prices matching or exceeding traditional CMSs. An entry level figure for Hybrid CMSs is approximately $50,000 but this figure can quickly increase to several hundred thousand $ as you include add-ons and other features.

    Headless CMS Comparison: Kontent vs Contentful

    Let's compare two popular CMSs.


    Content Modelling - the ability to model your website components, and see how they are used in your website.

    Collections - allows you to manage content dependent on your business and geographical structure. This eliminates the use of silos, which make it more difficult to manage your data.

    Website optimisation - See the Kontent's useful docs on this topic.

    NameKontent (Recommended) - Video (3 mins)Contentful - Video (1 min)
    In-Context EditingInfo
    Personalized Experiences✅ via Uniform✅ via Uniform
    SSO and MFA
    GraphQL SupportSoon: October 2021
    Content Modelling
    Unlimited Content Types
    Content Collaboration✅ + Simultaneous Editing
    Task ManagementInfo + better functionalityInfo
    Website Optimisation
    Roadmap TransparencyBetter: feature release roadmapGood: Info
    Australian Compliance✅ stored in an Australian Azure Data Center❌ stored in a United States AWS Data Center
    Dev/Staging/Prod Data MigrationProd only by default - Add migration script and pipelineProd only by default - Add migration script and pipeline
    Email CampaignsUse 3rd party best of breed tool e.g. MailChimpUse 3rd party best of breed tool e.g. MailChimp
    User Tracking e.g. Leads, funnelsExternal CRM e.g. Salesforce Pardot, Dynamics 365 MarketingExternal CRM e.g. Salesforce Pardot, Dynamics 365 Marketing
    StatisticsExternal Analytics e.g. Google AnalyticsExternal Analytics e.g. Google Analytics
    Developer Friendly
    PricingPremium: $30,000 pa (cheaper with scaling)Team: $24,000 pa (with Compose + Launch)

    Assuming you want enterprise features, Kontent is preferred as the Headless CMS of choice over Contentful.

    Source: Kentico Kontent vs. Contentful

    Dead CMSs

    • Microsoft SharePoint for public sites
  40. Do you use Web Compiler extension?

    You can use Visual Studio's Web Compiler extension to create a bundle.css and test if CSS was compiled successfully.

    More information and download at Visual Studio Marketplace.

    web compiler find error
    Figure: Web Compiler can find missing curly braces

    Unfortunately different kinds of errors, like are not caught.

    web compiler didnt find error
    Figure: Curly braces in the wrong place, but still compiled successfully

    In addition, Gulp is wrongly successful too:

    gulp didnt find error
    Figure: Gulp couldn't find the curly braces error

  41. Npm packages often get new releases (adding new functionalities, fixing bugs or vulnerabilities). It is important to keep the packages updated as much as possible during the development of your application. The best way to do that is to update all the packages every time you add a new package to your application, and include the npm outdated and npm audit reports in the Sprint Review. These commands are also available with yarn with yarn outdated and yarn audit.

    npm outdated returns an overview of your packages: the version, the wanted version (the maximum version of the package that satisfies the semver range specified in package.json) and the latest version of the package.

    npm outdated
    Figure: Use 'npm outdated'

    • Red indicates the package version is below the wanted version.
    • Yellow indicates the package version is at the wanted version but below the latest version.

    npm audit returns an audit on your packages for vulnerabilities. It also provides information on how to resolve them.

    npm audit
    Figure: Use 'npm audit' to discover vulnerabilities in your application

    To add a new package, use npm install package-name or yarn add package-name.

    To update your packages, use npm update package-name or yarn upgrade package-name. Yarn also has a useful tool called yarn upgrade-interactive that allows you to see which packages are outdated, and upgrade them all at once.

    upgrade interactive
    Figure: Using yarn upgrade-interactive

    Note: Use yarn upgrade-interactive --latest to see outdated packages with breaking changes.

  42. A migration from one technology to another is a process fraught with danger. Everyone would love the "upgrade" button to work perfectly but it doesn't. Expect any migration to fail first go. Any statement that "I didn't expect to have any problems" shows inexcusable optimism.

    A plan for a migration will typically include:

    1. Business purpose for migration
    2. Test migration
    3. User Acceptance Testing of the test migration
    4. Rollback procedure
    5. Decommissioning procedure

    Approved plans are mandatory for a migrations such as:

    1. Exchange Server 2003 to 2007
    2. ISA Server to a hardware firewall
    3. Phone system to VoIP
    4. etc.
We open source. Powered by GitHub