Blog

Blogging on programming and life in general.

  • Published on
    -
    1 min read

    Aligning Images In Markdown

    Every post on this site is written in markdown since successfully moving over to GatsbyJS. Overall, the transition has been painless and found that writing blog posts using the markdown syntax is a lot more efficient than using a conventional WYSIWYG editor. I never noticed until making the move to markdown how fiddly those editors were as you sometimes needed to clean the generated markup at HTML level.

    Of course, all the efficiency of markdown does come at a minor cost in terms of flexibility. Out of the minor limitations, there was one I couldn't let pass. I needed to find a way to position images left, right and centre as majority of my previous posts have been formatted in this way. When going through the conversion process from HTML to markdown, all my posts were somewhat messed up and images were rendered 100% width.

    HTML can be mingled alongside the markdown syntax, so I do have an option to use the image tag and append styling. I wouldn't recommend this from a maintainability perspective. Markdown is platform-agnostic so your content is not tied to a specific platform. By adding HTML to markdown, you're instantly sacrificing the portability of your content.

    I found a more suitable approach would be to handle the image positioning by appending a hashed value to the end of the image URL. For example, #left, #right, or #centre. We can at CSS level target the src attribute of the image and position the image along with any additional styling based on the hashed value. Very neat!

    img[src*='#left'] {
    float: left;
    margin: 10px 10px 10px 0;
    }
    
    img[src*='#center'] {
    display: block;
    margin: 0 auto;
    }
    
    img[src*='#right'] {
    float: right;
    margin: 10px 0 10px 10px;
    }
    

    Being someone who doesn’t delve into front-end coding techniques as much as I used to, I am amazed at the type of things you can do within CSS. I’ve obviously come late to the more advanced CSS selectors party.

  • I decided to write this post to act primarily as a reminder to myself for when I'm publishing an ASP.NET Core project ready for a production environment. Most of the ASP.NET Core projects I'm currently working on are based on pre-existing client or platform-based boilerplates and when taking these on, they vary in quality and a result, some key project settings are just not implemented.

    I will be covering the following areas:

    • Ensuring the correct environment variable is set for your publish profile.
    • Setting custom error pages.
    • Switching between development and production appsetting.json files.

    Setting Environment In Publish Profile

    After you have created the publish profile, update the .pubxml file (found under the "/Properties/PublishProfiles" directory within your project) and add a EnvironmentName variable:

    <PropertyGroup>
        <EnvironmentName>Production</EnvironmentName>
    </PropertyGroup>
    

    This variable is very much key to the whole operation. Without it, the project will be stuck in development mode and the sections, listed below, will not work.

    Setting Custom Error Pages

    We are only interested in seeing a custom error page when in production mode. To do this, we need to:

    1. Update the Startup.cs file to enable status code error pages.
    2. Create an error controller to render the custom error pages.

    Startup.cs

    To serve our custom error page, we need to declare the route using the app.UseStatusCodePagesWithReExecute() method. This method includes a placeholder {0}, which will be replaced with the status code integer - 404, 500, etc. We can then render different views depending on the error code returned. For example:

    • /Error/404
    • /Error/500
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        // Render full blown exception only if in development mode.
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseStatusCodePagesWithReExecute("/Error/{0}");
            app.UseHsts();
        }
    }
    

    Error Controller

    Based on the status code returned, different views can be rendered.

    public class ErrorController : Controller
    {
        [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
        [Route("/Error/{statusCode}")]
        public ViewResult Status(int statusCode)
        {
            if (statusCode == StatusCodes.Status404NotFound)
            {
                return View("~/Views/Error/NotFound.cshtml");
            }
            else
            {
                return View("~/Views/Error/GeneralError.cshtml");
            }
        }
    }
    

    Web.config

    Being a .NET Core project, there is one area that is easily overlooked as we're so focused on the Startup.cs and appsettings.json files - that is the web.config. We need to ensure the environment variable is set here also by adding the following:

    <environmentVariables>
        ...
        <environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Production" />
        ...
    </environmentVariables>
    

    If the "ASPNETCORE_ENVIRONMENT" value isn't set correctly at this point, this will cause issues/inconsistencies globally.

    Switching To appsetting.production.json

    You've probably noticed that your ASP.NET Core project contains three appsettings.json files - each one for your environment:

    • appsettings.json
    • appsettings.development.json
    • appsettings.production.json

    If your ASP.NET Core project version is less than 3.0, you can switch between each appsettings.json file by adding the following code to your Startup.cs file:

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        IConfigurationBuilder configBuilder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", true, true)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", true)
            .AddEnvironmentVariables();
    
        Configuration = configBuilder.Build();
    }
    

    However, if running on ASP.NET Core 3.0+, you will need to use WebHost.CreateDefaultBuilder(args) method that will be added to the Programs.cs file.

    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }
    
        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .UseContentRoot(Directory.GetCurrentDirectory())
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }
    

    The CreateDefaultBuilder performs the following environment-related tasks (to name a few):

    • Sets the content root to the path returned by Directory.GetCurrentDirectory().
    • Loads host configuration from environment variables prefixed with ASPNETCORE_ (for example, ASPNETCORE_ENVIRONMENT).
    • Loads application configuration settings in the following order, starting from appsettings.json and then appsettings.{Environment}.json.

    As you can see, from ASP.NET Core 3.0 onwards, quite a lot is being done for you from such a minimal amount of code.

  • I’ve had this blog since 2007 when I had a bright idea to make a small mark on the internet. Back then, there weren’t many platforms to easily contribute ones technical thoughts freely in writing as there are now. All you really had were forums and a handful of other sites in the likes of 4GuysFromRolla.com, C# Corner and LearnASP.com (to name a few that come to mind). Now I could be wrong about the accuracy of this opening statement as 2007 was a long time ago - back in much simpler times when I was a Junior Web Developer.

    We have now come to a point where we’re spoilt for choice. There are multiple mediums where you have the freedom to publish your own technical writing in a more public and accessible way, the main ones being:

    • Medium
    • Dev.to
    • Hashnode.com
    • LinkedIn Articles

    At present, I post some of my writing to Medium whether that is a clone of my own blog content or new material specifically for the platform. However, I’m now rethinking where I should be publishing my content as I am now seeing more of my fellow developers on Twitter posting content to dev.to, when they previously used Medium.

    I really like dev.to found its approach to content curation to the developer community refreshing, which makes for very addictive reading and you can really see the passion in the writers. Should I start cross-posting there as well for more exposure? How does this affect things from an SEO standpoint where I have the same post on my blog as well as Medium and dev.to? All I know is anything I cross-post from my blog to Medium gets ranked higher in Google search results, which is to be expected.

    If I’m being honest to myself, I like posting content where I’m another small cog part of a wider community as there is a higher chance in like-minded individuals gaining access to your content and in the process get involved by commenting and imparting their knowledge on your written piece. You can’t help but feel rewarded when your article gets a like, clap or comment, which in return makes you want to do the same for other contributers. This doesn’t really happen on a personal website.

    When you are posting on another platform you don’t have to worry about technical issues or hosting. The only thing you need to do is write! But you have to remember that you’re writing in a platform that is not your own and any future changes will be out of your control.

    As great as these other writing platforms are, you are restricted in really seeing the developers personality, which is something that speaks volumes when viewing their personal website. They present their content in their own unique way and most importantly write about things freely that, otherwise, may not be within the parameters of a third-party platform.

    Final Thoughts

    As I’ve noted a shift in the number of technical posts being published to dev.to, I will more than likely do the same and cross-post any relevant content from my personal site. You can’t help but feel it’s the best place to get exposure to programming related content. Having said this, I still feel there’s is space for me to also cross-post to Medium. But what I won’t do is cross-post the same content to both. This feels counter-intuitive. Use the most appropriate platform that has the highest chance of targeting the readers based on the subject matter in hand.

    I don’t think I could ever stop writing within my own site as I like the freedom of expression - no strings attached. I can write about whatever I want and if there happens to be a post I’d like to also publish to the likes of either Medium or dev.to, I got the flexibility to do that as well.

  • If you’re seeing this post, then this means I have fully made the transition to a static-generated website architecture using GatsbyJS. I started this process late December last year but then started taking it seriously into the new year. It’s been a learning process getting to grips with a new framework as well as a big jump for me and my site.

    Why has it been a big jump?

    Everything is static. I have downsized my website footprint exponentially. All 250+ blog posts have been migrated into markdown files, so from now on, I will be writing in markdown and (with the help of Netlify) pushing new content by a simple git commit. Until now, I have always had a website that used server-side frameworks that stored all my posts in a database. It’s quite scary moving to a framework that feels quite unnatural to how I would normally build sites and the word “static” when used in relation to a website reminds me of a bygone era.

    Process of Moving To Netlify

    I was pleasantly surprised by how easy the transition to Netlify was. There is a vast amount of resources available that makes for good reading before making the switch to live. After linking my website Bitbucket repository to a site, the only things left to do to make it live were the following:

    • Upload a _redirects file, listing out any redirects you require Netlify to handle. For GatsbyJS sites, this will need to be added to the /static directory.
    • Setup Environment variables to allow the application to easily switch between development and production states. For example, my robots.txt is set to be indexable when only in production mode.
    • Add CNAME records to your existing domain that point to your Netlify domain. For example, surindersite.netlify.com.
    • Issue a free Let’s Encrypt SSL certificate, which is easily done within the account Domain settings.

    Post live, the only thing that stumped me was the Netlify domain didn’t automatically redirect to my custom domain. This is something I thought Netlify would automatically handle once the domain records were updated. To get around this, an explicit domain 301 redirect needs to be added to your _redirects file.

    # Domain Redirect
    https://surinderbhomra.netlify.com/*     https://www.surinderbhomra.com/:splat    301!
    

    New Publishing Process

    Before making the switchover, I had to carry out some practice runs on how I would be updating my website just to be sure I could live with the new way of adding content. The process is now the following:

    1. Use “content/posts” branch to add a new blog post.
    2. Create a new .md file that consists of the date and slug. In my case, all my markdown files are named "2010-04-02---My-New-Post.md".
    3. Ensure all categories and tags in the markdown frontmatter is named correctly. This is an important step to ensure no unnecessary new categories or tags are created.
    4. Add any images used in the post to the site. The images should reference Imagekit.io.
    5. Check over the post locally.
    6. Push to master branch and let Netlify carry out the rest.

    Out of all the steps, I have only found steps 3 and 4 to require a little effort when compared to using a CMS platform, as previously, I could select from a predefined list of categories and upload images directly. Not a deal-breaker.

    Next Steps

    I had a tight deadline to ensure I made the move to Netlify before my current hosting renews for another year and still have quite a bit of improvement to make. Have you seen my Google Lighthouse score!?! It’s shockingly bad due to using the same HTML markup and CSS from my old site. I focused my efforts cramming in all the functionality to mimic how my site used to work and efficiencies in keeping build times to Netlify low.

    First thing on the list - rebuild website templates from the ground up.

  • Yesterday, I was frantically trying to debug why some documents weren’t getting returned when using the DocumentHelper.GetDocuments() method. Normally when this happens, I need delve deeper to see what SQL Kentico is generating via the API in order to get a little more information on where the querying could be going wrong. To do this, I perform a little “hacky” approach (purely for debugging) whereby I break the SQL within the API by insert a random character within the OrderBy or Where condition parameters.

    Voila! The can see the SQL in the error page.

    But it was only yesterday where I was shown a much more elegant solution by simply adding a GetFullQueryText() to your GetDocuments(), which then returns the SQL with all the parameters populated for you:

    string debugQuery = DocumentHelper.GetDocuments()
                                      .OnSite(SiteContext.CurrentSiteName)
                                      .Types(DocumentTypeHelper.GetClassNames(TreeProvider.ALL_CLASSNAMES))
                                      .Path("/", PathTypeEnum.Children)
                                      .Culture(LocalizationContext.PreferredCultureCode)
                                      .OrderBy("NodeLevel ASC", "NodeOrder ASC")
                                      .GetFullQueryText();
    

    I can’t believe I did not know this after so many years working on Kentico! How embarrassing...

  • For the Gatsby version of my website, currently in development, I am serving all my images from Imagekit.io - a global image CDN. The reasons for doing this is so I will have the ultimate flexibility in how images are used within my site, which didn’t necessarily fit with what Gatsby has to offer especially when it came to how I wanted to position images within blog post content served from markdown files.

    As I understand it, Gatsby Image has two methods of responsively resizing images:

    1. Fixed: Images that have a fixed width and height.
    2. Fluid: Images that stretch across a fluid container.

    In my blog posts, I like to align my images (just take look at my post about my time in the Maldives) as it helps break the post up a bit. I won’t be able to achieve that look by the options provided in Gatsby. It’ll look all a little bit too stacked. The only option is to serve my images from Imagekit.io, which in the grand scheme isn’t a bad idea. I get the benefit of being able to transform images on the fly, optimisation (that can be customised through Imagekit.io dashboard) and fast delivery through its content-delivery network.

    To meet my image requirements, I decided to develop a custom responsive image component that will perform the following:

    • Lazyload image when visible in viewport.
    • Ability to parse an array “srcset" sizes.
    • Set a default image width.
    • Render the image on page load in low resolution.

    React Visibility Sensor

    The component requires the use of "react-visibility-sensor” plugin to mimic the lazy loading functionality. The plugin notifies you when a component enters and exits the viewport. In our case, we only want the sensor to run once an image enters the viewport. By default, the sensor is always fired every time a block enters and exits the viewport, causing our image to constantly alternate between the small and large versions - something we don't want.

    Thanks for a useful post by Mark Oskon, he provided a solution that extends upon the react-visibility-sensor plugin and allows us to turn off the sensor after the first reveal. I ported the code from Mark's solution in a newly created component housed in "/core/visibility-sensor.js", which I then reference into my LazyloadImage component:

    import React, { Component } from "react";
    import PropTypes from "prop-types";
    import VSensor from "react-visibility-sensor";
    
    class VisibilitySensor extends Component {
      state = {
        active: true
      };
    
      render() {
        const { active } = this.state;
        const { once, children, ...theRest } = this.props;
        return (
          <VSensor
            active={active}
            onChange={isVisible =>
              once &&
              isVisible &&
              this.setState({ active: false })
            }
            {...theRest}
          >
            {({ isVisible }) => children({ isVisible })}
          </VSensor>
        );
      }
    }
    
    VisibilitySensor.propTypes = {
      once: PropTypes.bool,
      children: PropTypes.func.isRequired
    };
    
    VisibilitySensor.defaultProps = {
      once: false
    };
    
    export default VisibilitySensor;
    

    LazyloadImage Component

    import PropTypes from "prop-types";
    import React, { Component } from "react";
    import VisibilitySensor from "../core/visibility-sensor"
    
    class LazyloadImage extends Component {
        render() {
          let srcSetAttributeValue = "";
          let sanitiseImageSrc = this.props.src.replace(" ", "%20");
    
          // Iterate through the array of values from the "srcsetSizes" array property.
          if (this.props.srcsetSizes !== undefined && this.props.srcsetSizes.length > 0) {
            for (let i = 0; i < this.props.srcsetSizes.length; i++) {
              srcSetAttributeValue += `${sanitiseImageSrc}?tr=w-${this.props.srcsetSizes[i].imageWidth} ${this.props.srcsetSizes[i].viewPortWidth}w`;
    
              if (this.props.srcsetSizes.length - 1 !== i) {
                srcSetAttributeValue += ", ";
              }
            }
          }
    
          return (
              <VisibilitySensor key={sanitiseImageSrc} delayedCall={true} partialVisibility={true} once>
                {({isVisible}) =>
                <>
                  {isVisible ? 
                    <img src={`${sanitiseImageSrc}?tr=w-${this.props.widthPx}`} 
                          alt={this.props.alt}
                          sizes={this.props.sizes}
                          srcSet={srcSetAttributeValue} /> : 
                    <img src={`${sanitiseImageSrc}?tr=w-${this.props.defaultWidthPx}`} 
                          alt={this.props.alt} />}
                  </>
                }
              </VisibilitySensor>
          )
        }
    }
    
    LazyloadImage.propTypes = {
      alt: PropTypes.string,
      defaultWidthPx: PropTypes.number,
      sizes: PropTypes.string,
      src: PropTypes.string,
      srcsetSizes: PropTypes.arrayOf(
        PropTypes.shape({
          imageWidth: PropTypes.number,
          viewPortWidth: PropTypes.number
        })
      ),
      widthPx: PropTypes.number
    }
    
    LazyloadImage.defaultProps = {
      alt: ``,
      defaultWidthPx: 50,
      sizes: `50vw`,
      src: ``,
      widthPx: 50
    }
    
    export default LazyloadImage
    

    Component In Use

    The example below shows the LazyloadImage component used to serve a logo that will serve a different sized image with the following widths - 400, 300 and 200.

    <LazyloadImage 
                    src="https://ik.imagekit.io/surinderbhomra/Pages/logo-me.jpg" 
                    widthPx={400} 
                    srcsetSizes={[{ imageWidth: 400, viewPortWidth: 992 }, { imageWidth: 300, viewPortWidth: 768 }, { imageWidth: 200, viewPortWidth: 500 }]}
                    alt="Surinder Logo" />
    

    Useful Links

    https://alligator.io/react/components-viewport-react-visibility-sensor/ https://imagekit.io/blog/lazy-loading-images-complete-guide/ https://www.sitepoint.com/how-to-build-responsive-images-with-srcset/

  • Published on
    -
    2 min read

    Journey To GatsbyJS: Beta Site Release v2

    It’s taken me a little longer to make more progress as I’ve been stumped on how I would go about listing blog posts filtered by year and/or month. I’ve put extra effort in ensuring the full date is included in the URL for all my blog posts. In the process of doing this, I had to review and refactor the functions used within gatsby-node.js.

    Refactoring

    I noticed that I was carrying out build operations inefficiently and in some cases where they didn’t need to happen. For example, I was building individual blog post pages all over the place thinking I was required to do this in areas where I was listing blog posts. Reviewing my build operations had a positive impact and managed to reduce build times to Netlify from 2 minutes 17 seconds to 2 minutes 3 seconds. Where you are able to make build time savings, why wouldn’t you want to do this? By being efficient, you could squeeze in more builds within Netlify’s 300-minute monthly limit (based on free-tier).

    Page Speed Tests

    The GatsyJS build is at a point where I can start carrying out some performance tests using Google Page Insights and Lighthouse. Overall, the tests have proved more favourable when compared against my current site. The Lighthouse analysis still proves there is work to be done, however, the static-site generator architecture sets you off to a good start with minimal effort.

    Google Lighthouse Stats - Current Site Current site

    Google Lighthouse Stats - Gatsby Site Gatsby site

    Current HTML/CSS Quality

    I can see the main area of failure is the HTML and CSS build... not my strong suit. The template has inherited performance-lag remnants from my current site and even though I have cleaned it up as well as I can, it’s not ideal. At this moment, I have to focus on function over form.

    Site Release Details

    This version contains the following:

    • Blog post-filtering by year and/or month. For example:
      • /Blog/2019
        • /Blog/2019/12
    • Refactored build functions.
    • Removed unneeded CSS from the old template (still got more to do).

    GatsbyJS Beta Site: http://surinderbhomra.netlify.com

  • There will be times where you will want to customise the slug based on fields from your markdown file. In my case, I wanted all my blog post URL's in the following format: /Blog/yyyy/MM/dd/Blog-Post-Title. There are two ways of doing this:

    1. Enter the full slug using a “slug” field within your markdown file.
    2. Use the onCreateNode() function found in the gatsby-node.js file to dynamically generate the slug.

    My preference would be option 2 as it gives us the flexibility to modify the slug structure in one place when required. If for some reason we had to update our slug structure at a later date, it would be very time consuming (depending on how many markdown files you have) to update the slug field within each markdown file if we went ahead with option 1.

    This post is suited for those who are storing their content using markdown files. I don’t think you will get much benefit if your Gatsby site is linked to a headless CMS, as the slugs are automatically generated within the platform.

    The onCreateNode() Function

    This function is called whenever a node is created or updated, which makes it the most ideal place to add the functionality we want to perform. It is found in the gatsby-node.js file

    What we need to do is retrieve the fields we would like to form part of our slug by accessing the nodes frontmatter. In our case, all we require is two fields:

    1. Post Date
    2. Slug
    exports.onCreateNode = ({ node, actions, getNode }) => {
        const { createNodeField } = actions
      
        if (node.internal.type === `MarkdownRemark`) {
          const relativeFilePath = createFilePath({ node, getNode, trailingSlash: false });
          const postDate = moment(node.frontmatter.date); // Use moment.js to easily change date format.
          const url = `/Blog/${postDate.format("YYYY/MM/DD")}${node.frontmatter.slug}`;
    
          createNodeField({
            name: `slug`,
            node,
            value: url,
          });
        }
      }
    

    After making this change, you will need to re-run the gatsby develop command.

  • Published on
    -
    2 min read

    Journey To GatsbyJS: Beta Site Release v1

    I am surprised at just how much progress I have made in replicating my site using the GatsbyJS framework. I have roughly spent around 10-12 days (not full days) getting up to speed on everything GatsbyJS and transitioning what I have learnt over to the GatsbyJS version of my site.

    Initially, my progress was slow as I had to get my head around GraphQL, the process of how static pages are generated in the hierarchy I require and export my existing blog content to markdown. Having previous experience in React has definitely helped in making relatively swift progress.

    What I would say to new GatsbyJS developers is to use the Gatsby Starter Default package - if you really want to understand Gatsby in its entirety. The package gives you enough functionality to understand what’s going on so you can easily make your own customisations. Using other fully functional starter packages can cause confusion and led me asking more questions when attempting to make changes. Trust me, it’s not wise to get too ahead of yourself (as admirable as that might be) in the early stages. Start simple and work your way up!

    The interesting thing I noticed whilst working with GatsbyJS is when I think I am stumped from a functionality point-of-view, I find there is a plugin that does exactly what I require. GatsbyJS offers a foray of quality plugins. For example, I had issues in ordering my "preconnect" declarations within the <head> block so they resided before any styles or scripts. It seemed GatsbyJS has its own way of ordering the <head> elements. Thankfully, like always, there’s a plugin on hand to cure my woes.

    Site Release Details

    As of today, I have released the first version of my GatsbyJS site to Netlify. It’s by no means perfect and will be a work-in-progress for many iterations to come.

    This version contains the following:

    • Implemented styling from the current site. Still rough around the edges and in no way efficiently done.
    • All images are hosted via Imagekit.io to be served efficiently via CDN with responsive capability.
    • Added custom routing for blog posts to include the date. For example, “/Blog/2020/01/01/My-Blog-Post”.
    • Posts can be filtered by Category (unstyled).
    • Posts Archive page (unstyled)
    • Implemented pagination for blog listing.
    • Added the following plugins:

    Making my first publish to Netlify was completed in: 2 minutes 17 seconds. From an efficiency standpoint, I don’t know if this is good or bad. For me, 2 minutes seems like a long time. I wonder if it could be due to the 250+ markdown files I’m using for my blog posts and the multiple filtering routes. It’s also worth noting, I’m going completely static by not relying on any content management platform.

    GatsbyJS Beta Site: http://surinderbhomra.netlify.com

  • Published on
    -
    6 min read

    Year In Review - 2019

    I am glad to report that this year was a year of new learning. Not just about things from a technical standpoint but from a personal standpoint. I feel I started the year with a single-track mindset. However, as the year progressed I have become open to new ways of thinking and finally accepting that even though certain personal milestones I set for myself may not have been accomplished, I am content on lessons learnt from failure. Failure may suck, but it’s progression! It also gives me something to write about. :-)

    2019 in Words/Phrases

    Kentico 12 MVC, Umbraco, GatsbyJs, Azure Dev Ops, Maldives, Hiking, Drupal (yes I had to do that along with a bit of PHP), Cloudflare CDN Configuration, Google Lighthouse score, Headless CMS - strategic asset, Prismic, Netlify, Kontent, CaaS (Content-as-a-Service), Automated backups for personal hosting, iPad for improved productivity, A2 Hosting Issues, Writers block, New desk and office, Failing Macbook Pro battery, Considering an iPhone 11, Fondness of Port.

    Site Offline and Lessons Learnt

    I was welcomed with the first bit of failure in April where my website was taken offline (along with many others) for a lengthy period thanks to my previous hosting provider, A2 Hosting. They had no backups, no disaster recovery and no customer support. Their whole operation is a disaster.

    Failure = Lesson learnt.

    The only benefit of this experience was that it led me to a chain of events to reassess how I host my site and come to the realisation just how important my online presence is to me. Luckily, I was able to get back up and running by moving hosting provider. Thank god I had a recent enough backup to do this.

    Popular Posts of The Year

    This year I have written 26 posts (including this one). I've delved into my Google Analytics and picked a handful of gems where I believe in my own small way have made an impact:

    I think my crowning glory is Google classing my post about “Switching Branches in TortoiseGit" as a featured snippet. So if anyone searches for something along those search terms, they will see the following as a top post. I don't know how long this will last, but I'll take it!

    Google Featured Snippet - Switch Branches In TortoiseGit

    Statistics

    My site statistics have increased considerably, which has been amazing. However, I have to remain realistic and grounded in what to expect in future comparisons. I think the figures may plateau over the next year.

    The stats I post below is based on organic searches and I haven’t actively posted links on my social. Maybe this is something I should get back into doing for further exposure.

    2018/2019 Comparison:

    • Users: +50%
    • Page Views: +47%
    • New Users: +48%
    • Bounce Rate: +0.8%
    • Search Console Total Clicks: +251%
    • Search Console Impressions: +280%
    • Search Console Page Position: -15%

    Syndicut

    I am so close to hitting the all-time milestone for the length of service when compared to any company I’ve worked in previously. In fact, I have already surpassed any previous record three-fold. As of next July, it will be 10 years! Wowsers!

    I can see the coming year will be a time to reassess how we approach our technical projects to accommodate new markets, technologies and frameworks. It’s always an exciting time to be a developer at Syndicut, but I am looking forward to sinking my teeth into new challenges ahead!

    Greater Emphasis on CaaS (Content-as-a-Service)

    Over the last year, I have noticed a shift in how content is managed. Even though I have been busy working away on headless CMS’s at Syndicut over the last few years, it seems to be the year where its properly been given global traction and market awareness. You can just tell by the number of events for both developers and clients.

    Through this exposure, clients are becoming technically savvy and questioning how and where their data is housed. Content is a strategic asset that should no longer be siloed, but distributed across multiple mediums, for example:

    • Website
    • Mobile Applications
    • Digital Billboards

    The key to a successful Headless CMS integration is not the development of an application, but the content-modelling. Based on what I have seen from other implementations, sufficient content-modelling always seems to be missed. Data-architecture is key to ensure data is scalable across all mediums.

    I am also a Kontent (previously known as Kentico Cloud) Certified Developer.

    iPad and Now iPhone???

    This subject matter truly alarms me.

    I’ve been considering getting an iPhone 11 after Google released their dismal spec of the Pixel 4 and on top of that, finding that I am really happy with my iPad Air purchase. This is coming from an Android fan!

    I have no regrets in getting an iPad, especially when combined with the a keyboard and Apple Pen. It makes you a productivity powerhouse! We live in a world where finding quality Android tablets with sufficient accessories is difficult to find.

    If I can get my head around being locked into the Apple eco-system, I might make the move. Why oh why is Google putting me in such a position. :-S

    I guess we’ll have to wait till I write my “Year In Review - 2020” on what I ended up doing.

    Coffee Tables and Desk Purchased!

    In my last year in review, I jokingly added a footnote stating I needed to get a coffee table set and desk. I can mark a massive tick against these two items for a job well done. In fact, I went a step further with purchasing a desk by converting a part of a room into a small office with the following additions:

    • Ikea desk chair
    • Corner shelves
    • An array of potted plants
    • Laptop stand
    • Very cool desk lamp
    • Nice grey rug with some pleasant subtle abstract patterns

    It’s now a perfect place where I can work and write without any distractions. The room still requires some finishing touches - in my case, it’s always the small jobs that take the longest!

    I was surprised at how productive I’ve been by finally having a small office setup. Gone are the days where I would be reclined on my sofa in front of the TV working away on my laptop.

    Redeveloping My Site

    It seems like I can’t go through a year without looking into redeveloping my site. It’s the curse when being exposed to working with new technologies and platforms. I like to ensure I am moving with the times too.

    I have been considering ditching Kentico as my content-management platform and opting for the static-generator route, such as Gatsby. Resulting in simplified platform-agnostic hosting, site architecture and with the added benefit of portability. I am in the middle of replicating my site functionality using Gatsby to see if it’s a feasible option.

    I will be posting links to my “in progress” site hosted on Netlify in my “Journey To GatsbyJs” Series, where I will be writing about things I’ve learnt trying to replicate my site functionality.