diff --git a/2010/07/my-first-post/index.html b/2010/07/my-first-post/index.html index e21fb909..d2b97c5f 100644 --- a/2010/07/my-first-post/index.html +++ b/2010/07/my-first-post/index.html @@ -5,4 +5,4 @@

My First Post

I’ve finally gone and done it.

To be honest, creating my own blog wasn’t foremost in my thoughts until fairly recently. Scott Hanselman had a couple of interesting videos on his blog that finally convinced me to do it.

I hope you like it.

-
Shared Resource Schedule Service
\ No newline at end of file +
Shared Resource Schedule Service
\ No newline at end of file diff --git a/2010/07/shared-resource-schedule-service/index.html b/2010/07/shared-resource-schedule-service/index.html index a80fadf6..20ec7ec0 100644 --- a/2010/07/shared-resource-schedule-service/index.html +++ b/2010/07/shared-resource-schedule-service/index.html @@ -4,4 +4,4 @@ gtag('config', 'UA-17968343-1');

Shared Resource Schedule Service

I think I’ve got a new project to work on at home. We’ve got this problem at work coordinating a few shared resources in Outlook (like a couple of meeting rooms and a projector), but we couldn’t find any good solutions out there short of installing Exchange Server.

I’ve been wanting to play around with Entity Framework a bit, so this should be a good candidate. Perhaps I can slap a UI on it using Silverlight and Ria Services.

-
Shared Resource Service Requirements
\ No newline at end of file +
Shared Resource Service Requirements
\ No newline at end of file diff --git a/2010/08/changing-from-an-ipod-to-a-creative-zen/index.html b/2010/08/changing-from-an-ipod-to-a-creative-zen/index.html index 6a55876a..d87e9261 100644 --- a/2010/08/changing-from-an-ipod-to-a-creative-zen/index.html +++ b/2010/08/changing-from-an-ipod-to-a-creative-zen/index.html @@ -12,4 +12,4 @@

So

Converting to Media Monkey was easy, and all the data (like ratings, play counts, album art) came over fine. I did have some trouble with the comments getting scrambled in several tracks, but it seems like iTunes was causing that well before copying the data over. All told, I had all the data over and fixed up after a half day of elbow grease.

Verdict

My only real problem so far has been with the Zen. I’ve had to reboot the device a couple times when it’s hiccupped during a huge sync operation or failed to come back out of sleep.The UI can be a bit difficult sometimes as well. I won’t get into details, but let me just say that converting a WEP key to stars while typing with 9 buttons isn’t making my life any easier.

All in all, I’m pretty happy with the change so far. Just getting the weight of my old 20 GB monster out of my pocket has been nice.

-
My First Open Source Project
\ No newline at end of file +
My First Open Source Project
\ No newline at end of file diff --git a/2010/08/shared-resource-service-requirements/index.html b/2010/08/shared-resource-service-requirements/index.html index 21a82c2f..112ab8d1 100644 --- a/2010/08/shared-resource-service-requirements/index.html +++ b/2010/08/shared-resource-service-requirements/index.html @@ -17,4 +17,4 @@
  • Save free/busy information for all resources in a format compatible with MS Outlook.
  • The schedule for a resource can be retrieved in the iCal format.
  • -
    SQL Management Studio Express with VS 2010 Express
    \ No newline at end of file +
    SQL Management Studio Express with VS 2010 Express
    \ No newline at end of file diff --git a/2010/08/ssmse-with-vs2010-express/index.html b/2010/08/ssmse-with-vs2010-express/index.html index f8cad1b7..561fc7bb 100644 --- a/2010/08/ssmse-with-vs2010-express/index.html +++ b/2010/08/ssmse-with-vs2010-express/index.html @@ -24,4 +24,4 @@
  • Stand back and let the web platform installer do it’s thing.
  • I wish I’d tried that the first time.

    -
    Changing From an iPod to a Creative Zen
    \ No newline at end of file +
    Changing From an iPod to a Creative Zen
    \ No newline at end of file diff --git a/2010/09/ie9-try-and-fail/index.html b/2010/09/ie9-try-and-fail/index.html index 0247509c..800fd2d9 100644 --- a/2010/09/ie9-try-and-fail/index.html +++ b/2010/09/ie9-try-and-fail/index.html @@ -12,4 +12,4 @@

    I could have lived with the disabled desktop sharing if it were the only problem, but a few hideous rendering problems in Google Calendar, and WordPress failing to save my posts was a deal breaker. The compatibility mode doesn’t seem to be compatible enough, and tweaking the settings in the developer console (F12) is too much of a nuisance to do every day.

    IE9 came off pretty easy once I figured out how to do it. It’s listed as an update, not as an application, so you need to click on the the “View installed updates” thingy of thePrograms and Features menu.

    I hope they get the bugs worked out soon; it’s only been a day and I’m starting to miss it already.

    -
    SQLite vs. SQL CE 3.5 with Entity Framework 4
    \ No newline at end of file +
    SQLite vs. SQL CE 3.5 with Entity Framework 4
    \ No newline at end of file diff --git a/2010/09/my-first-open-source-project/index.html b/2010/09/my-first-open-source-project/index.html index 705450f3..4aa12425 100644 --- a/2010/09/my-first-open-source-project/index.html +++ b/2010/09/my-first-open-source-project/index.html @@ -8,4 +8,4 @@

    My favourite of the contenders is released under the GNU LGPL license. This shouldn’t impose any awkward restrictions. I have additional freedom because I’m planning to release my project as open source, but I can see how this would be more difficult for a company building a commercial product.

    Since I was reading about licenses, it seemed as good a time as any to pick one for my project. After a lot of reading, I decided to go with the GNU GPL license. I want my project to be freely available, and I don’t want anyone to use it to make a profit without me being involved. If I were unsure this would be the safest choice anyway, because I always have the ability to switch to a less restrictive license later.

    Now if I can just find an IoC container, a unit testing framework, and a mocking framework that are also compatible with GPL, Ill be ready to get started.

    -
    Themis: System Design
    \ No newline at end of file +
    Themis: System Design
    \ No newline at end of file diff --git a/2010/09/themis-system-design/index.html b/2010/09/themis-system-design/index.html index f02b6a87..f5ba0f70 100644 --- a/2010/09/themis-system-design/index.html +++ b/2010/09/themis-system-design/index.html @@ -23,4 +23,4 @@

    IE9 Try and Fail
    \ No newline at end of file +
    IE9 Try and Fail
    \ No newline at end of file diff --git a/2010/10/sqlite-vs-sql-ce-3-5-with-entity-framework-4/index.html b/2010/10/sqlite-vs-sql-ce-3-5-with-entity-framework-4/index.html index ef03e49d..23a6731b 100644 --- a/2010/10/sqlite-vs-sql-ce-3-5-with-entity-framework-4/index.html +++ b/2010/10/sqlite-vs-sql-ce-3-5-with-entity-framework-4/index.html @@ -48,4 +48,4 @@

    SQLiteThe only thing left is to study.

    You can get a .Net library for SQLite here: https://sqlite.phxsoftware.com/

    It’s able to integrate with Visual Studio, even the Express version, but it didn’t work well for me. With a good database management tool you don’t need it. I’ve been using SQLite Administrator, which you can get here: https://sqliteadmin.orbmu2k.de/

    -
    64-bit IIS vs. 32-bit Assemblies
    \ No newline at end of file +
    64-bit IIS vs. 32-bit Assemblies
    \ No newline at end of file diff --git a/2010/11/64-bit-iis-vs-32-bit-assemblies/index.html b/2010/11/64-bit-iis-vs-32-bit-assemblies/index.html index 01305cec..255b59b0 100644 --- a/2010/11/64-bit-iis-vs-32-bit-assemblies/index.html +++ b/2010/11/64-bit-iis-vs-32-bit-assemblies/index.html @@ -17,4 +17,4 @@
  • Compile most of your assemblies for ‘Any CPU’, but compile entry-point assemblies (such as my service executable) for 32-bit
  • A configuration-based solution isn’t ideal based on the number and management practices of our environments. Finding and removing platform dependence would be the best technical solution, but it would be risky and time consuming. Switching some of my assemblies back to ‘Any CPU’ did the job with a minimal amount of impact.

    -
    Invitations and the VCard Format
    \ No newline at end of file +
    Invitations and the VCard Format
    \ No newline at end of file diff --git a/2010/12/invitations-and-the-vcard-format/index.html b/2010/12/invitations-and-the-vcard-format/index.html index 22798256..778a7763 100644 --- a/2010/12/invitations-and-the-vcard-format/index.html +++ b/2010/12/invitations-and-the-vcard-format/index.html @@ -17,4 +17,4 @@

    I’ve added the first unit tests to the solution, checking the parser against a number of examples in the specifications and real snippets extracted from emails sent by Outlook. I’ve also added tests for a number of failure cases in the parser such as groups without an ending or values lines without a value delimiter.

    My next addition will be parsers for the value types and a stub in the test harness that replies to emails with some info about the original request.

    The code at the time of this post is available here: https://github.com/jessemcdowell/themis/tree/8e0c428df0e33145df0323d6e9ae617114dd0f85

    -
    Teaching IT
    \ No newline at end of file +
    Teaching IT
    \ No newline at end of file diff --git a/2010/12/teaching-it/index.html b/2010/12/teaching-it/index.html index 08438344..bb8218ce 100644 --- a/2010/12/teaching-it/index.html +++ b/2010/12/teaching-it/index.html @@ -21,4 +21,4 @@

    It took me about an hour and a half to prepare, and two hours to present. I’ve spent about a day of effort writing it down, but would guess that I’ve covered less than half of the material I talked about. To be fair, the written material is laid out quite differently from the presentations; I am trying to capture a series of troubleshooting guides that can be used in an emergency.

    Are you curious about the difference between a developer and an IT pro? The most significant difference I see is that we developers are used to an environment where we can test changes quickly and safely: change a line of code, hit F5, and see what happens. IT pros take the opposite approach because the cost of a bad change in a live production environment can be devastating. They need to be certain what any change will do before it’s made, and be prepared to roll it back if there’s any hint of trouble. It can be frustrating for a developer to work this way because it’s a serious effort to make even simple changes, but it’s this mentality that keeps the world’s servers running.

    -
    When to Add an ORM Tool
    \ No newline at end of file +
    When to Add an ORM Tool
    \ No newline at end of file diff --git a/2011/01/when-to-add-an-orm-tool/index.html b/2011/01/when-to-add-an-orm-tool/index.html index 94cca1cd..78e48c54 100644 --- a/2011/01/when-to-add-an-orm-tool/index.html +++ b/2011/01/when-to-add-an-orm-tool/index.html @@ -7,4 +7,4 @@

    Now that I’m building this neutral representation, my next thought is how it will be saved to the database. I don’t need a database at this stage of the project, so part of me wants to ignore the decision until later, but the whole point of the system is to persist and interact with these types, so it’s important that I get it right. If I make simple POCO classes now, and start writing a bunch of code that uses them, I might have to change a lot of code later if I want to switch to types generated by Entity Framework. I could write my own custom code to read and write my own types from the database, then I can use any type I want without restrictions, but it would be a waste to write this plumbing code myself when an ORM can do it faster and better.

    Creating a table design now wouldn’t be a simple matter either. I don’t know enough about the needs of the scheduling service to know which parts of the VCalendar format to bring over. If I try to guess now I know I’ll bring over a bunch of stuff that I don’t need, but starting with a simple table and adding fields every time I need one is no fun either. Adding a database to a system is like attaching a ball and chain, and I want to wait until I can be sure I have my model correct before I do it.

    I need to make a decision, so here it is: I’m going to keep building my own types, and try to keep them. When it comes time to hook up a database, I’ll play around with the new POCO support in Entity Framework 4, and if that fails I’ll try another ORM tool. I may need to change my model a bit to suit the ORM, but I’m hoping that it wont need to change much.

    -
    Working Together and Having Fun
    \ No newline at end of file +
    Working Together and Having Fun
    \ No newline at end of file diff --git a/2011/01/working-together-and-having-fun/index.html b/2011/01/working-together-and-having-fun/index.html index 53576ac5..719b0473 100644 --- a/2011/01/working-together-and-having-fun/index.html +++ b/2011/01/working-together-and-having-fun/index.html @@ -9,4 +9,4 @@

    Thanks to the people involved, this release went well despite a few hiccups.

    -
    The Average Test
    \ No newline at end of file +
    The Average Test
    \ No newline at end of file diff --git a/2011/04/the-average-test/index.html b/2011/04/the-average-test/index.html index ef50e68a..8a69363b 100644 --- a/2011/04/the-average-test/index.html +++ b/2011/04/the-average-test/index.html @@ -55,4 +55,4 @@
    1
    2
    3
    4
    int ConversionAverage(int a, int b)
    {
    return (Int32)(((Int64)a + (Int64)b) / 2);
    }

    Results for ConversionAverage():
    Near Zero: 121 of 121 passed.
    End of Range: 3 of 3 passed.

    -
    Consulting - A Brave New World
    \ No newline at end of file +
    Consulting - A Brave New World
    \ No newline at end of file diff --git a/2011/05/consulting-a-brave-new-world/index.html b/2011/05/consulting-a-brave-new-world/index.html index 1b14e86c..4722b08a 100644 --- a/2011/05/consulting-a-brave-new-world/index.html +++ b/2011/05/consulting-a-brave-new-world/index.html @@ -7,4 +7,4 @@

    Instead of settling in somewhere else for another long haul, I felt it was time for a change of pace. Now I get to hop from organization to organization working on new problems and broadening my skill set in the most efficient way possible. I might settle down if a good opportunity comes along, but for now I’m enjoying the freedom.

    I’m currently working on a fun little contract, but I’ll be looking for my next opportunity soon.

    If you want help designing or building awesome software that delights users, we should talk. I’d be happy to put my experience to work building you exactly what you need.

    -
    The Critical Path
    \ No newline at end of file +
    The Critical Path
    \ No newline at end of file diff --git a/2011/06/the-critical-path/index.html b/2011/06/the-critical-path/index.html index ac428aa2..9a4e8515 100644 --- a/2011/06/the-critical-path/index.html +++ b/2011/06/the-critical-path/index.html @@ -13,4 +13,4 @@

    When a critical path is defining the time line for your project, it’s important to identify it; any step that gets delayed affects the entire chain. You should start these tasks as soon as possible, and do what you can to stop them from getting blocked.

    -
    Doubling Data for Performance Testing
    \ No newline at end of file +
    Doubling Data for Performance Testing
    \ No newline at end of file diff --git a/2011/08/doubling-data-for-performance-testing/index.html b/2011/08/doubling-data-for-performance-testing/index.html index 98f112f3..4d07fa43 100644 --- a/2011/08/doubling-data-for-performance-testing/index.html +++ b/2011/08/doubling-data-for-performance-testing/index.html @@ -10,4 +10,4 @@

    I had one table variable with a list of tables to copy, and another defining the relationships between foreign keys and their source tables. Most foreign keys were named the same in all tables that they appeared in, so a single mapping was often enough for all of them. Most of the mappings could be determined from the list of tables itself, so I only had a few other relationships and special column rules that had to be entered manually.

    Another factor that helped was our use of guids for all primary keys. Because the can be determined before inserting a row, it was possible to generate the mapping from old to new key at the start of the script. I could also use a single insert statement for each table, and the order of execution only mattered where foreign key constraints existed.

    The results were tremendous. We found a bunch of issues we wouldn’t have found otherwise, and had a fairly solid indication of how the application would behave years in the future.

    -
    Managing Priorities Outside of Work
    \ No newline at end of file +
    Managing Priorities Outside of Work
    \ No newline at end of file diff --git a/2011/10/managing-priorities-outside-of-work/index.html b/2011/10/managing-priorities-outside-of-work/index.html index b2b49e0f..9fdfaf66 100644 --- a/2011/10/managing-priorities-outside-of-work/index.html +++ b/2011/10/managing-priorities-outside-of-work/index.html @@ -10,4 +10,4 @@

    This is a common problem in the software world: getting overwhelmed by a giant list of tasks, doing a little bit of everything, and completing nothing. I’ve experienced this first hand, and have been using effective tools for dealing with it for years, but I had never considered applying them to my personal life.

    I tried a few things next, but the best help came from the book Getting Results the Agile Way, which was also mentioned in the podcast. It combines agile philosophy with some ideas about balancing life priorities and energy levels. I’m not committed to the entire process, but the parts I am trying have already made a big difference. By focusing on three goals a day, I’m now managing to plow through even dauntingly large tasks. Though I’m not doing everything on my list, I’m getting the most important things done, and because I feel that I’m making progress again it’s motivating me to work harder.

    Taking the time off has been really good for me. Beyond organizing my personal priorities, I’ve also been organizing my main workspaces: my office, and my kitchen. You could say the experience is like rebooting a computer; it took a bit of time, but now I feel fresh and full of life, ready to tackle something new.

    -
    Sharpening The Saw
    \ No newline at end of file +
    Sharpening The Saw
    \ No newline at end of file diff --git a/2011/10/sharpening-the-saw/index.html b/2011/10/sharpening-the-saw/index.html index 2addefab..53fdaf46 100644 --- a/2011/10/sharpening-the-saw/index.html +++ b/2011/10/sharpening-the-saw/index.html @@ -10,4 +10,4 @@

    To learn specific technologies, I’ll spend an hour or two a few times a week reading or watching videos. I need to play with something to understand it, so I spend an odd evening banging away at some pet project.

    My study used to be limited to an occasional book or seminar, but increasing my study time, and opening myself to podcasts, blogs, and twitter has made a huge difference in my career. I have more to contribute in design meetings. I have opinions on various technologies I haven’t even used. It takes more energy for sure, but I feel like I am a better developer for it, and I don’t regret it one bit.

    This business is a challenging one, but exciting as well. If you are the kind of person that loves to learn, explore new technologies, and push yourself to constantly look at problems in new ways, then embrace the change and you will do well.

    -
    Choosing Priorities
    \ No newline at end of file +
    Choosing Priorities
    \ No newline at end of file diff --git a/2012/03/choosing-priorities/index.html b/2012/03/choosing-priorities/index.html index eefdee8c..8383451f 100644 --- a/2012/03/choosing-priorities/index.html +++ b/2012/03/choosing-priorities/index.html @@ -6,4 +6,4 @@

    When you change from trying to do everything to doing what’s most important, you need to decide what important means. Figuring this out for myself has proven difficult. I still don’t have all the answers, but I am constantly making progress.

    Deciding what isn’t important has been easier. I am abandoning Themis, my attempt at an open source project. I no longer have a need for it, and it will take a lot more effort to get it finished than I originally expected. I would be delighted if someone wanted to take it on, but there isn’t enough there for it to be likely.

    Writing in this blog has also been pushed down the priority list. I intend to keep going, but instead of forcing out a steady pace of content, I’ll wait until I have ideas that I have a strong desire to share.

    -
    InstallUtil and BadImageFormatException - Facepalm
    \ No newline at end of file +
    InstallUtil and BadImageFormatException - Facepalm
    \ No newline at end of file diff --git a/2012/04/installutil-and-badimageformatexception/index.html b/2012/04/installutil-and-badimageformatexception/index.html index 76b2a58e..e8b85f28 100644 --- a/2012/04/installutil-and-badimageformatexception/index.html +++ b/2012/04/installutil-and-badimageformatexception/index.html @@ -16,4 +16,4 @@

    Long version: Service applications in Visual Studio 2010 are 32 bit by default, and this is a reasonable default for them to have. We were trying to install the 32 bit service with the 64 bit version of InstallUtil. InstallUtil loads the target assembly to access it’s installation instructions, but you can’t load a 32 bit assembly from a 64 bit application (or vice versa). If you try to, you get a BadImageFormatException.

    Short version: Two numbers derailed my entire afternoon.

    It would have been nice if the error message from InstallUtil was a little more specific, but I suppose this isn’t a common problem. At least I got a good reminder about the importance of checking the small details when the big ones aren’t bearing fruit.

    -
    Reading Server Graphs: Connected Users
    \ No newline at end of file +
    Reading Server Graphs: Connected Users
    \ No newline at end of file diff --git a/2013/06/reading-server-graphs-connected-users/index.html b/2013/06/reading-server-graphs-connected-users/index.html index c90975cf..c7c1f5f4 100644 --- a/2013/06/reading-server-graphs-connected-users/index.html +++ b/2013/06/reading-server-graphs-connected-users/index.html @@ -40,4 +40,4 @@

    Monitoring Failure

    A flat line like this is almost never real, except maybe during deliberate maintenance windows. If it’s not obvious why you’re flat, you should check that your monitoring and graphing systems are collecting data correctly.

    -
    Controller Led Navigation in Angular
    \ No newline at end of file +
    Controller Led Navigation in Angular
    \ No newline at end of file diff --git a/2014/04/controller-led-navigation-in-angular/index.html b/2014/04/controller-led-navigation-in-angular/index.html index 733c5ab5..efc457f0 100644 --- a/2014/04/controller-led-navigation-in-angular/index.html +++ b/2014/04/controller-led-navigation-in-angular/index.html @@ -18,4 +18,4 @@

    It was easy to test this code. Whenever I expected a controller to navigate, I checked the value of $location.path(). To pass navigation parameters into controllers, I just called the navigate method before the controller was created in the setup block.

    Unfortunately this solution breaks the back button. Because the browser triggers backward navigation, the navigation parameter won’t be set when the controller tries to load. This wasn’t something I needed, so I left alone.

    -
    Why I Only Drink Loose Tea
    \ No newline at end of file +
    Why I Only Drink Loose Tea
    \ No newline at end of file diff --git a/2014/06/why-i-only-drink-loose-tea/index.html b/2014/06/why-i-only-drink-loose-tea/index.html index fa0aac92..1a4b940c 100644 --- a/2014/06/why-i-only-drink-loose-tea/index.html +++ b/2014/06/why-i-only-drink-loose-tea/index.html @@ -10,4 +10,4 @@

    Loose teas can be harder to find, but there are many great sources online. If there is a tea store in your neighbourhood, going in and selecting a few teas can be a lot of fun. Except for the very highest grades, most good teas aren’t too expensive, especially when compared to premium tea bags.

    Once awakened, I started taking a lot of pleasure in hunting down and trying new teas and brewing equipment. I have been researching and experimenting for more than a decade now, and I still feel like I’ve barely scratched the surface.

    Sometimes I am forced to drink tea from tea bags while I’m in a restaurant or visiting family. Some tea bags that are better than others, but all of them seem lacking compared to my own stash at home. It’s enough that I’ll never forget why I put in the extra effort to enjoy my cup of tea.

    -
    Infiltrating an Organization (or: Joining a New Team)
    \ No newline at end of file +
    Infiltrating an Organization (or: Joining a New Team)
    \ No newline at end of file diff --git a/2016/08/infiltrating-an-organization/index.html b/2016/08/infiltrating-an-organization/index.html index 7f2736c9..e7e59e88 100644 --- a/2016/08/infiltrating-an-organization/index.html +++ b/2016/08/infiltrating-an-organization/index.html @@ -16,4 +16,4 @@

    This is when I start fine-tuning my personal processes, and trying to resolve anything that’s still holding me back. I expect to have a good relationship with my manager by this point. I would be bringing up more serious issues earlier, but now I want to start bringing up everything else. If our relationship strong enough, this is when I would try to fix that also.

    Sometimes I never make it to this stage. I might be spending too much energy arguing, or feel like my contributions are not appreciated. If I don’t make it here within a few months, and have no clear path to improve things, I know it’s time to brush up my resume.

    4) Performing

    With good working relationships, enough context about the problem space, and all my major issues resolved, I can now focus on getting some work done.

    -
    Brewing Your Own Iced Tea
    \ No newline at end of file +
    Brewing Your Own Iced Tea
    \ No newline at end of file diff --git a/2018/06/brewing-your-own-iced-tea/index.html b/2018/06/brewing-your-own-iced-tea/index.html index 0a2bdc52..bef9549b 100644 --- a/2018/06/brewing-your-own-iced-tea/index.html +++ b/2018/06/brewing-your-own-iced-tea/index.html @@ -13,4 +13,4 @@

    Let the tea cool slowly to room temperature, then put it in the fridge to cool the rest of the way. Adding ice while it’s hot can disturb the flavour, and dilutes the tea.

    Once it’s cold, pour a glass, add ice if you like, and enjoy.

    You can experiment with different teas. Green or white tea should work, but follow their proper brewing instructions. Only black tea should be brewed with boiling water. My second favourite mix is using a plain black orange pekoe, inserting a couple springs of fresh mint after removing the tea.

    -
    Breaking Past Senior Developer
    \ No newline at end of file +
    Breaking Past Senior Developer
    \ No newline at end of file diff --git a/2021/01/breaking-past-senior-developer/index.html b/2021/01/breaking-past-senior-developer/index.html index 2e5480a9..c9f65f55 100644 --- a/2021/01/breaking-past-senior-developer/index.html +++ b/2021/01/breaking-past-senior-developer/index.html @@ -37,4 +37,4 @@

    Develop your personal brand

    I think a lot of us developers lack awareness of our personal brand, but it’s an important part of your career, and it’s importance increases the higher up you go. Make sure people want to work with you, and try to get some high-profile successes under your belt. These will all help you earn a promotion, and give you essential credibility once you get it.

    -
    How to Report a Bug
    \ No newline at end of file +
    How to Report a Bug
    \ No newline at end of file diff --git a/2023/03/How-to-Report-a-Bug/index.html b/2023/03/How-to-Report-a-Bug/index.html index cab161e2..fff3c6d4 100644 --- a/2023/03/How-to-Report-a-Bug/index.html +++ b/2023/03/How-to-Report-a-Bug/index.html @@ -36,4 +36,4 @@

    Where did you encounter the bug? (Location)

    It’s not always obvious, but sometimes companies have more than one piece of software, or more than one version in circulation.

    If you’re using a website, include the URL. If it’s a visual bug, maybe include the browser you’re using, it’s version, and the operating system you’re using it on. If it’s a mobile app, include the kind of phone you have. If the app has a version number include that too.

    -
    How to Fix a Bug
    \ No newline at end of file +
    How to Fix a Bug
    \ No newline at end of file diff --git a/2023/04/How-to-Fix-a-Bug/index.html b/2023/04/How-to-Fix-a-Bug/index.html index 7885c71b..76b54713 100644 --- a/2023/04/How-to-Fix-a-Bug/index.html +++ b/2023/04/How-to-Fix-a-Bug/index.html @@ -32,4 +32,4 @@

    Step 9: Bug Retrospective (Post-mortem)

    Once in a while I take a bit of time to reflect on the bugs I’ve encountered. How did the bug escape in the first place? Is it likely that similar bugs will be introduced again? Can I introduce tools or change processes to make this class of bug less likely to occur?

    Some organizations have a formal post mortem process for impactful issues. This is a great way to ensure a team is learning from its mistakes. I have introduced this process in a few of my teams and highly recommend it.

    Even for bugs with less impact it can be worth spending a bit of time thinking about this. It’s not always feasible to prevent some types of bugs, but as craftspeople we should be trying!

    -
    Case of the Disappearing Users
    \ No newline at end of file +
    Case of the Disappearing Users
    \ No newline at end of file diff --git a/2023/05/Case-of-the-Disappearing-Users/index.html b/2023/05/Case-of-the-Disappearing-Users/index.html index a9ad6a0b..f864292f 100644 --- a/2023/05/Case-of-the-Disappearing-Users/index.html +++ b/2023/05/Case-of-the-Disappearing-Users/index.html @@ -9,4 +9,4 @@

    I found the offending delete statement. The bug was actually a feature!

    The customer had re-installed the software at some point and couldn’t find their licence key. The software wouldn’t work without a licence unless it was put into “demonstration mode.” Demonstration mode caused users to be deleted after the trial period ended.

    We issued them a new licence key and changed the demonstration mode feature so it wouldn’t be so destructive if it ever got turned on in the future.

    -
    Is the Bug Fun?
    \ No newline at end of file +
    Is the Bug Fun?
    \ No newline at end of file diff --git a/2023/05/Is-the-Bug-Fun/index.html b/2023/05/Is-the-Bug-Fun/index.html index bc1e291b..d919bd3f 100644 --- a/2023/05/Is-the-Bug-Fun/index.html +++ b/2023/05/Is-the-Bug-Fun/index.html @@ -6,4 +6,4 @@

    There are plenty of unintended features (bugs) in games that became beloved. Attack combos were an accident in Street Fighter II, but they became so popular that they are a part of basically every fighting game now. Rocket jumps are another example. The internet is full of examples.

    Sometimes very glitchy games can be fun too, especially for a certain audience. Speed runners sometimes use glitches to lower their times. People love games for all sorts of reasons beyond just beating them and getting high scores. At the end of the day the goal of a game is to entertain more than be correct.

    The next time a bug comes across your desk, maybe ask yourself if fixing it would make your app less fun.

    -
    Sustainable Errors
    \ No newline at end of file +
    Sustainable Errors
    \ No newline at end of file diff --git a/2023/05/Polyglot-Unconference-2023/index.html b/2023/05/Polyglot-Unconference-2023/index.html index b4ece3ad..ccca3997 100644 --- a/2023/05/Polyglot-Unconference-2023/index.html +++ b/2023/05/Polyglot-Unconference-2023/index.html @@ -10,4 +10,4 @@

    A few experienced founders attended my session, and quite a few people who wanted to or had already started software companies were present too. I asked my questions, other people asked their questions, and we got a lot of great answers. I took 3 pages of notes that will absolutely be helpful in my endeavors.

    The best part of this event is learning about what other companies in town are doing, what’s working for them, and where they’ve had problems. Traditional software conferences tend to have more vendor-sponsored presentations where everything is a sales pitch. These are valuable too, but the unconference is a better way to get a balanced opinion.

    I can’t wait to attend again next year.

    -
    Importance of Alignment
    \ No newline at end of file +
    Importance of Alignment
    \ No newline at end of file diff --git a/2023/05/Sustainable-Errors/index.html b/2023/05/Sustainable-Errors/index.html index 15dcc932..4466bf84 100644 --- a/2023/05/Sustainable-Errors/index.html +++ b/2023/05/Sustainable-Errors/index.html @@ -30,4 +30,4 @@

    What About Performance?

    One common argument against throwing exceptions is that it causes a performance hit. It’s true, it does takes time to capture the stack trace, and allocating a new object on the heap isn’t free. It depends on your circumstance of course, but I think in 99% of scenarios this cost is too miniscule to matter, and certainly far cheaper than the wasted time of developers who can’t find bugs.

    If your exceptional case is something you expect to hit often inside a tight loop though, it may actually matter. The TryFunction pattern is the common alternative in .Net. The drawback is that because your return value is typically boolean you can’t easily add new failure cases as safely as you can with exceptions. You could include more information in another output parameter, but that can also impact your callers whenever the list changes. It also means every caller needs to check the function response, or even worse, they can forget to and the app can continue running in a weird state without realizing the call failed.

    What About Leaking Security Sensitive Information?

    Another argument I’ve heard against good error handling is to prevent leaking information to attackers, but I think this is mostly bad advice too. For any software that is distributed, a malicious user can easily find tools to look inside and see how it’s wired. For server-side code you should at least share the error details with yourself in your own log files. If you need to withhold information from potential hackers then do that in your global error handler.

    -
    Polyglot Unconference 2023
    \ No newline at end of file +
    Polyglot Unconference 2023
    \ No newline at end of file diff --git a/2023/06/Automating-Non-Non-Downtime-Upgrades-in-Kubernetes-with-ArgoCD/index.html b/2023/06/Automating-Non-Non-Downtime-Upgrades-in-Kubernetes-with-ArgoCD/index.html index 532804a8..5c860f6e 100644 --- a/2023/06/Automating-Non-Non-Downtime-Upgrades-in-Kubernetes-with-ArgoCD/index.html +++ b/2023/06/Automating-Non-Non-Downtime-Upgrades-in-Kubernetes-with-ArgoCD/index.html @@ -63,4 +63,4 @@

    Conclusion

    Using ArgoCD for automating the more complicated upgrade process worked well for us, even with its challenges. I would recommend this solution to others.

    Another strong reason to use ArgoCD is that it is an excellent tool to use even if you don’t need to control the synchronization process. It was a great platform for us to deploy newer Kubernetes-native applications, and it was convenient to use the same tool for everything. It also left us in a position where we could iterate gradually to a simpler deployment process with our legacy applications.

    -
    Case of the Appearing Users
    \ No newline at end of file +
    Case of the Appearing Users
    \ No newline at end of file diff --git a/2023/06/Importance-of-Alignment/index.html b/2023/06/Importance-of-Alignment/index.html index 0ffe1e07..9ffbe75a 100644 --- a/2023/06/Importance-of-Alignment/index.html +++ b/2023/06/Importance-of-Alignment/index.html @@ -15,4 +15,4 @@

    Some companies don’t see the value of keeping everyone informed. If that’s the case where you work, you will have to take matters into your own hands. At the very least, make sure you read the company emails. Ask questions when you can, and try to always understand the direction your company is going.

    Even when you have good alignment with your manager and a clear understanding of the organization’s goals, you may sometimes find yourself under a manager that isn’t well aligned themselves. Even if you are a perfect employee, the success of your team will reflect on you, and the team won’t be seen as successful if it isn’t helping the organization. The teams that are doing the best from this point of view tend to have the best bonuses and the best growth opportunities.

    It’s not always possible to control the team you work on, sometimes the only way to improve things is to leave your company entirely. Of course there are lots of factors that go into a decision like that… but if you don’t feel that you, your team, and your company are going in the same direction, or if you can’t tell, you should at least be aware that it could be hurting your opportunities to grow and advance.

    -
    Automating Non-Non-Downtime Upgrades in Kubernetes with ArgoCD
    \ No newline at end of file +
    Automating Non-Non-Downtime Upgrades in Kubernetes with ArgoCD
    \ No newline at end of file diff --git a/2023/07/Case-of-the-Appearing-Users/index.html b/2023/07/Case-of-the-Appearing-Users/index.html index 1216710b..ddcddb0e 100644 --- a/2023/07/Case-of-the-Appearing-Users/index.html +++ b/2023/07/Case-of-the-Appearing-Users/index.html @@ -10,4 +10,4 @@

    One of the (many) challenges with Access is that it is sometimes a bit too clover. It could convert a select statement into insert / update / delete statements automatically. If you navigated the form past the last row of the query (even if your query only selected a single row) it would go into creation mode.

    The form where the row was created had all the keyboard navigation shortcuts blocked, as was the standard practice, but the user was still able to trigger it. This is where the new mouse comes in. This problem occurred around the time when mice just started shipping with scroll wheels, and in Access it automatically triggered row navigation.

    We weren’t able to disable this behavior, but I was able to rewrite the query and modify the form so that a new row couldn’t be generated any more. We also updated our installation instructions to ban mice with scroll wheels in case the same problem could be triggered in any of our hundreds of other forms.

    -
    Horizontal One-on-Ones and Talking Practice
    \ No newline at end of file +
    Horizontal One-on-Ones and Talking Practice
    \ No newline at end of file diff --git a/2023/07/Design-by-Dogma-Antipattern/index.html b/2023/07/Design-by-Dogma-Antipattern/index.html index 2afdb8cc..ca087d70 100644 --- a/2023/07/Design-by-Dogma-Antipattern/index.html +++ b/2023/07/Design-by-Dogma-Antipattern/index.html @@ -23,4 +23,4 @@

    When you believe in things that you don’t understand
    Then you suffer
    Superstition ain’t the way

    – Superstition by Stevie Wonder

    -
    My Architectural Report Template
    \ No newline at end of file +
    My Architectural Report Template
    \ No newline at end of file diff --git a/2023/07/Horizontal-One-on-Ones-and-Talking-Practice/index.html b/2023/07/Horizontal-One-on-Ones-and-Talking-Practice/index.html index 01b146f0..6757bd9b 100644 --- a/2023/07/Horizontal-One-on-Ones-and-Talking-Practice/index.html +++ b/2023/07/Horizontal-One-on-Ones-and-Talking-Practice/index.html @@ -12,4 +12,4 @@

    I was fortunate to work in an environment with a lot of trust: I could speak my mind honestly, and I didn’t really need to be persuasive to make sure my ideas were heard. Even still, the better I got, the more confident I felt. Portraying confidence is important in a leadership position - if a leader looks worried it can generate more stress for those around them.

    After a few years of these meetings, I am convinced that they were a big part of my success as an architect. I’m also convinced that they’ve helped me improve as a communicator.

    Repeating similar conversation has been so valuable, that I’ve started having practice conversations just for the sake of it. Rough notes and research is still my preferred place to start, but this type of preparation starts to have diminishing returns after a while. If I really need to nail a conversation, a practice conversation is an efficient way to improve my messages. All it takes is a bit of time from a trusted colleague, or if that’s not possible, a rubber duck can do the job too.

    -
    Design by Dogma Antipattern
    \ No newline at end of file +
    Design by Dogma Antipattern
    \ No newline at end of file diff --git a/2023/08/My-Architectural-Report-Template/index.html b/2023/08/My-Architectural-Report-Template/index.html index 43e98b08..312709d9 100644 --- a/2023/08/My-Architectural-Report-Template/index.html +++ b/2023/08/My-Architectural-Report-Template/index.html @@ -92,4 +92,4 @@

    Template

    I’ve created a standalone page with the example from this post so you can use it as a template for your own work. You can find it under Resources, Architectural Report Template. If you do use it I suggest replacing the contents before sharing it to prevent any embarrassment.

    Acknowledgements

    This template was inspired by the Decision record template by Michael Nygard which I also recommend for its intended purpose.

    If you want to know more about how to write architectural reports, gather information, or validate designs, I highly recommend the book Design It!: From Programmer to Software Architect by Michael Keeling. I learned a lot from this book, and have referred to its contents many times since.

    -
    Regarding Test Coverage Targets
    \ No newline at end of file +
    Regarding Test Coverage Targets
    \ No newline at end of file diff --git a/2023/08/Regarding-Test-Coverage-Targets/index.html b/2023/08/Regarding-Test-Coverage-Targets/index.html index 78630eae..ba8d2921 100644 --- a/2023/08/Regarding-Test-Coverage-Targets/index.html +++ b/2023/08/Regarding-Test-Coverage-Targets/index.html @@ -16,4 +16,4 @@

    You could make an argument that you should avoid architectures that encourage lots of boring boilerplate code. I agree with that idea, but in my experience most teams are not mature enough to design systems that prevent it. It is easy to follow simple service-business-repository patterns blindly, and to be honest, for most software this is good enough.

    Again: I do think unit tests are a good thing, and good test coverage is essential to get good value from them, but unit tests also have a cost. Unit tests often need to be changed when code is being changed. If you have lots of low-value tests testing lots of simple methods, you can quickly get overwhelmed trying to make non-trivial changes. Unit tests are supposed to make it safer to go faster… but poorly written tests can do the exact opposite too.

    Of course there is an exception to every rule. If you are writing the software for my bank, or for medical equipment, or for self driving cars, please enforce 100% coverage and use several other tools to enure an extremely high quality. For most of us though, not all of the tests are actually worth the effort of writing them, and I don’t want to edit the coverage percentage every time I make a change.

    -
    Case of the Slow Matchmaking Routine
    \ No newline at end of file +
    Case of the Slow Matchmaking Routine
    \ No newline at end of file diff --git a/2023/09/Case-of-the-Slow-Matchmaking-Routine/index.html b/2023/09/Case-of-the-Slow-Matchmaking-Routine/index.html index deecc0d2..4ac22567 100644 --- a/2023/09/Case-of-the-Slow-Matchmaking-Routine/index.html +++ b/2023/09/Case-of-the-Slow-Matchmaking-Routine/index.html @@ -11,4 +11,4 @@

    The problem originated in a database query we used to find matches. It used a cartesian join, which takes exponentially longer to complete as more rows are added (O(n²) complexity). At some queue length, the processing time increases from milliseconds to seconds, and then it quickly increases from seconds to minutes. It also didn’t help that our contrived load test meant thousands of users were all attempting to make matches with the same power rating, thus making it harder to distinguish suitable matches.

    After all the time it took to find the problem, it only took a day to fix it. I replaced the algorithm with one that processed matches linearly, giving it O(n) complexity.

    About a week later, I got an email confirming that the issue was fixed. Since the report came in overnight, it was the first thing I read in the morning. It was exhilarating, but the day is still bittersweet in my memory. About an hour later, I attended a last-minute team-wide meeting where we were all let go. The game was never released.

    -
    Choosing Powerful Names
    \ No newline at end of file +
    Choosing Powerful Names
    \ No newline at end of file diff --git a/2023/09/Choosing-Powerful-Names/index.html b/2023/09/Choosing-Powerful-Names/index.html index c0c1a039..7784f540 100644 --- a/2023/09/Choosing-Powerful-Names/index.html +++ b/2023/09/Choosing-Powerful-Names/index.html @@ -21,4 +21,4 @@

    Being respectful of all cultures is becoming more important as the internet continues connecting the whole world together. Some words can have unexpected or unpleasant connotations for people who live (or have lived) in other cultures. Some words commonly used in Western culture should be retired now. Names from nature, science, geography, or popular fiction are usually safe. References to religions, cultures, or historical figures or groups should be avoided.

    After focusing on a name for hours, it’s not uncommon to develop tunnel vision. Before pasting a name all over my files and objects, I like to get an external perspective. Asking a boss or a peer can save a lot of time if your name isn’t quite as great as you thought.

    Once the name is set, all that’s left is living up to it.

    -
    Getting Unstuck Without a Rubber Duck
    \ No newline at end of file +
    Getting Unstuck Without a Rubber Duck
    \ No newline at end of file diff --git a/2023/10/Getting-Unstuck-Without-a-Rubber-Duck/index.html b/2023/10/Getting-Unstuck-Without-a-Rubber-Duck/index.html index 5e967ddb..8f32e729 100644 --- a/2023/10/Getting-Unstuck-Without-a-Rubber-Duck/index.html +++ b/2023/10/Getting-Unstuck-Without-a-Rubber-Duck/index.html @@ -17,4 +17,4 @@

    Confirm the problem is important

    If you are really, really, really stuck on a problem, maybe there is a good reason. It may be beyond your current capability. It may also not be important enough to justify more effort. A quick chat with your manager shouldn’t hurt. If it is dangerous to ask your manager, you may want to find a new manager, but that’s a topic for another post.

    Ask for help

    If your problem is important enough, and you’ve made an effort and failed to get yourself unstuck, it’s not inappropriate to ask for help. Pair programming is an excellent technique for tackling complicated problems.

    Searching or asking online for an answer could also help, but I’ve not personally had much luck here. Your results may vary.

    -
    Review: Grammarly Premium
    \ No newline at end of file +
    Review: Grammarly Premium
    \ No newline at end of file diff --git a/2023/10/Review-Grammarly-Premium/index.html b/2023/10/Review-Grammarly-Premium/index.html index 977a8c3e..e1341ca9 100644 --- a/2023/10/Review-Grammarly-Premium/index.html +++ b/2023/10/Review-Grammarly-Premium/index.html @@ -21,4 +21,4 @@

    I don’t use any of the apps or plugins now. I found them to be exceedingly intrusive. The Windows app added a giant green G button that covered text boxes, and a lot of times it was covering things I wanted to see. The VS Code plugin covered my rough drafts in red and blue lines, and my programmer muscle memory couldn’t just ignore them. The browser plugin was the least intrusive, but still too noisy and often not helpful.

    Now I use Grammarly primarily via its web interface, and only as a final pass at the end of the editing process.

    The technology is promising, and it has helped a bit with some of the more mechanical editing I do. Until it gets a lot better, though, I will only be using it for very specific tasks. I’d have to see some pretty major improvements before I’d consider Grammarly Premium again.

    -
    \ No newline at end of file +
    This Blog: Hexo-generated static site hosted on GitHub Pages
    \ No newline at end of file diff --git a/2023/11/This-Blog-Hexo-generated-static-site-hosted-on-GitHub-Pages/index.html b/2023/11/This-Blog-Hexo-generated-static-site-hosted-on-GitHub-Pages/index.html new file mode 100644 index 00000000..c2f4468b --- /dev/null +++ b/2023/11/This-Blog-Hexo-generated-static-site-hosted-on-GitHub-Pages/index.html @@ -0,0 +1,45 @@ +This Blog: Hexo-generated static site hosted on GitHub Pages | Jesse Builds Software

    This Blog: Hexo-generated static site hosted on GitHub Pages

    A couple of years ago I switched this blog from a WordPress site hosted on GoDaddy to a statically generated site. The new setup is faster, more secure, and cheaper to operate. And it was easy to do!

    +

    Static vs Dynamic websites

    WordPress is a very popular blogging platform. You can use it hosted on WordPress.com, or any number of other web providers that offer it. Because it’s open source, you can also host it yourself easily. In my case, I had a virtual server running in GoDaddy where I maintained the installation myself.

    +

    Hexo is a static website generator. When you want to publish changes, you run a command that causes it to spit out a bunch of static html, css, and so on that you can then host anywhere you like. These tools can store the raw content any way they like, but Hexo and all the other generators I’ve played with use a directory structure with simple markdown files.

    +

    Dynamic websites are generated by software running on the web server. Ignoring any caches or other optimizations, every web request triggers a call to the running application, which in turn makes database requests and invokes any loaded plugins before a page gets sent back to the browser. For medium-sized websites, this isn’t noticeable because the server will be constantly warmed up and ready to respond. For very small websites like mine that go idle, a fresh web request can take more than 30 seconds to respond while everything is initialized. This is not ideal.

    +

    Static websites have fantastic performance. The server only has to return the pre-computed content, and the providers that do this at scale do it very well. Even if I only get one hit a month, that page will still load very quickly, likely even faster than a warmed-up WordPress instance. It depends on the hosting platform, but static websites can typically also handle massive traffic spikes without any extra effort, and at a much lower cost. Your small self-hosted WordPress site, by comparison, could fall over when one of your posts goes viral.

    +

    Another benefit to static websites is their security. Because it’s just plain files, there is much less attack surface. As long as your account is secure, it should be impossible for an attacker to modify the content. Even if someone did, the content and site generator can be kept separate, so the site can easily be replaced with fresh, clean content. With a WordPress site, you have the running server, the WordPress software, and the database all running in the cloud. They are prone to bugs and attacks like any other cloud infrastructure, and they need to be updated regularly to keep them secure.

    +

    Comments and contact pages on a static website

    The biggest drawback to static websites is that they are, well, static. There are a few tricks you can use, but some features are much more difficult to implement. For a simple blog like mine, this wasn’t a problem.

    +

    Comments are a common blog feature that is trivial for a dynamic site to implement. For this blog, I recently set up utterances. It uses GitHub Issues (in a free public repository) like a database to store comments, and retrieves / renders them on each page with a bit of client-side javascript. This way I don’t need to run hexo generate every time someone posts a comment.

    +

    A reader does need a GitHub account to add a comment with this system, but this seems like a reasonable limitation given my audience. There are other static-capable comment systems available, each with different styles and storage mechanisms. There are commercial offerings too, which may or may not be more expensive than using a hosted WordPress site for your blog to begin with.

    +

    I don’t have a contact form on this site, but I easily set one up on another static website using getform. For the frequency of messages I expect there, it should also be free.

    +

    It gets unfortunately difficult to push much further than this on a static website. Some things can be done with client-side javascript or advanced application firewalls, but these can get complicated and/or expensive pretty quickly. It may be worth it if you want the scalability advantages of a static site, but if you just want a cheap website with a couple of dynamic features, a hosted WordPress site may be your best bet.

    +

    HTTPS and custom domains

    The main reason I left WordPress on GoDaddy was the desire to move my blog to HTTPS. Nowadays it’s not that hard to get a free certificate from Let’s Encrypt, but the certificates don’t last very long, so it’s best to automate the process. At the time I changed, automating this wasn’t possible with the package I had from GoDaddy. I could have changed to a more expensive virtual machine option or bought a proper certificate. I went with option 3 instead.

    +

    HTTPS requires a certificate, and the certificate has to contain the domain name of the website you’re using it for. That means that you need a custom certificate to go with your custom domain name. The good news is that many hosting services can procure certificates on your behalf, and some will do it for free.

    +

    GitHub Pages is one of these services, and it was easy to set up. There were a couple of steps necessary so they could validate that I had control of the domain, but now they just take care of it for me. They can also provide redirects from HTTP to HTTPS, and from www to the apex website. GitHub Pages has good documentation if you want to set this up for yourself.

    +

    Price of static websites

    Because GitHub Pages is free (for public repositories, at the time of this writing), the only thing I’m paying for is the domain name and the DNS service, both of which I get from AWS. The .ca domain costs $13 USD per year, and the Route53 hosted zone costs me $0.90 USD per month (the minimum possible since I don’t exceed the initial usage limits). This is much less than I was paying GoDaddy for a virtual server.

    +

    There are a few equivalents to GitHub Pages that are also free. There are also cheaper options than AWS for domain registration and DNS.

    +

    If you don’t want the hassle of setting this all up, there are lots of hosted WordPress solutions around, and other blogging/website platforms too. Some of these are even free, but the free ones each have their own limitations. I haven’t searched exhaustively, but I don’t know of any free options that support custom domains and control over advertising.

    +

    Creating, editing, and publishing posts

    It can take a bit of effort to get a static site generator set up and configured with a nice theme, but things get easier once you have it all working. You still need to run a few commands in a terminal, which will be too much for some people. Even the mildly technically challenged should be able to keep themselves going with a few basic commands written down. This is what I use:

    +

    When I want to start a new post, I use the hexo new command:

    +
    1
    hexo new draft 'This Blog: Hexo-generated static site hosted on GitHub Pages'
    + +

    This command generates a markdown file in the draft folder with some initial “front-matter”. I can then edit the content in any text editor I wish. These days I use VS Code. Markdown is a very simple mostly-text format for making pages that is very easy to learn. Front-matter is a bit of data about the page that go at the top of the document such as the title, publish date, tags, categories, and so on. You can see an example of what this looks like in the source for the Hexo documentation.

    +

    If I want to see how a page will look (for example: if I’m using some tricky markdown syntax), I use hexo server --drafts. This hosts a website on my computer that looks exactly like the blog will when I publish it. I also sometimes use commands like hexo list tag --draft to make sure I’m using the same tags across multiple posts.

    +

    Once I’m happy with a post, I run the hexo publish command:

    +
    1
    hexo publish 'This Blog: Hexo-generated static site hosted on GitHub Pages'
    + +

    The main thing this does is move the file and its attachments from the drafts folder into the posts folder. It also renames the file and updates the front-matter with the published date and time. You could do this manually, but the command is quick and reliable. Then I need to re-generate the static content for publishing:

    +
    1
    hexo generate
    + +

    This goes through all the content files and configuration and generates everything needed for the website. The new post gets its own folder and html file, but it will also cause changes to the front page and a number of peripheral pages. The theme I’m using supports paging, so it also pushes the post at the bottom of the front page back to page 2, the bottom post from page 2 to page 3, and so on. There are also the tag, category, and archive pages that get updated similarly. It might seem like a lot, but I assure you, the software doesn’t mind.

    +

    After this, it’s a simple matter of uploading the content to my hosting provider. In the case of GitHub Pages, this means copying it to the website repository, commiting, and then pushing the branch. Nowadays I use a PowerShell script to generate, copy, commit, and push in a single step.

    +

    I use Git and GitHub to manage my hexo folders because I am very comfortable with these tools. This isn’t necessary though. You could just as easily store your hexo files on a cloud drive. You could store it on your local hard drive too, but I highly recommend using somewhere that has automatic backups and some form of change history.

    +

    Because I’m using drafts for incomplete posts, I commit and push any changes I’ve made regularly. The drafts aren’t included in the generated site, so I can keep a few sitting around while publishing other posts or changes. I originally went a little bonkers with a branch-per-post but found it made my process unnecessarily complicated.

    +

    You can simplify publishing your site further. Some static page providers can automatically run the generate step for you. I chose not to do this for my blog because I didn’t want my drafts and their edit history to be visible in the public repository (as a public repository is required to use Pages for free). There are other options that don’t have this limitation.

    +

    Converting from WordPress to Hexo

    Most of the work of migrating was achieved using a WordPress export file and the Hexo migration tool:

    +
    1
    hexo migrate wordpress wordpress-export.xml --paragraph-fix --import-image original
    + +

    It took a bit of fiddling after this to get everything working perfectly. I had some issues with my code snippets (I was using a gist plugin in WordPress), and some of the attachment references didn’t work with my theme. The nice thing about working with markdown files is that it was really easy to search for patterns once I found them. With Git and branches, I could also quickly test fixes and revert them if they didn’t work.

    +

    I didn’t have a lot of content when I made the switch, but it only took me a few hours.

    +

    Summary

    Static websites can be cheaper, perform better, and require less maintenance than self-hosted options. They have their limitations, but for a simple blog like mine, it was an easy choice that I’m still happy with.

    +
    \ No newline at end of file diff --git a/about/index.html b/about/index.html index e7ac143d..98d50f18 100644 --- a/about/index.html +++ b/about/index.html @@ -465,4 +465,4 @@ .fad.fa-inverse { color: #fff; } -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2010/07/index.html b/archives/2010/07/index.html index c6a7cf57..fc6198d0 100644 --- a/archives/2010/07/index.html +++ b/archives/2010/07/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2010/08/index.html b/archives/2010/08/index.html index aa452446..ebd32932 100644 --- a/archives/2010/08/index.html +++ b/archives/2010/08/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2010/09/index.html b/archives/2010/09/index.html index b8ea5f82..d856e77f 100644 --- a/archives/2010/09/index.html +++ b/archives/2010/09/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2010/10/index.html b/archives/2010/10/index.html index 579631a7..e0d3722f 100644 --- a/archives/2010/10/index.html +++ b/archives/2010/10/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2010/11/index.html b/archives/2010/11/index.html index a8501c7e..8b7b6b2a 100644 --- a/archives/2010/11/index.html +++ b/archives/2010/11/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2010/12/index.html b/archives/2010/12/index.html index 46040e65..6a3d0826 100644 --- a/archives/2010/12/index.html +++ b/archives/2010/12/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2010/index.html b/archives/2010/index.html index 5d1e7de8..9d732923 100644 --- a/archives/2010/index.html +++ b/archives/2010/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2010/page/2/index.html b/archives/2010/page/2/index.html index 1320d50f..35efb9dd 100644 --- a/archives/2010/page/2/index.html +++ b/archives/2010/page/2/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2011/01/index.html b/archives/2011/01/index.html index 8b543263..ea33fc8e 100644 --- a/archives/2011/01/index.html +++ b/archives/2011/01/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2011/04/index.html b/archives/2011/04/index.html index 143acf24..afecd15e 100644 --- a/archives/2011/04/index.html +++ b/archives/2011/04/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -

    2011

    \ No newline at end of file +

    2011

    \ No newline at end of file diff --git a/archives/2011/05/index.html b/archives/2011/05/index.html index 70e8120b..f0625942 100644 --- a/archives/2011/05/index.html +++ b/archives/2011/05/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2011/06/index.html b/archives/2011/06/index.html index 7ed6233d..04aed493 100644 --- a/archives/2011/06/index.html +++ b/archives/2011/06/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -

    2011

    \ No newline at end of file +

    2011

    \ No newline at end of file diff --git a/archives/2011/08/index.html b/archives/2011/08/index.html index dad61de8..44e9017c 100644 --- a/archives/2011/08/index.html +++ b/archives/2011/08/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2011/10/index.html b/archives/2011/10/index.html index 1aad66ea..e7d7ac1b 100644 --- a/archives/2011/10/index.html +++ b/archives/2011/10/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2011/index.html b/archives/2011/index.html index 230f7b02..5b4a8d05 100644 --- a/archives/2011/index.html +++ b/archives/2011/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2012/03/index.html b/archives/2012/03/index.html index 1efaf809..3c81b281 100644 --- a/archives/2012/03/index.html +++ b/archives/2012/03/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -

    2012

    \ No newline at end of file +

    2012

    \ No newline at end of file diff --git a/archives/2012/04/index.html b/archives/2012/04/index.html index 00e4c902..f5b56f2d 100644 --- a/archives/2012/04/index.html +++ b/archives/2012/04/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2012/index.html b/archives/2012/index.html index 7284a2ec..3a74a86e 100644 --- a/archives/2012/index.html +++ b/archives/2012/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2013/06/index.html b/archives/2013/06/index.html index 7a2e06e9..193e8be2 100644 --- a/archives/2013/06/index.html +++ b/archives/2013/06/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2013/index.html b/archives/2013/index.html index 7a2e06e9..193e8be2 100644 --- a/archives/2013/index.html +++ b/archives/2013/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2014/04/index.html b/archives/2014/04/index.html index 05fad480..e4a0c735 100644 --- a/archives/2014/04/index.html +++ b/archives/2014/04/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2014/06/index.html b/archives/2014/06/index.html index 5f8b729e..31f27fe9 100644 --- a/archives/2014/06/index.html +++ b/archives/2014/06/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2014/index.html b/archives/2014/index.html index 66c82461..f4b4868b 100644 --- a/archives/2014/index.html +++ b/archives/2014/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2016/08/index.html b/archives/2016/08/index.html index e74147a3..3334fd0a 100644 --- a/archives/2016/08/index.html +++ b/archives/2016/08/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2016/index.html b/archives/2016/index.html index e74147a3..3334fd0a 100644 --- a/archives/2016/index.html +++ b/archives/2016/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2018/06/index.html b/archives/2018/06/index.html index 6462980f..b3617c84 100644 --- a/archives/2018/06/index.html +++ b/archives/2018/06/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2018/index.html b/archives/2018/index.html index 6462980f..b3617c84 100644 --- a/archives/2018/index.html +++ b/archives/2018/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2021/01/index.html b/archives/2021/01/index.html index 20c4c05d..530a75fe 100644 --- a/archives/2021/01/index.html +++ b/archives/2021/01/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2021/index.html b/archives/2021/index.html index 20c4c05d..530a75fe 100644 --- a/archives/2021/index.html +++ b/archives/2021/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2023/03/index.html b/archives/2023/03/index.html index 0a64606e..3d78e138 100644 --- a/archives/2023/03/index.html +++ b/archives/2023/03/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -

    2023

    \ No newline at end of file +

    2023

    \ No newline at end of file diff --git a/archives/2023/04/index.html b/archives/2023/04/index.html index 00431859..51ee36c5 100644 --- a/archives/2023/04/index.html +++ b/archives/2023/04/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -

    2023

    \ No newline at end of file +

    2023

    \ No newline at end of file diff --git a/archives/2023/05/index.html b/archives/2023/05/index.html index 26bc5672..fe6a5f57 100644 --- a/archives/2023/05/index.html +++ b/archives/2023/05/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2023/06/index.html b/archives/2023/06/index.html index b09cf312..dcdd14cf 100644 --- a/archives/2023/06/index.html +++ b/archives/2023/06/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2023/07/index.html b/archives/2023/07/index.html index 72eac7c7..9e2ff494 100644 --- a/archives/2023/07/index.html +++ b/archives/2023/07/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2023/08/index.html b/archives/2023/08/index.html index 7d957590..9c7c0ec7 100644 --- a/archives/2023/08/index.html +++ b/archives/2023/08/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2023/09/index.html b/archives/2023/09/index.html index c41031ee..9b0b1530 100644 --- a/archives/2023/09/index.html +++ b/archives/2023/09/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2023/10/index.html b/archives/2023/10/index.html index 3f6b2f8d..ffc57a28 100644 --- a/archives/2023/10/index.html +++ b/archives/2023/10/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2023/11/index.html b/archives/2023/11/index.html new file mode 100644 index 00000000..39c10a72 --- /dev/null +++ b/archives/2023/11/index.html @@ -0,0 +1,5 @@ +Archive | Jesse Builds Software
    \ No newline at end of file diff --git a/archives/2023/index.html b/archives/2023/index.html index 01098b59..20107d1f 100644 --- a/archives/2023/index.html +++ b/archives/2023/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2023/page/2/index.html b/archives/2023/page/2/index.html index 6976c3a3..8abb0774 100644 --- a/archives/2023/page/2/index.html +++ b/archives/2023/page/2/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/2023/page/3/index.html b/archives/2023/page/3/index.html index 72e2d104..dd9f58f1 100644 --- a/archives/2023/page/3/index.html +++ b/archives/2023/page/3/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/index.html b/archives/index.html index df0b11e6..dde68b6c 100644 --- a/archives/index.html +++ b/archives/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/page/2/index.html b/archives/page/2/index.html index 80d9773a..0e4a0f40 100644 --- a/archives/page/2/index.html +++ b/archives/page/2/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/page/3/index.html b/archives/page/3/index.html index 12f9d2fc..7abcd007 100644 --- a/archives/page/3/index.html +++ b/archives/page/3/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/page/4/index.html b/archives/page/4/index.html index ee2dab24..bee1e385 100644 --- a/archives/page/4/index.html +++ b/archives/page/4/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/page/5/index.html b/archives/page/5/index.html index 17cbbb66..60b00049 100644 --- a/archives/page/5/index.html +++ b/archives/page/5/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/archives/page/6/index.html b/archives/page/6/index.html index 92075ede..d91eeb9c 100644 --- a/archives/page/6/index.html +++ b/archives/page/6/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/atom.xml b/atom.xml index e0bda25e..ede8095e 100644 --- a/atom.xml +++ b/atom.xml @@ -6,7 +6,7 @@ - 2023-10-19T15:50:33.000Z + 2023-11-01T17:34:32.603Z https://jessemcdowell.ca/ @@ -16,6 +16,36 @@ Hexo + + This Blog: Hexo-generated static site hosted on GitHub Pages + + https://jessemcdowell.ca/2023/11/This-Blog-Hexo-generated-static-site-hosted-on-GitHub-Pages/ + 2023-11-01T17:34:32.000Z + 2023-11-01T17:34:32.603Z + + A couple of years ago I switched this blog from a WordPress site hosted on GoDaddy to a statically generated site. The new setup is faster, more secure, and cheaper to operate. And it was easy to do!

    Static vs Dynamic websites

    WordPress is a very popular blogging platform. You can use it hosted on WordPress.com, or any number of other web providers that offer it. Because it’s open source, you can also host it yourself easily. In my case, I had a virtual server running in GoDaddy where I maintained the installation myself.

    Hexo is a static website generator. When you want to publish changes, you run a command that causes it to spit out a bunch of static html, css, and so on that you can then host anywhere you like. These tools can store the raw content any way they like, but Hexo and all the other generators I’ve played with use a directory structure with simple markdown files.

    Dynamic websites are generated by software running on the web server. Ignoring any caches or other optimizations, every web request triggers a call to the running application, which in turn makes database requests and invokes any loaded plugins before a page gets sent back to the browser. For medium-sized websites, this isn’t noticeable because the server will be constantly warmed up and ready to respond. For very small websites like mine that go idle, a fresh web request can take more than 30 seconds to respond while everything is initialized. This is not ideal.

    Static websites have fantastic performance. The server only has to return the pre-computed content, and the providers that do this at scale do it very well. Even if I only get one hit a month, that page will still load very quickly, likely even faster than a warmed-up WordPress instance. It depends on the hosting platform, but static websites can typically also handle massive traffic spikes without any extra effort, and at a much lower cost. Your small self-hosted WordPress site, by comparison, could fall over when one of your posts goes viral.

    Another benefit to static websites is their security. Because it’s just plain files, there is much less attack surface. As long as your account is secure, it should be impossible for an attacker to modify the content. Even if someone did, the content and site generator can be kept separate, so the site can easily be replaced with fresh, clean content. With a WordPress site, you have the running server, the WordPress software, and the database all running in the cloud. They are prone to bugs and attacks like any other cloud infrastructure, and they need to be updated regularly to keep them secure.

    Comments and contact pages on a static website

    The biggest drawback to static websites is that they are, well, static. There are a few tricks you can use, but some features are much more difficult to implement. For a simple blog like mine, this wasn’t a problem.

    Comments are a common blog feature that is trivial for a dynamic site to implement. For this blog, I recently set up utterances. It uses GitHub Issues (in a free public repository) like a database to store comments, and retrieves / renders them on each page with a bit of client-side javascript. This way I don’t need to run hexo generate every time someone posts a comment.

    A reader does need a GitHub account to add a comment with this system, but this seems like a reasonable limitation given my audience. There are other static-capable comment systems available, each with different styles and storage mechanisms. There are commercial offerings too, which may or may not be more expensive than using a hosted WordPress site for your blog to begin with.

    I don’t have a contact form on this site, but I easily set one up on another static website using getform. For the frequency of messages I expect there, it should also be free.

    It gets unfortunately difficult to push much further than this on a static website. Some things can be done with client-side javascript or advanced application firewalls, but these can get complicated and/or expensive pretty quickly. It may be worth it if you want the scalability advantages of a static site, but if you just want a cheap website with a couple of dynamic features, a hosted WordPress site may be your best bet.

    HTTPS and custom domains

    The main reason I left WordPress on GoDaddy was the desire to move my blog to HTTPS. Nowadays it’s not that hard to get a free certificate from Let’s Encrypt, but the certificates don’t last very long, so it’s best to automate the process. At the time I changed, automating this wasn’t possible with the package I had from GoDaddy. I could have changed to a more expensive virtual machine option or bought a proper certificate. I went with option 3 instead.

    HTTPS requires a certificate, and the certificate has to contain the domain name of the website you’re using it for. That means that you need a custom certificate to go with your custom domain name. The good news is that many hosting services can procure certificates on your behalf, and some will do it for free.

    GitHub Pages is one of these services, and it was easy to set up. There were a couple of steps necessary so they could validate that I had control of the domain, but now they just take care of it for me. They can also provide redirects from HTTP to HTTPS, and from www to the apex website. GitHub Pages has good documentation if you want to set this up for yourself.

    Price of static websites

    Because GitHub Pages is free (for public repositories, at the time of this writing), the only thing I’m paying for is the domain name and the DNS service, both of which I get from AWS. The .ca domain costs $13 USD per year, and the Route53 hosted zone costs me $0.90 USD per month (the minimum possible since I don’t exceed the initial usage limits). This is much less than I was paying GoDaddy for a virtual server.

    There are a few equivalents to GitHub Pages that are also free. There are also cheaper options than AWS for domain registration and DNS.

    If you don’t want the hassle of setting this all up, there are lots of hosted WordPress solutions around, and other blogging/website platforms too. Some of these are even free, but the free ones each have their own limitations. I haven’t searched exhaustively, but I don’t know of any free options that support custom domains and control over advertising.

    Creating, editing, and publishing posts

    It can take a bit of effort to get a static site generator set up and configured with a nice theme, but things get easier once you have it all working. You still need to run a few commands in a terminal, which will be too much for some people. Even the mildly technically challenged should be able to keep themselves going with a few basic commands written down. This is what I use:

    When I want to start a new post, I use the hexo new command:

    1
    hexo new draft 'This Blog: Hexo-generated static site hosted on GitHub Pages'

    This command generates a markdown file in the draft folder with some initial “front-matter”. I can then edit the content in any text editor I wish. These days I use VS Code. Markdown is a very simple mostly-text format for making pages that is very easy to learn. Front-matter is a bit of data about the page that go at the top of the document such as the title, publish date, tags, categories, and so on. You can see an example of what this looks like in the source for the Hexo documentation.

    If I want to see how a page will look (for example: if I’m using some tricky markdown syntax), I use hexo server --drafts. This hosts a website on my computer that looks exactly like the blog will when I publish it. I also sometimes use commands like hexo list tag --draft to make sure I’m using the same tags across multiple posts.

    Once I’m happy with a post, I run the hexo publish command:

    1
    hexo publish 'This Blog: Hexo-generated static site hosted on GitHub Pages'

    The main thing this does is move the file and its attachments from the drafts folder into the posts folder. It also renames the file and updates the front-matter with the published date and time. You could do this manually, but the command is quick and reliable. Then I need to re-generate the static content for publishing:

    1
    hexo generate

    This goes through all the content files and configuration and generates everything needed for the website. The new post gets its own folder and html file, but it will also cause changes to the front page and a number of peripheral pages. The theme I’m using supports paging, so it also pushes the post at the bottom of the front page back to page 2, the bottom post from page 2 to page 3, and so on. There are also the tag, category, and archive pages that get updated similarly. It might seem like a lot, but I assure you, the software doesn’t mind.

    After this, it’s a simple matter of uploading the content to my hosting provider. In the case of GitHub Pages, this means copying it to the website repository, commiting, and then pushing the branch. Nowadays I use a PowerShell script to generate, copy, commit, and push in a single step.

    I use Git and GitHub to manage my hexo folders because I am very comfortable with these tools. This isn’t necessary though. You could just as easily store your hexo files on a cloud drive. You could store it on your local hard drive too, but I highly recommend using somewhere that has automatic backups and some form of change history.

    Because I’m using drafts for incomplete posts, I commit and push any changes I’ve made regularly. The drafts aren’t included in the generated site, so I can keep a few sitting around while publishing other posts or changes. I originally went a little bonkers with a branch-per-post but found it made my process unnecessarily complicated.

    You can simplify publishing your site further. Some static page providers can automatically run the generate step for you. I chose not to do this for my blog because I didn’t want my drafts and their edit history to be visible in the public repository (as a public repository is required to use Pages for free). There are other options that don’t have this limitation.

    Converting from WordPress to Hexo

    Most of the work of migrating was achieved using a WordPress export file and the Hexo migration tool:

    1
    hexo migrate wordpress wordpress-export.xml --paragraph-fix --import-image original

    It took a bit of fiddling after this to get everything working perfectly. I had some issues with my code snippets (I was using a gist plugin in WordPress), and some of the attachment references didn’t work with my theme. The nice thing about working with markdown files is that it was really easy to search for patterns once I found them. With Git and branches, I could also quickly test fixes and revert them if they didn’t work.

    I didn’t have a lot of content when I made the switch, but it only took me a few hours.

    Summary

    Static websites can be cheaper, perform better, and require less maintenance than self-hosted options. They have their limitations, but for a simple blog like mine, it was an easy choice that I’m still happy with.

    ]]>
    + + + + + <p>A couple of years ago I switched this blog from a WordPress site hosted on GoDaddy to a statically generated site. The new setup is faste + + + + + + + + + + + + + + + +
    + Review: Grammarly Premium diff --git a/categories/projects/Themis/index.html b/categories/projects/Themis/index.html index 98779c99..18ee83ad 100644 --- a/categories/projects/Themis/index.html +++ b/categories/projects/Themis/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/categories/projects/index.html b/categories/projects/index.html index 919e9b8c..20803b82 100644 --- a/categories/projects/index.html +++ b/categories/projects/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/categories/uncategorized/index.html b/categories/uncategorized/index.html index 499f3c98..fd913c17 100644 --- a/categories/uncategorized/index.html +++ b/categories/uncategorized/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/index.html b/index.html index d5a1d4ec..3fda50cb 100644 --- a/index.html +++ b/index.html @@ -2,9 +2,9 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -

    Review: Grammarly Premium

    I spend a fair bit of time working on this blog. More than I probably should given my unimpressive view metrics. It does help me to crystalize my thoughts and practice articulating points that are important to me, but I’m spending an awful lot of time doing it. Ultimately, I write because I enjoy writing. I just wish I could spend less time per post. +

    This Blog: Hexo-generated static site hosted on GitHub Pages

    A couple of years ago I switched this blog from a WordPress site hosted on GoDaddy to a statically generated site. The new setup is faster, more secure, and cheaper to operate. And it was easy to do! +Static vs Dynamic websitesWordPress is a very popular blogging platform. You can use it hosted on WordPress.com, or any number of other web providers that offer it. Because it’s open source, you can a...

    Read More

    Review: Grammarly Premium

    I spend a fair bit of time working on this blog. More than I probably should given my unimpressive view metrics. It does help me to crystalize my thoughts and practice articulating points that are important to me, but I’m spending an awful lot of time doing it. Ultimately, I write because I enjoy writing. I just wish I could spend less time per post. For a while there I was getting hammered by ads...

    Read More

    Getting Unstuck Without a Rubber Duck

    Building software is a mostly creative endeavour, and as such, it sometimes resists progress. No matter how hard you try to push forward, if you are truly stuck, continuing on the same path is unlikely to work. Fortunately, there are a few different tricks you can use to get going again. Take a restThe easiest way I’ve found to get back on track is to take a break. When in the office this was ofte...

    Read More

    Choosing Powerful Names

    A junior developer needs to strengthen their technical skills to advance. An intermediate developer needs to strengthen their organizational skills to advance. Senior developers need to master these and also demonstrate that they can move multiple teams forward together. Influencing people (and especially developers) is no easy task, but a positive reputation can do a lot of the heavy lifting. One...

    Read More

    Case of the Slow Matchmaking Routine

    The most challenging bug I’ve ever fixed was a performance issue in a matchmaking routine. Matchmaking is the process of finding players to compete against each other in a video game. An excellent matchmaking algorithm doesn’t just stick players together randomly; it tries to make the game more fun by balancing power levels and preventing anyone from waiting too long for a match. About six weeks b...

    Read More

    Regarding Test Coverage Targets

    Unit tests are undeniably a good thing, but you only realize the full benefits of them when you have enough tests that you can make changes with confidence. If you can make a change, run your tests, and be comfortable enough to ship your changes, then you and your team can get work done much faster. More drastic changes to the shared code become feasible. Life gets better. -It makes sense then that...

    Read More

    My Architectural Report Template

    As an architect I’ve been asked to answer a lot of hard questions. I used to waste time figuring out how to structure my answers, preventing me from getting into a good flow sooner. Now I have a simple template that is easy to use, easy to read, and saves me that wasted time up front. -This template works for simple reports that are only a couple of pages, but can easily be adjusted or expanded for...

    Read More

    \ No newline at end of file +It makes sense then that...

    Read More

    \ No newline at end of file diff --git a/licence/index.html b/licence/index.html index d0071792..3a0fb78b 100644 --- a/licence/index.html +++ b/licence/index.html @@ -11,4 +11,4 @@

    \ No newline at end of file +
    \ No newline at end of file diff --git a/mysterysolver/index.html b/mysterysolver/index.html index 60818bae..de0f1329 100644 --- a/mysterysolver/index.html +++ b/mysterysolver/index.html @@ -5,4 +5,4 @@

    Mystery Solver

    Mystery Solver is a tool to track answers and help solve a particular board game that is popular in my family.

    You can use it here:https://www.jessemcdowell.ca/mystery/

    I built it with AngularJS using entirely client-side logic. You can see the source code here: https://github.com/jessemcdowell/mysterysolver

    -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/page/2/index.html b/page/2/index.html index 0416abf8..9faaf7d1 100644 --- a/page/2/index.html +++ b/page/2/index.html @@ -2,12 +2,12 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -

    Design by Dogma Antipattern

    +

    My Architectural Report Template

    As an architect I’ve been asked to answer a lot of hard questions. I used to waste time figuring out how to structure my answers, preventing me from getting into a good flow sooner. Now I have a simple template that is easy to use, easy to read, and saves me that wasted time up front. +This template works for simple reports that are only a couple of pages, but can easily be adjusted or expanded for...

    Read More

    Design by Dogma Antipattern

    Always use a NoSQL database so your app can scale. NoSQL databases can be more scalable, but schema-on-read has other drawbacks. NoSQL databases are much less capable of transactional changes. Relationships are difficult or impossible. Designing schemas to be efficient is much harder, and requires more up-front knowledge about your problem. NoSQL databases are sometimes the right tool for the jo...

    Read More

    Horizontal One-on-Ones and Talking Practice

    When I was promoted to the role of architect it was a new role in the organization. The stakeholders I had to work with were not used to talking to an architect, and weren’t sure what I did or when I should be involved in a conversation. I started using recurring one-on-one meetings with each stakeholder separately. It worked great. It’s also made me a much better communicator. One of the first an...

    Read More

    Case of the Appearing Users

    A couple of years after solving The Case of The Disappearing Users, I was assigned another high profile bug where new users were being spontaneously created. They were being generated without a name or any profile information, but still filling up space in lists and appearing on schedules. A couple of other developers had tried fixing it but had no luck, so it was assigned to me. I went through my...

    Read More

    Automating Non-Non-Downtime Upgrades in Kubernetes with ArgoCD

    I recently worked on a project to move a complicated legacy application onto Kubernetes. It was quite an undertaking, but in the end we were successful. One of the biggest challenges was figuring out how to automate our legacy deployment process, one where the whole application has to be stopped completely for schema upgrades to run. The normal “Kubernetes way” to upgrade an application is by chan...

    Read More

    Importance of Alignment

    Unless you work entirely alone, alignment is a big deal. When you are well aligned with your company’s goals you are a more valuable employee. When you are well aligned with your manager they can keep you on the right track and be an ally against obstacles. When you are well aligned with your peers you can keep each other focused on the most important work. -On the other hand, when you have poor al...

    Read More

    Polyglot Unconference 2023

    I recently had the pleasure of attending the 2023 Polyglot Unconference in Vancouver, put on by the Polyglot Software Association. I’ve been attending these for years. It is my favourite local conference. -An unconference, sometimes called an open spaces conference, is a participant-driven event where attendees choose the topics of discussion and provide the content themselves. They are meant to be...

    Read More

    \ No newline at end of file +On the other hand, when you have poor al...

    Read More

    \ No newline at end of file diff --git a/page/3/index.html b/page/3/index.html index 11d12b0f..b61be2ac 100644 --- a/page/3/index.html +++ b/page/3/index.html @@ -2,7 +2,8 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -

    Sustainable Errors

    Making a program work for the happy path is not always easy, but given enough time I believe pretty much anyone could do it. When a professional takes on the task however they will make it work for more than just the happy path, and do it with code that is easy to debug, and easy for others to understand and change. Since so much of what we end up dealing with are exceptional flows, we need a conc...

    Read More

    Is the Bug Fun?

    There are many things about producing video games that are surprising, but one of the weirdest has to be the approach to bugs. Like any piece of software, bugs are found through testing or user reports, triaged, then assigned to developers. Unlike normal business software they also ask the question, “is the bug fun?” +

    Polyglot Unconference 2023

    I recently had the pleasure of attending the 2023 Polyglot Unconference in Vancouver, put on by the Polyglot Software Association. I’ve been attending these for years. It is my favourite local conference. +An unconference, sometimes called an open spaces conference, is a participant-driven event where attendees choose the topics of discussion and provide the content themselves. They are meant to be...

    Read More

    Sustainable Errors

    Making a program work for the happy path is not always easy, but given enough time I believe pretty much anyone could do it. When a professional takes on the task however they will make it work for more than just the happy path, and do it with code that is easy to debug, and easy for others to understand and change. Since so much of what we end up dealing with are exceptional flows, we need a conc...

    Read More

    Is the Bug Fun?

    There are many things about producing video games that are surprising, but one of the weirdest has to be the approach to bugs. Like any piece of software, bugs are found through testing or user reports, triaged, then assigned to developers. Unlike normal business software they also ask the question, “is the bug fun?” There are plenty of unintended features (bugs) in games that became beloved. Atta...

    Read More

    Case of the Disappearing Users

    Many years ago I worked on a program that had a serious problem: the users in one customer’s system were getting deleted periodically. When a user was deleted, any data linked with them was also deleted. We could restore the data from backups, but it was a difficult process, and having a system that loses data wasn’t great for our reputation, so we wanted to resolve it quickly. Our VP of developme...

    Read More

    How to Fix a Bug

    Building applications can be tricky, and it’s inevitable that mistakes will be made. As a result, we programmers spend a lot of time fixing bugs. Sometimes they are easy, but sometimes they can be pretty tough to figure out. I’ve fixed a lot of bugs in my career, and to be honest with you, I usually enjoy the process. These days I am typically assigned the super urgent bugs that nobody else can fi...

    Read More

    How to Report a Bug

    Nobody likes bugs, least of all programmers. No matter how hard we try to catch them early, some will always escape into circulation. Until computers are smart enough to do what we meant instead of what we said, users are going to keep finding bugs, and we’re going to keep fixing them. -Before a bug is fixed, it needs to be reported. Unfortunately it’s not uncommon to receive incomplete reports. We...

    Read More

    Breaking Past Senior Developer

    Developing software is an excellent career. Software has touched almost every aspect of our world, and its impact is always expanding. Many new things have become possible because of software, things that couldn’t have been dreamed of even ten years ago. The industry is continuing to expand. Tools are getting better. New opportunities are appearing everywhere… So why haven’t you gotten a promotion...

    Read More

    \ No newline at end of file +Before a bug is fixed, it needs to be reported. Unfortunately it’s not uncommon to receive incomplete reports. We...

    Read More

    \ No newline at end of file diff --git a/page/4/index.html b/page/4/index.html index 3457b51d..d0a32fe1 100644 --- a/page/4/index.html +++ b/page/4/index.html @@ -2,8 +2,7 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -

    Brewing Your Own Iced Tea

    There are few things more refreshing than a cold glass of good iced tea. I’ve tried iced tea from a lot of places, but the best I’ve had to this day is my own recipe. It’s so easy that I can’t in good conscience keep it secret. It’s also far cheaper than anything you can buy in a can or bottle, and a lot healthier because it doesn’t require any kind of sweetener. The only down side is that it take...

    Read More

    Infiltrating an Organization (or: Joining a New Team)

    It takes some time to integrate into a new team. I always feel like an outsider at first. As I build friendships and trust, I’m able to contribute with increasing effectiveness. Having noticed some patterns, I’ve been able to make the process faster and smoother using a few simple tricks. +

    Breaking Past Senior Developer

    Developing software is an excellent career. Software has touched almost every aspect of our world, and its impact is always expanding. Many new things have become possible because of software, things that couldn’t have been dreamed of even ten years ago. The industry is continuing to expand. Tools are getting better. New opportunities are appearing everywhere… So why haven’t you gotten a promotion...

    Read More

    Brewing Your Own Iced Tea

    There are few things more refreshing than a cold glass of good iced tea. I’ve tried iced tea from a lot of places, but the best I’ve had to this day is my own recipe. It’s so easy that I can’t in good conscience keep it secret. It’s also far cheaper than anything you can buy in a can or bottle, and a lot healthier because it doesn’t require any kind of sweetener. The only down side is that it take...

    Read More

    Infiltrating an Organization (or: Joining a New Team)

    It takes some time to integrate into a new team. I always feel like an outsider at first. As I build friendships and trust, I’m able to contribute with increasing effectiveness. Having noticed some patterns, I’ve been able to make the process faster and smoother using a few simple tricks. Tuckman’s Stages of Group Development describe what happens when a team is formed. His theory has four stages:...

    Read More

    Why I Only Drink Loose Tea

    When I was a child, I drank tea because my parents wouldn’t let me drink coffee. I would soak a tea bag in hot water until it made a dark, bitter liquid, then dump in milk and sugar until it was overly sweet, and mostly flavourless. I would sip it to fit in with adults, but I wouldn’t say that it was something I enjoyed. As a young adult, I tried loose tea on the advice of a friend. It was a total...

    Read More

    Controller Led Navigation in Angular

    I recently tried AngularJS for a pet project. I watched a great tutorial about the platform, then dove in head first. You can see what I built here: MysterySolver -I enjoyed Angular. It was straightforward to use, and allowed me to bang out a lot of functionality without much cumbersome boilerplate code. Jasmine, the testing framework set up in the bootstrap source, was also pretty slick. I really ...

    Read More

    Reading Server Graphs: Connected Users

    I’ve spent the last several years working on multi-user server systems in two different companies. Both those companies had a giant monitor hanging off a wall showing a graph of connected users. It won’t give you detailed diagnostic information, but it is a good indicator for the health of your servers, and your product generally. If you learn to notice certain patterns in your user graph, it can ...

    Read More

    InstallUtil and BadImageFormatException - Facepalm

    I had a frustrating issue at work this week: one that was easy to fix, but embarrassingly difficult to find. I came pretty close to giving up, which is not a solution I often explore, but in the end we figured it out and got everything working. -A member of our operations team was installing a Windows service I’d built to monitor some stuff in our production environment. I’ve made a few windows ser...

    Read More

    \ No newline at end of file +I enjoyed Angular. It was straightforward to use, and allowed me to bang out a lot of functionality without much cumbersome boilerplate code. Jasmine, the testing framework set up in the bootstrap source, was also pretty slick. I really ...

    Read More

    Reading Server Graphs: Connected Users

    I’ve spent the last several years working on multi-user server systems in two different companies. Both those companies had a giant monitor hanging off a wall showing a graph of connected users. It won’t give you detailed diagnostic information, but it is a good indicator for the health of your servers, and your product generally. If you learn to notice certain patterns in your user graph, it can ...

    Read More

    \ No newline at end of file diff --git a/page/5/index.html b/page/5/index.html index 14944c8b..2795819c 100644 --- a/page/5/index.html +++ b/page/5/index.html @@ -2,10 +2,10 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -

    Choosing Priorities

    During the summer I started a difficult but important journey to reorganize my life. The first step was organizing my daily tasks. I was successful, but becoming productive again has created new issues. +

    InstallUtil and BadImageFormatException - Facepalm

    I had a frustrating issue at work this week: one that was easy to fix, but embarrassingly difficult to find. I came pretty close to giving up, which is not a solution I often explore, but in the end we figured it out and got everything working. +A member of our operations team was installing a Windows service I’d built to monitor some stuff in our production environment. I’ve made a few windows ser...

    Read More

    Choosing Priorities

    During the summer I started a difficult but important journey to reorganize my life. The first step was organizing my daily tasks. I was successful, but becoming productive again has created new issues. When you change from trying to do everything to doing what’s most important, you need to decide what important means. Figuring this out for myself has proven difficult. I still don’t have all the a...

    Read More

    Sharpening The Saw

    One of the best things about working in the software business is the high rate of change. Not only do we work with machines that radically change in capability every few years, but new techniques and technologies are constantly appearing on the scene. It is a fascinating new frontier that never gets dull. One of the worst things about working in the software business is the high rate of change. If...

    Read More

    Managing Priorities Outside of Work

    I’ve been fortunate to take some serious down time during the summer. After working pretty much non-stop for ten years, things have piled up. I took some time to rest, then got to work on some personal projects that have been neglected far too long. What I’ve learned, however, is that it takes more than time to get things done. After about a month, pretty much all I’d achieved was completing a cou...

    Read More

    Doubling Data for Performance Testing

    Or: The Most Impressive T-SQL Script I’ve Ever Written I was recently working on a new application. After three months in the field, users were starting to complain about performance issues. We had done some limited performance tuning for the first release, and more as part of the second release, but new issues were popping up as more data got entered into the system. We could have continued fixin...

    Read More

    The Critical Path

    For the last ten years, if you had asked, I would have told you with some conviction that a “critical path” is a kind of test script that tests the essential functionality of a system. If the app passes it’s critical path test, I would have said, it may not delight users, but it’s unlikely that they’ll storm your basement with torches and pitchforks. -It came up at work during a discussion about in...

    Read More

    Consulting - A Brave New World

    I’ve taken a big step in my career. I’ve become a software consultant. -The decision to leave my job of three and a half years wasn’t an easy one. I was working with some fantastic people, building the best software we could, but at the end of the day I wasn’t learning. The work was challenging, but the challenges were mostly non-technical. In this business, if you’re not moving forward you may as ...

    Read More

    \ No newline at end of file +It came up at work during a discussion about in...

    Read More

    \ No newline at end of file diff --git a/page/6/index.html b/page/6/index.html index 79c22a92..bd58e1f8 100644 --- a/page/6/index.html +++ b/page/6/index.html @@ -2,9 +2,10 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -

    The Average Test

    I was conducting technical interviews recently for a senior developer position. I like to talk about a bunch of things, but there is one question I particularly enjoy asking each candidate. Write an implementation for this: +

    Consulting - A Brave New World

    I’ve taken a big step in my career. I’ve become a software consultant. +The decision to leave my job of three and a half years wasn’t an easy one. I was working with some fantastic people, building the best software we could, but at the end of the day I wasn’t learning. The work was challenging, but the challenges were mostly non-technical. In this business, if you’re not moving forward you may as ...

    Read More

    The Average Test

    I was conducting technical interviews recently for a senior developer position. I like to talk about a bunch of things, but there is one question I particularly enjoy asking each candidate. Write an implementation for this: 1234int Average(int a, int b){} It’s a great question because it’s a simple problem, and anyone that comes through the door should know the formula without having to...

    Read More

    Working Together and Having Fun

    We did one of our monthly releases at work this week. Releases can be stressful and frustrating, and take a lot of methodical preparation to get right. It can be thankless work too; the only time a user notices a release is when it goes badly. We do our releases early on a week day to minimize impact, so if anything does go wrong, there’s not many bodies around to help out. It’s not much fun, but ...

    Read More

    When to Add an ORM Tool

    I’m working on the code that parses VCalendar data so that it can be processed. I’m copying the data I care about into a simple data structure that can represent a calendar request in any format. Any logic that interacts with calendar requests would use this internal structure. I want it to be simple, only having the stuff that I need, but I don’t want to completely re-invent the wheel either, so ...

    Read More

    Teaching IT

    My company runs a 24/7 site with a substantial number of users and connections to partner systems all over the world. We do what we can to make the system fault tolerant, but problems can still appear at any time of day or night. Ideally we would have a technical support team that’s staffed around the clock, but that not in the cards for now. We used to have a system where anyone that could f...

    Read More

    Invitations and the VCard Format

    My next goal for the Themis project is to parse an invitation from an email. I am starting with invitations generated by MS Outlook because that’s my target audience, but a peak inside of a Google Calendar invitation gives me hope that I’ll be able to support multiple calendars without much trouble. -Outlook invitations are sent in the VCalendar format, content type “text/calendar”. The standa...

    Read More

    64-bit IIS vs. 32-bit Assemblies

    I found my first 64-bit bug at work. I was moving a windows service built for the ‘Any CPU’ to a 64-bit server. It started fine on the new server, and gave no indication of poor health in the logs, but one key function was malfunctioning. I’m not exactly sure what the cause is, but I know that the hash of any binary file was resulting in the same value. The service does some direct memory manipula...

    Read More

    \ No newline at end of file +Outlook invitations are sent in the VCalendar format, content type “text/calendar”. The standa...

    Read More

    \ No newline at end of file diff --git a/page/7/index.html b/page/7/index.html index 31b61dcf..883aecf9 100644 --- a/page/7/index.html +++ b/page/7/index.html @@ -2,16 +2,10 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -

    SQLite vs. SQL CE 3.5 with Entity Framework 4

    My wife and I have been taking a Japanese class. I’m enjoying it quite a bit, even though learning languages has never been easy for me. I need to work hard to memorize all the new words, and that means lots and lots of practice. +

    64-bit IIS vs. 32-bit Assemblies

    I found my first 64-bit bug at work. I was moving a windows service built for the ‘Any CPU’ to a 64-bit server. It started fine on the new server, and gave no indication of poor health in the logs, but one key function was malfunctioning. I’m not exactly sure what the cause is, but I know that the hash of any binary file was resulting in the same value. The service does some direct memory manipula...

    Read More

    SQLite vs. SQL CE 3.5 with Entity Framework 4

    My wife and I have been taking a Japanese class. I’m enjoying it quite a bit, even though learning languages has never been easy for me. I need to work hard to memorize all the new words, and that means lots and lots of practice. My wife bought a pack of index cards. This is what a normal person would do. To me, it seems like defeat. Why use paper when there’s a computer in the room? While she’s a...

    Read More

    IE9 Try and Fail

    I decided to give IE9 a try. What’s not to like about a browser that’s supposed to be faster, cleaner, and support new HTML features? They really nailed the faster and cleaner parts. I didn’t find the user interface in IE8 too busy, but seeing the improvement I’m happy for the extra space. Plunking a site onto my task bar like it were an application is pretty awesome. There are a couple of website...

    Read More

    Themis: System Design

    I’m charging forward on the Shared Resource Schedule Service. There are a lot of things I’m getting into place before I start writing code. Don’t try to tell me that I’m not being agile either, you always need to design a little to write good code. The key to being agile is designing only as much as you need, and being prepared to change your mind later. The NameThe first order of business was to ...

    Read More

    My First Open Source Project

    I’ve been spending time on the first part of the shared resource service project: “Receive event invitations by email and send an acceptance email”. I hadn’t considered the difficulty I would face receiving emails. This is the most important part of the application, and if I can’t make it work, there’s really no point to continue. I don’t want to write my own POP3 library, I’ve done that before an...

    Read More

    Changing From an iPod to a Creative Zen

    The time finally came for me to replace my iPod with something new. I was using aniPod click wheelthat I got as a warranty replacement back in 2004.It was good to me, but I felt that it was time to look at other options.If iTunes ran a little better on my PC, I probably would have just bought another iPod without a second thought. -HardwareIt took me quite a while to choose a new device. I did look...

    Read More

    SQL Management Studio Express with VS 2010 Express

    I had some fun trying to install SQL Management Studio on my home computer over the weekend. I was successful in the end, but it was a rough journey. -These seem to be the things that can lead you into my scenario: - -Windows 7 -Visual Web Developer 2010 Express (which installs SQL Server 2008 Express) - -These are the things I ran into trying to install SQL Management Studio (both from an SQL 2008 stan...

    Read More

    \ No newline at end of file +HardwareIt took me quite a while to choose a new device. I did look...

    Read More

    \ No newline at end of file diff --git a/page/8/index.html b/page/8/index.html index f9142331..15c6d398 100644 --- a/page/8/index.html +++ b/page/8/index.html @@ -2,9 +2,15 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); -

    Shared Resource Service Requirements

    I want to start my project by dividing up the various things the system needs to do, then put them into the order I plan to approach them. I want to start with requirements that are the most risky and most important to success first, and work my way down the list until I finish with items that are neither risky nor important. +

    SQL Management Studio Express with VS 2010 Express

    I had some fun trying to install SQL Management Studio on my home computer over the weekend. I was successful in the end, but it was a rough journey. +These seem to be the things that can lead you into my scenario: + +Windows 7 +Visual Web Developer 2010 Express (which installs SQL Server 2008 Express) + +These are the things I ran into trying to install SQL Management Studio (both from an SQL 2008 stan...

    Read More

    Shared Resource Service Requirements

    I want to start my project by dividing up the various things the system needs to do, then put them into the order I plan to approach them. I want to start with requirements that are the most risky and most important to success first, and work my way down the list until I finish with items that are neither risky nor important. This approach gives me several advantages. It’s not an issue in this cas...

    Read More

    Shared Resource Schedule Service

    I think I’ve got a new project to work on at home. We’ve got this problem at work coordinating a few shared resources in Outlook (like a couple of meeting rooms and a projector), but we couldn’t find any good solutions out there short of installing Exchange Server. I’ve been wanting to play around with Entity Framework a bit, so this should be a good candidate. Perhaps I can slap a UI on it using ...

    Read More

    My First Post

    I’ve finally gone and done it. To be honest, creating my own blog wasn’t foremost in my thoughts until fairly recently. Scott Hanselman had a couple of interesting videos on his blog that finally convinced me to do it. I hope you like it. -

    Read More

    \ No newline at end of file +

    Read More

    \ No newline at end of file diff --git a/resources/architectural-report-template/index.html b/resources/architectural-report-template/index.html index 49f5a5af..d0bcdaa6 100644 --- a/resources/architectural-report-template/index.html +++ b/resources/architectural-report-template/index.html @@ -41,4 +41,4 @@

    \ No newline at end of file +
    \ No newline at end of file diff --git a/resources/index.html b/resources/index.html index b593ffae..93e23149 100644 --- a/resources/index.html +++ b/resources/index.html @@ -6,4 +6,4 @@ -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/sitemap.txt b/sitemap.txt index 07d6c30c..716e3214 100644 --- a/sitemap.txt +++ b/sitemap.txt @@ -1,3 +1,4 @@ +https://jessemcdowell.ca/2023/11/This-Blog-Hexo-generated-static-site-hosted-on-GitHub-Pages/ https://jessemcdowell.ca/mysterysolver/ https://jessemcdowell.ca/about/ https://jessemcdowell.ca/resources/ @@ -49,6 +50,7 @@ https://jessemcdowell.ca/2011/10/sharpening-the-saw/ https://jessemcdowell.ca/2016/08/infiltrating-an-organization/ https://jessemcdowell.ca/licence/ https://jessemcdowell.ca/ +https://jessemcdowell.ca/tags/github/ https://jessemcdowell.ca/tags/blogging/ https://jessemcdowell.ca/tags/design/ https://jessemcdowell.ca/tags/sql/ diff --git a/sitemap.xml b/sitemap.xml index c6c0bc74..61431dd3 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -1,6 +1,15 @@ + + https://jessemcdowell.ca/2023/11/This-Blog-Hexo-generated-static-site-hosted-on-GitHub-Pages/ + + 2023-11-01 + + monthly + 0.6 + + https://jessemcdowell.ca/mysterysolver/ @@ -454,274 +463,281 @@ https://jessemcdowell.ca/ - 2023-10-27 + 2023-11-01 daily 1.0 + + https://jessemcdowell.ca/tags/github/ + 2023-11-01 + weekly + 0.2 + + https://jessemcdowell.ca/tags/blogging/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/design/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/sql/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/devops/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/gadgets/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/quality/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/practices/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/ioc/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/unit-testing/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/open-source/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/net/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/debugging/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/web/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/database/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/entity-framework/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/people-management/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/leadership/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/c/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/interviewing/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/career/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/consulting/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/project-management/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/performance/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/learning/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/food/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/tea/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/angular/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/js/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/recipes/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/bugs/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/war-stories/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/video-games/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/community/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/kubernetes/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/argocd/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/architecture/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/resources/ - 2023-10-27 + 2023-11-01 weekly 0.2 https://jessemcdowell.ca/tags/reviews/ - 2023-10-27 + 2023-11-01 weekly 0.2 diff --git a/tags/angular/index.html b/tags/angular/index.html index b2723c50..deac945f 100644 --- a/tags/angular/index.html +++ b/tags/angular/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/architecture/index.html b/tags/architecture/index.html index 420b15b1..0409206d 100644 --- a/tags/architecture/index.html +++ b/tags/architecture/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/argocd/index.html b/tags/argocd/index.html index c5009335..c935ee12 100644 --- a/tags/argocd/index.html +++ b/tags/argocd/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/blogging/index.html b/tags/blogging/index.html index 0f490de9..8b8e64fa 100644 --- a/tags/blogging/index.html +++ b/tags/blogging/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/bugs/index.html b/tags/bugs/index.html index eb98d6d5..b6bae409 100644 --- a/tags/bugs/index.html +++ b/tags/bugs/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/c/index.html b/tags/c/index.html index 593ec997..ffc5b8f3 100644 --- a/tags/c/index.html +++ b/tags/c/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/career/index.html b/tags/career/index.html index 1295881b..2cd6cd30 100644 --- a/tags/career/index.html +++ b/tags/career/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/career/page/2/index.html b/tags/career/page/2/index.html index 844a718b..1789e7b8 100644 --- a/tags/career/page/2/index.html +++ b/tags/career/page/2/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/community/index.html b/tags/community/index.html index 1609f402..440e2937 100644 --- a/tags/community/index.html +++ b/tags/community/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/consulting/index.html b/tags/consulting/index.html index 30392807..41348ecf 100644 --- a/tags/consulting/index.html +++ b/tags/consulting/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/database/index.html b/tags/database/index.html index ab63b5b5..102a8553 100644 --- a/tags/database/index.html +++ b/tags/database/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/debugging/index.html b/tags/debugging/index.html index 69ad20a5..a02e2299 100644 --- a/tags/debugging/index.html +++ b/tags/debugging/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/debugging/page/2/index.html b/tags/debugging/page/2/index.html index f9416730..2a6fba71 100644 --- a/tags/debugging/page/2/index.html +++ b/tags/debugging/page/2/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/design/index.html b/tags/design/index.html index 93bb1bdc..991be4aa 100644 --- a/tags/design/index.html +++ b/tags/design/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/design/page/2/index.html b/tags/design/page/2/index.html index 1e3890c7..ef2d9f4b 100644 --- a/tags/design/page/2/index.html +++ b/tags/design/page/2/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/devops/index.html b/tags/devops/index.html index c63e2044..2dd1e286 100644 --- a/tags/devops/index.html +++ b/tags/devops/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/entity-framework/index.html b/tags/entity-framework/index.html index 6e406747..b1d2a404 100644 --- a/tags/entity-framework/index.html +++ b/tags/entity-framework/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/food/index.html b/tags/food/index.html index fc5f64b6..fed100e9 100644 --- a/tags/food/index.html +++ b/tags/food/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/gadgets/index.html b/tags/gadgets/index.html index a1ee7fcc..936bb005 100644 --- a/tags/gadgets/index.html +++ b/tags/gadgets/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/github/index.html b/tags/github/index.html new file mode 100644 index 00000000..2240017e --- /dev/null +++ b/tags/github/index.html @@ -0,0 +1,5 @@ +github | Jesse Builds Software \ No newline at end of file diff --git a/tags/interviewing/index.html b/tags/interviewing/index.html index b3f3ce5c..a0632055 100644 --- a/tags/interviewing/index.html +++ b/tags/interviewing/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/ioc/index.html b/tags/ioc/index.html index cc18d71c..309739cb 100644 --- a/tags/ioc/index.html +++ b/tags/ioc/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/js/index.html b/tags/js/index.html index 163336a1..52469ae2 100644 --- a/tags/js/index.html +++ b/tags/js/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/kubernetes/index.html b/tags/kubernetes/index.html index 581d0b36..2a3583b9 100644 --- a/tags/kubernetes/index.html +++ b/tags/kubernetes/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/leadership/index.html b/tags/leadership/index.html index 24a56ff4..8b2345cc 100644 --- a/tags/leadership/index.html +++ b/tags/leadership/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/learning/index.html b/tags/learning/index.html index c8afa50d..710d0bb8 100644 --- a/tags/learning/index.html +++ b/tags/learning/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/net/index.html b/tags/net/index.html index 17c942e6..720900a1 100644 --- a/tags/net/index.html +++ b/tags/net/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/open-source/index.html b/tags/open-source/index.html index ecb4959c..6a1e324d 100644 --- a/tags/open-source/index.html +++ b/tags/open-source/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/people-management/index.html b/tags/people-management/index.html index 4eb2f358..8d7e0bc2 100644 --- a/tags/people-management/index.html +++ b/tags/people-management/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/performance/index.html b/tags/performance/index.html index fb2d1be5..7bdb4c20 100644 --- a/tags/performance/index.html +++ b/tags/performance/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/practices/index.html b/tags/practices/index.html index afa11f94..b0807665 100644 --- a/tags/practices/index.html +++ b/tags/practices/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/project-management/index.html b/tags/project-management/index.html index f69904d5..8707d3cb 100644 --- a/tags/project-management/index.html +++ b/tags/project-management/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/quality/index.html b/tags/quality/index.html index f587041a..a6f7b117 100644 --- a/tags/quality/index.html +++ b/tags/quality/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/recipes/index.html b/tags/recipes/index.html index 12dae8cb..affbd595 100644 --- a/tags/recipes/index.html +++ b/tags/recipes/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/resources/index.html b/tags/resources/index.html index fa406f4a..9e6cfce5 100644 --- a/tags/resources/index.html +++ b/tags/resources/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/reviews/index.html b/tags/reviews/index.html index 11ec5976..9adeaed7 100644 --- a/tags/reviews/index.html +++ b/tags/reviews/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/sql/index.html b/tags/sql/index.html index 2723c8c5..b371602d 100644 --- a/tags/sql/index.html +++ b/tags/sql/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/tea/index.html b/tags/tea/index.html index 2ae040af..a5588e24 100644 --- a/tags/tea/index.html +++ b/tags/tea/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/unit-testing/index.html b/tags/unit-testing/index.html index 57819ce1..2d580d94 100644 --- a/tags/unit-testing/index.html +++ b/tags/unit-testing/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/video-games/index.html b/tags/video-games/index.html index e6c9e600..aeb9450b 100644 --- a/tags/video-games/index.html +++ b/tags/video-games/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/war-stories/index.html b/tags/war-stories/index.html index e344d594..99b3803b 100644 --- a/tags/war-stories/index.html +++ b/tags/war-stories/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file diff --git a/tags/web/index.html b/tags/web/index.html index f68a3300..b9bfcb8d 100644 --- a/tags/web/index.html +++ b/tags/web/index.html @@ -2,4 +2,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17968343-1'); - \ No newline at end of file + \ No newline at end of file