├── src
├── favicon.png
├── images
│ └── kevin_rockon.png
├── pages
│ ├── Resume.vue
│ ├── Contact.vue
│ ├── Training.vue
│ ├── README.md
│ ├── Consulting.vue
│ ├── Categories.vue
│ ├── Index.vue
│ └── Speaking.vue
├── components
│ ├── README.md
│ ├── Heading.vue
│ ├── Welcome.vue
│ ├── Contact.vue
│ ├── WelcomeConsulting.vue
│ ├── WelcomeTraining.vue
│ ├── LatestArticles.vue
│ └── SiteHeader.vue
├── layouts
│ ├── README.md
│ ├── Default.vue
│ └── CategoryLayout.vue
├── templates
│ ├── README.md
│ └── Article.vue
├── styles
│ └── global.css
└── main.js
├── .gitignore
├── tailwind.config.js
├── static
└── README.md
├── todo.md
├── purgecss.config.js
├── README.md
├── blog
├── fix-my-computer.md
├── ASPNET-40-To-ASPNET-Core.md
├── One-Simple-Rule-for-Successful-Consulting.md
├── Enhancing-Your-Applications-For-Windows-7.md
├── Enable-SignalR-Logging-with-One-Simple-Line.md
├── Interview-with-Michael-Rollins-for-HRDevFest-2016.md
├── Simple-HTML-Formatting-in-Sublime-Text.md
├── Wildcard-search-with-LINQ.md
├── Learn-about-Windows-7-Task-Dialogs.md
├── Powershell-How-to-recursively-delete-files-based-of-file-extension.md
├── 50-Ways-to-Avoid-Find-and-Fix-ASP-NET-Performance-Issues.md
├── If-You-Reach-Just-One-Person.md
├── Specifying-Visual-Studio-Version-in-NPM-Installs.md
├── How-to-run-Visual-Studio-Code-from-Zsh-on-Mac-OSX.md
├── Quick-Introduction-to-SignalR-Streaming.md
├── How-to-run-Visual-Studio-Code-from-Terminal-on-Mac-OSX.md
├── My-Defacto-gitignore-file.md
├── Named-Callbacks-in-JavaScript.md
├── swift-kick-show-unbelievable-and-complex-advancements-in-machine-learning-with-ankur-kalra.md
├── Online-vs-Retail-Stores.md
├── No-matter-what-you-do-add-value.md
├── MongoDB-Setting-TTL-on-Documents.md
├── Preloading-Multiple-Audio-Tags-in-Internet-Explorer-9.md
├── Review-7-Recurring-Revenue-Recipes-for-Freelancers.md
├── Console-Games-Why-do-we-have-to-press-start.md
├── Exploring-C-7-0-Out-Variables.md
├── Moving-on-to-Greener-Pastures.md
├── Managing-Your-User-Group-Calendar-Roulette.md
├── The-10-Rule-to-Presentations.md
├── Managing-Your-User-Group-Food.md
├── swift-kick-show-nosql-shouldnt-mean-nosecurity-with-matt-groves.md
├── Running-a-Conference-Like-A-Startup.md
├── A-Diet-Programmers-Can-Relate-To.md
├── My-Attempt-at-LINQ-Pagination.md
├── Leaving-It-Better-Than-You-Found-It.md
├── Building-better-ConnectionStrings-with-ConnectionStringBuilder.md
├── Banks-ATMS-and-Horrible-User-Experiences.md
├── Speaker-Gifts.md
├── Are-we-too-dependent-on-the-Internet.md
├── i-removed-email-from-my-phone.md
├── The-Zen-of-Free-Labor.md
├── Node-js-Using-require-to-load-your-own-files.md
├── Book-Review-Financially-Stupid-People-Are-Everywhere.md
├── about-blog-posts.md
├── Maintaining-SignalR-ConnectionId-rsquo-s-Across-Page-Instances.md
├── Open-Source-Mentality-of-Choosing-Your-Tech-Stack.md
├── How-I-m-Beating-Email-Addiction.md
├── Managing-Your-User-Group-Sponsor-Relationships.md
├── Definition-of-a-Computer-Scientist.md
├── Colossal-Failures.md
├── I-suck-at-writing-unit-tests-but-I-m-trying-to-change.md
├── SignalR-Transports-Explained.md
├── Using-Unity-for-Dependency-Injection-with-SignalR.md
├── What-Makes-A-Good-Bug-Report.md
├── Why-should-ASP-NET-developers-consider-SignalR-for-ALL-projects.md
├── The-Non-Techie-Guide-to-Source-Control.md
├── Anatomy-of-an-XNA-Application.md
├── Non-Tech-Factors-to-Consider-When-Choosing-Your-Tech-Stack.md
├── Review-Everleap.md
├── Shedquarters.md
├── Paying-Attention.md
└── Books-I-Read-in-2016.md
├── package.json
├── gridsome.server.js
├── azure-pipelines.yml
└── gridsome.config.js
/src/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/1kevgriff/kevgriffin.v3/master/src/favicon.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.log
2 | .cache
3 | .DS_Store
4 | src/.temp
5 | node_modules
6 | dist
7 | .env
8 | .env.*
9 |
--------------------------------------------------------------------------------
/src/images/kevin_rockon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/1kevgriff/kevgriffin.v3/master/src/images/kevin_rockon.png
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | theme: {
3 | extend: {}
4 | },
5 | variants: {},
6 | plugins: []
7 | }
8 |
--------------------------------------------------------------------------------
/src/pages/Resume.vue:
--------------------------------------------------------------------------------
1 |
2 | {{value}}
3 |
4 |
5 |
--------------------------------------------------------------------------------
/static/README.md:
--------------------------------------------------------------------------------
1 | Add static files here. Files in this directory will be copied directly to `dist` folder during build. For example, /static/robots.txt will be located at https://yoursite.com/robots.txt.
2 |
3 | This file should be deleted.
--------------------------------------------------------------------------------
/src/pages/Contact.vue:
--------------------------------------------------------------------------------
1 |
2 | Got a problem? Yo, I'll solve it.
9 |
I invite you to head over to Developer Fusion, and read my article on "Enhancing Your Applications For Windows 7”. If you haven’t played with the Windows 7 API Code Pack yet, I definitely recommend it.
http://www.developerfusion.com/article/70531/enhancing-your-applications-for-windows-7/
-------------------------------------------------------------------------------- /blog/Enable-SignalR-Logging-with-One-Simple-Line.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Enable SignalR Logging with One Simple Line 3 | categories: 4 | - "Development - ASP.NET" 5 | permalink: signalr-logging 6 | date: 2015-08-28 23:26:42 7 | --- 8 | 9 | It is easy to think that SignalR works within a black box, but if you are deploying JavaScript clients, here is an EASY trick to learning what is happening underneath the scenes. 10 | 11 | Before you start your connection, add this ONE line of code: 12 | 13 | ```javascript 14 | $.connection.hub.logging = true; 15 | $.connection.hub.start(); 16 | ``` 17 | 18 | Tada! You have logging in your browser console: 19 | 20 |  -------------------------------------------------------------------------------- /blog/Interview-with-Michael-Rollins-for-HRDevFest-2016.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Interview with Michael Rollins for HRDevFest 2016 3 | categories: 4 | - Community, User Groups, and Conferences 5 | permalink: interview-with-michael-rollins-for-hrdevfest-2016 6 | date: 2016-09-01 10:56:33 7 | --- 8 | 9 | Recently, I had the opportunity to sit down with my friend [Michael Rollins](http://www.rollins.io) to talk about life as a mobile SDK developer, drones, and his upcoming HRDevFest keynote on growth through suffering. 10 | 11 | Watch the interview for yourself! Get your tickets for HRDevfest at [http://hrdevfest.org!](http://hrdevfest.org) 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /blog/Simple-HTML-Formatting-in-Sublime-Text.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Simple HTML Formatting in Sublime Text 3 | categories: 4 | - Development 5 | permalink: simple-html-formatting-in-sublime-text 6 | id: 730 7 | updated: '2013-02-27 05:17:35' 8 | date: 2013-02-27 06:00:16 9 | --- 10 | 11 | One common questions I've asked and seen asked quite a bit about Sublime Text is how to quickly and easily format HTML while editing. There isn't a default key binding for this, but if you select all text and then go to: 12 |Edit -> Lines -> Reindent13 | Want to create your own keybinding? Go to Preferences, Key Bindings - User and add this line: 14 |
{ "keys": ["ctrl+shift+r"], "command": "reindent" , "args": {"single_line": false}}
15 | Enjoy!
--------------------------------------------------------------------------------
/blog/Wildcard-search-with-LINQ.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Wildcard search with LINQ
3 | categories:
4 | - "Development - C#"
5 | permalink: wildcard-search-with-linq
6 | date: 2009-04-21 09:17:26
7 | ---
8 |
9 | I just a situation where I needed to perform a wildcard search on a table in my database. When I used to do ADO.NET, I would simply write my SELECT statements with LIKE keywords to do wildcard searches.
10 |
11 | However, in this project, I'm using LINQ to Entities and the solution didn't work the same way as it did back in SQL land. My alternative was to use the .Contains() method.
12 |
13 | For example:
14 | var userList = from u in entity.Users
15 | where u.FirstName.Contains(searchParameter) ||
16 | u.LastName.Contains(searchParameter)
17 | select u;
18 |
19 | Hope this helps if you ever run into this problem.
--------------------------------------------------------------------------------
/azure-pipelines.yml:
--------------------------------------------------------------------------------
1 | # Node.js
2 | # Build a general Node.js project with npm.
3 | # Add steps that analyze code, save build artifacts, deploy, and more:
4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/javascript
5 |
6 | trigger:
7 | - master
8 |
9 | pool:
10 | vmImage: 'windows-latest'
11 |
12 | steps:
13 | - task: NodeTool@0
14 | inputs:
15 | versionSpec: '12.x'
16 | displayName: 'Install Node.js'
17 |
18 | - script: |
19 | npm install
20 | npm install --global @gridsome/cli
21 | gridsome build
22 | displayName: 'npm install + gridsome cli + gridsome build'
23 |
24 | - task: AzureFileCopy@3
25 | inputs:
26 | SourcePath: 'dist'
27 | azureSubscription: 'Microsoft Azure Sponsorship(c36e07bf-0eab-4330-aa8e-7f95fdcf3319)'
28 | Destination: 'AzureBlob'
29 | storage: 'kevgriffinv3'
30 | ContainerName: 'hosting'
31 |
--------------------------------------------------------------------------------
/blog/Learn-about-Windows-7-Task-Dialogs.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Learn about Windows 7 Task Dialogs
3 | categories:
4 | - Development
5 | permalink: learn-about-windows-7-task-dialogs
6 | updated: '2009-12-01 07:00:00'
7 | date: 2009-12-01 07:00:00
8 | ---
9 |
10 | Please take a few minutes and travel over to DeveloperFusion where my latest article on Windows 7 Task Dialogs has been published. If you’ve never used a task dialog before, I would definitely recommend them. I consider them “Message Box 2.0”.
Let me know what you think!
-------------------------------------------------------------------------------- /src/components/Contact.vue: -------------------------------------------------------------------------------- 1 | 2 |After giving a talk, it’s really difficult to judge if you reached any of the attendee’s. Normally, you get the occasional “good job” or “thanks, that was a big help.” Today I got a small mention by Johnathan Bracken, who was sitting in my jQuery From The Ground Up talk at Roanoke Code Camp. This means a lot, because it shows that my talk stayed in Johnathan’s head past the end of the talk.
He just started blogging, and mentioned me in his entry I Will Not Run from JavaScript No More. This is very cool to see. I wish Johnathan the best of luck in his jQuery adventures! And I expect him to give a jQuery talk at next year’s code camp.
-------------------------------------------------------------------------------- /gridsome.config.js: -------------------------------------------------------------------------------- 1 | // This is where project configuration and plugin options are located. 2 | // Learn more: https://gridsome.org/docs/config 3 | 4 | // Changes here require a server restart. 5 | // To restart press CTRL + C in terminal and run `gridsome develop` 6 | 7 | 8 | const tailwindcss = require("tailwindcss"); 9 | const purgecss = require("@fullhuman/postcss-purgecss"); 10 | 11 | module.exports = { 12 | siteName: 'Kevin W. Griffin', 13 | plugins: [ 14 | { 15 | use: '@gridsome/source-filesystem', 16 | options: { 17 | path: 'blog/*.md', 18 | typeName: 'Article', 19 | route: '/:permalink', 20 | remark: { 21 | plugins: [ 22 | ['gridsome-plugin-remark-shiki', { theme: 'nord', skipInline: false }] 23 | ] 24 | } 25 | } 26 | } 27 | ], 28 | css: { 29 | loaderOptions: { 30 | postcss: { 31 | plugins: [ 32 | tailwindcss, 33 | ...process.env.NODE_ENV === "production" ? [purgecss] : [] 34 | ], 35 | }, 36 | }, 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /blog/Specifying-Visual-Studio-Version-in-NPM-Installs.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Specifying Visual Studio Version in NPM Installs 3 | categories: 4 | - Development 5 | permalink: specifying-visual-studio-version-in-npm-installs 6 | date: 2013-05-14 06:34:08 7 | --- 8 | 9 | Sometimes when you install a NPM package, you'll run into an issue like this: 10 |C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V110\Microsoft.Cpp.Platform.targets(35,5): error MSB8020: The builds tools for Visual Studio 2010 (Platform Toolset = 'v100') cannot be found. To build using the v100 build tools, either click the Project menu or right-click the solution, and then select "Update VC++ Projects...". Install Visual Studio 2010 to build using the Visual Studio 2010 build tools.11 | Normally you'll get this if you're only running VS2012 and it wants VS2010/VS2008. You can ask NPM to use Visual Studio 2012 instead by using with "--msvs_version=2012" command. 12 | 13 | Example: 14 |
npm install socket.io --msvs_version=201215 | Tada. This should work almost every time. -------------------------------------------------------------------------------- /src/pages/Categories.vue: -------------------------------------------------------------------------------- 1 | 2 |
# Ignore file for Visual Studio 11 | 12 | # use glob syntax 13 | syntax: glob 14 | 15 | # Ignore Config files with keys and passwords 16 | #ServiceConfiguration*.cscfg 17 | #Web*.config 18 | #App*.config 19 | 20 | # Ignore Visual Studio files 21 | *.obj 22 | #*.exe 23 | #*.pdb 24 | *.user 25 | *.aps 26 | *.pch 27 | *.vspscc 28 | *.vshost.* 29 | *_i.c 30 | *_p.c 31 | *.ncb 32 | *.suo 33 | *.tlb 34 | *.tlh 35 | *.bak 36 | *.cache 37 | *.ilk 38 | *.log 39 | *.lib 40 | *.sbr 41 | *.scc 42 | *.orig 43 | UpgradeLog*.* 44 | UpgradeReport*.* 45 | [Bb]in 46 | [Dd]ebug*/ 47 | obj/ 48 | [Rr]elease*/ 49 | _ReSharper*/ 50 | [Tt]est[Rr]esult* 51 | [Bb]uild[Ll]og.* 52 | *.[Pp]ublish.xml 53 | glob:*.vs10x 54 | *.ReSharper 55 | [Pp]ublish 56 | [Rr]eleaseFiles 57 | [Cc]sx/ 58 | [Bb]ackup1/ 59 | [Pp]ackages/ 60 | 61 | # Mac Files 62 | .DS_Store 63 | *.DS_Store 64 | ._*-------------------------------------------------------------------------------- /src/templates/Article.vue: -------------------------------------------------------------------------------- 1 | 2 |
{{ $page.article.date }}
6 |12 | <audio id="myAudio" controls preload="auto"> 13 | <source src="/my-podcast.mp3" /> 14 | <source src="/my-podcast.ogg" /> 15 | </audio> 16 |17 | 18 | In Chrome, this works PERFECTLY (as it should). 19 | 20 | In Internet Explorer, several (if not all) files will fail to preload. Here's how to figure it: 21 | 22 |
23 | var audioElement = document.getElementById("myAudio");
24 | console.log(audioElement.networkState);
25 |
26 |
27 | Network state can have 3 options: NETWORK_EMPTY, NETWORK_IDLE, NETWORK_LOADING, NETWORK_NO_SOURCE.
28 |
29 | You "want" it to be IDLE, because that means the file is loaded. Typically, you'll get NO_SOURCE with Internet Explorer.
30 |
31 | What's a quick fix? First, make sure there is no preload attribute, and then do this:
32 |
33 |
34 | var audioElement = document.getElementById("myAudio");
35 | audioElement.load(); // kicks off the load
36 |
37 |
38 | This has worked for me in 100% of the tests I've done tonight. Feel free to comment on other solutions. I haven't tested in IE10 yet, so I cannot be certain of how it works.
--------------------------------------------------------------------------------
/blog/Review-7-Recurring-Revenue-Recipes-for-Freelancers.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'Review: 7 Recurring Revenue Recipes for Freelancers'
3 | permalink: review-7-recurring-revenue-recipes-for-freelancers
4 | categories:
5 | - Reviews
6 | updated: '2015-02-16 09:11:50'
7 | date: 2015-02-16 08:55:19
8 | ---
9 |
10 | During a flight from Norfok to Charlotte, I had the opportunity to read [Ryan Castillo's](https://twitter.com/rmcastil) new book [7 Recurring Revenue Recipes for Freelancers](http://ryancastillo.org/7-recipes-recurring-revenue/).
11 |
12 | In this book, Ryan provides seven actionable sets of guidelines that provides the reader a path way to earning $150k a year. Ryan allows the reader to take a "choose your own adventure" to their career and bottom line.
13 |
14 | This book provides clear ways for readers who are already experienced freelancers or consultants to move their target forward. If you're new to the consulting game, Ryan also provides some great places to get started.
15 |
16 | Ryan's recipe on developing support contracts with new and existing clients definitely struck a cord with me. This is a problem I'm running into now with multiple clients, and I'm going to be able to put Ryan's suggestions into action within the next week. This book has the potential to make me an easy $25k extra each year.
17 |
18 | Many of the recommendations Ryan makes echo throughout the communities I'm involved in daily. Every day, people are putting these recipes into action and are seeing results!
19 |
20 | Ryan is currently [pre-selling his book for $12](http://ryancastillo.org/7-recipes-recurring-revenue/), which is a drop in the bucket compared to what you will make if you put his receipes into adction.
--------------------------------------------------------------------------------
/blog/Console-Games-Why-do-we-have-to-press-start.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'Console Games: Why do we have to press start?'
3 | permalink: console-games-why-do-we-have-to-press-start
4 | categories:
5 | - "Development - Game Development"
6 | date: 2010-01-05 06:00:00
7 | ---
8 |
9 | Interesting question came up on Twitter the other day:
“Press Start” screens? Why can’t I just go straight to the main menu?
If you’re a gamer, especially on consoles, you’ve seen this screen more often than you’d care to. It’s a little annoyance. However, there is a very good reason for having this screen in place.
Imagine you’re running four controller on your Xbox, and all four of them are turned on. Then you put in a single player game, and it comes up to that annoying “Press Start” screen. Which controller do you use to press start with? The answer is easy: any of them!
The “Press Start” screen is designed to determine which controller the game should poll for input. During this screen, the game is polling all connected controllers for input. If any of them register a “start” button push, the game makes that controller the “default” controller. The use-case for this scenario is that the player should be able to use any connected controller to play the game, and not be forced to use controller #1. This is considered a best practice.
The More You Know…
-------------------------------------------------------------------------------- /blog/Exploring-C-7-0-Out-Variables.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Exploring C# 7.0: Out Variables" 3 | permalink: exploring-csharp70-out-variables 4 | categories: 5 | - "Development - C#" 6 | date: 2016-11-08 18:41:48 7 | --- 8 | 9 | _In this series, I want to explore a couple of the new C# 7.0 features coming down the pipeline. As with most things, I am working with preview bits, so these features are not guaranteed to work the same way in production._ 10 | 11 | Using the out keyword within C# is nothing new. If you declare a variable within a method called with **out**, you are instructing the compile that you are expecting the method to set the values of those at runtime. 12 | 13 | ```csharp 14 | class Program 15 | { 16 | static void Main(string[] args) 17 | { 18 | string firstName; 19 | string lastName; 20 | 21 | CreateName(out firstName, out lastName); 22 | Console.WriteLine($"Hello {firstName} {lastName}"); 23 | } 24 | 25 | private static void CreateName(out string firstName, out string lastName) 26 | { 27 | firstName = "Kevin"; 28 | lastName = "Griffin"; 29 | } 30 | } 31 | ``` 32 | 33 | Commonly the problem is that you have to declare the variable before the method call using out. In C# 7.0, there is the concept of out variables, which will save you a couple keystrokes by allowing you to declare the variable inline. 34 | 35 | The above example can be quickly refactored: 36 | 37 | ```csharp 38 | class Program 39 | { 40 | static void Main(string[] args) 41 | { 42 | // notice I'm declaring the type INSIDE THE CALL! 43 | CreateName(out string firstName, out string lastName); 44 | Console.WriteLine($"Hello {firstName} {lastName}"); 45 | } 46 | 47 | private static void CreateName(out string firstName, out string lastName) 48 | { 49 | firstName = "Kevin"; 50 | lastName = "Griffin"; 51 | } 52 | } 53 | ``` 54 | -------------------------------------------------------------------------------- /blog/Moving-on-to-Greener-Pastures.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Moving on to Greener Pastures 3 | categories: 4 | - Deep Thoughts 5 | permalink: moving-on-to-greener-pastures 6 | date: 2011-05-25 06:00:00 7 | --- 8 | 9 |After four years with my current company, Antech Systems, it is time for me to pack up and move on to greener pastures.
I would like to publically thank Antech for providing me with a foundation to build my career off of. I came to Antech as a college newbie, recently laid off from Symantec, with no .NET experience of any kind. Within weeks, I was able to grow into a position where I was not only functional, but able to provide meaningful feedback about the applications being built and the processes use to build them. Antech was the reason I found the developer community, and was one of the leading reasons why I started the Hampton Roads .NET Users Group. Without them, I have no idea where I would be right now.
I’m pleased to announce that on June 1st, 2011, I’ll be starting my new position with ComponentOne as a Technical Evangelist.

In this position, I’ll be working closely with Rich Dudley to help promote ComponentOne in the developer community. As a Technical Evangelist, it is my goal to help you all in your communities in anyway possible. Please feel free to use me as a resource.
If you’re going to be in the Kansas City area on June 25th, come out to the Kansas City Developer Conference to see me! I’ll be talking about MVVM! If you’re in the area, you should definitely come out.
-------------------------------------------------------------------------------- /blog/Managing-Your-User-Group-Calendar-Roulette.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Managing Your User Group: Calendar Roulette' 3 | permalink: calendar-roulette 4 | categories: 5 | - Community, User Groups, and Conferences 6 | date: 2015-03-06 22:39:16 7 | --- 8 | 9 | One trait of successful user groups is don't play calendar roulette. Meaning: they chose a time or day each month to hold the group meeting. 10 | 11 | > We meet every 2nd Tuesday. 12 | 13 | or 14 | 15 | > We are the last Thursday of the month. 16 | 17 | Why is this important? 18 | ***You want your members to be able to determine meeting dates based off a quick glance of a calendar.*** 19 | Consistency is key. If your meetings are in different venues or different days of the month, you're chancing that someone will forget and not be in attendance. 20 | 21 | **What's a good night for meetings?** 22 | With the Hampton Roads .NET Users Group, I chose the 2nd Tuesday of the month. Why? Because I felt Tuesdays were a better for my schedule. Only once in a 5 year period did I change the meeting. 23 | 24 | My recommendation is to choose a Tuesday, Wednesday, or Thursday. Mondays are bad for folks because it's the first day back to work after a short weekend. Fridays are bad because, dude, it's the weekend. PARTY TIME. 25 | 26 | Be careful with Wednesdays as well. Many church functions occur on Wednesday nights, and that might be limiting a percentage of your population. 27 | 28 | **When is it okay to move the meeting?** 29 | Let's imagine you have a speaker coming into town that's "a big deal". But they're only able to meeting on Wednesday night, and your meetings are Tuesdays. MOVE THE MEETING. Make sure the change is well communicated, and that it's temporary. You might lose attendance that month, but people are adaptable. Just don't make it a habit. 30 | 31 | **Conclusion** 32 | Keep scheduling simple. Hampton Roads .NET members knew where to go and when to be there every month of the year. If you build a level of consistency, you're going to have people showing up out of habit, and that's a recipe for a successful group. 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/pages/Speaking.vue: -------------------------------------------------------------------------------- 1 | 2 || Date | 13 |Event | 14 |Sessions | 15 |
|---|---|---|
| Jan. 21st, 2020 | 20 |Conference A | 21 |
22 |
|
27 |
| Date | 39 |Event | 40 |Sessions | 41 |
|---|---|---|
| Jan. 21st, 2020 | 46 |Conference A | 47 |
48 |
|
53 |
Today I’ve been diving into an easy way to paginate record sets in my applications. Searching around the internet yielded several good walkthroughs on how to do this. My favorite way came from my friend, Kevin Hazzard, He discussed using the Skip() and Take() extension methods to form fit LINQ into building a SQL statement that’ll do all the heavy lifting for you.
Copying from Kevin’s example, I built the following code snippet:
int pageNumber = 1;
10 | int pageSize = 20;
11 |
12 | using (var entity = new Entities())
13 | {
14 | var recordSet = (from r in entity.SomeTable
15 | orderby r.SomeID
16 | select r);
17 | recordSet = recordSet.Skip((pageNumber - 1) * pageSize).Take(pageSize);
18 |
19 | return recordSet;
20 | }
21 |
22 | What’s nice about the following code is that since LINQ is lazy loading, the SQL built doesn’t actually execute until we need it too. The days of returning full datasets are done (yes, we’re still doing that on some projects).
23 | 24 |I went the next step to see if I could build an extension method of my own that did all of the above for me automatically. Here was the result I came up with:
25 | 26 |public static class ExtensionMethods
27 | {
28 | public static IQueryable Paginate(this IQueryable content, int pageNumber, int pageSize)
29 | {
30 | return content.Skip((pageNumber - 1)*pageSize).Take(pageSize);
31 | }
32 | }
33 |
34 | This extension method takes the query returned from LINQ (an IQueryable), and applies the additional constraints to it. Here is the first example using my new extension method:
35 | 36 |int pageNumber = 1;
37 | int pageSize = 20;
38 |
39 | using (var entity = new Entities())
40 | {
41 | var recordSet = (from r in entity.SomeTable
42 | orderby r.SomeID
43 | select r);
44 | recordSet = recordSet.Paginate(pageNumber, pageSize);
45 |
46 | return recordSet;
47 | }
48 |
49 | 50 | 51 |
Ta da! Hopefully that makes sense. I’m open to other suggestions and comments. I’m learning that if I take about my thought processes on certain problems, that I receive a ton of great feedback from those who listen.
-------------------------------------------------------------------------------- /blog/Leaving-It-Better-Than-You-Found-It.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Leaving It Better Than You Found It 3 | categories: 4 | - Deep Thoughts 5 | permalink: leaving-it-better-than-you-found-it 6 | date: 2010-01-26 06:00:00 7 | --- 8 | 9 |When my wife and I bought our house back in April, one of my pet projects has been to renovate the room over our garage. I knew buying the house that it would be a lot of work, partly because the previous owner didn’t know what he was doing when finishing a room. I’ve spent the last week and half sanding, mudding, and fixing all the walls in this room. While sanding some dried mud tonight, I had a thought about how this experience was a lot like building software.
When building software, you’re not sometimes lucky enough to build a system from the ground up. Normally, you’ll inherit code from developers who have been hacking it for years. I related this to me working in my room. I inherited a poorly maintained room. The joints weren’t level with each other and the mud of the wall wasn’t smooth. The person doing the work took no pride in the work being done. The ceiling was also a “hacked” popcorn ceiling. I say hacked because, instead of using a hopper, the person slung dry wall mud onto the ceiling giving the illusion of popcorn. The illusion failed though because it looked horrible.
Fast forward to my work in the room last week. I had to go through and scrap all the excess mud off the wall. Each wall and joint had to be sanded, and mudded again in order to level everything. I’ve spend hours of time trying to reverse the effects caused by performing the job incorrectly.
What does this have to do with software development? Think about when you’re working on a bug in a piece of code, and it’s your first time looking at this code. How the previous developer left the code is how you’re going to inherit it. You might have to spend hours undoing the work of the previous person in order to get the code to a state it can be worked with. Hacks might have to be removed and properly implemented. Hours will be wasted that didn’t have to be.
When working on new code, do yourself and future developers a favor and leave the code in a state where it can be easily picked up and worked on. If you’re working on existing code, try to leave it in a better state than it was when you found it. In the long run, time will be saved, code will be more secure, and a developer will say fewer curse words.
-------------------------------------------------------------------------------- /blog/Building-better-ConnectionStrings-with-ConnectionStringBuilder.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Building better ConnectionStrings with ConnectionStringBuilder 3 | categories: 4 | - "Development - C#" 5 | permalink: building-better-connectionstrings-with-connectionstringbuilder 6 | date: 2011-02-14 05:00:02 7 | --- 8 | 9 | Okay, I never admitted to being a .NET guru or anything, and that’s why I get so excited whenever I run across a gem in the framework that allows me to do something easier and with fewer issues. 10 | 11 | ConnectionStrings has always been one of those things I did the hard way. For example, I would have a line of code that was like so: 12 | 13 |
14 | string connectionString = "Data Source={0};Initial Catalog={1};User Id={2};Password={3};";
15 | string.Format(connectionString, serverName, databaseName, userName, password);
16 |
17 |
18 | This seemed like a logical way to build my connection strings. However, it wasn’t very flexible. That was until I discovered the suite of ConnectionStringBuilder classes.
19 |
20 | Let’s take the above OleDb connection string and use the OleDbConnectionStringBuilder to build it.
21 |
22 |
23 | System.Data.OleDb.OleDbConnectionStringBuilder oleDbConnectionStringBuilder =
24 | new OleDbConnectionStringBuilder();
25 | oleDbConnectionStringBuilder.DataSource = "myServer";
26 | oleDbConnectionStringBuilder.FileName = "myAccessFile.mdb";
27 | oleDbConnectionStringBuilder.ToString();
28 |
29 |
30 | Look at how much cleaner that is! Maybe you’re working with a SQL Server database:
31 |
32 |
33 | System.Data.SqlClient.SqlConnectionStringBuilder connectionStringBuilder =
34 | new SqlConnectionStringBuilder();
35 | connectionStringBuilder.DataSource = "myServer";
36 | connectionStringBuilder.InitialCatalog = "databaseName";
37 | connectionStringBuilder.UserID = "userName";
38 | connectionStringBuilder.Password = "password";
39 | connectionStringBuilder.ToString();
40 |
41 |
42 | Isn’t that awesome?! Now, finally, let’s imagine you’re doing all this with Entity Framework:
43 |
44 |
45 | System.Data.EntityClient.EntityConnectionStringBuilder entityConnectionStringBuilder =
46 | new EntityConnectionStringBuilder();
47 | entityConnectionStringBuilder.ProviderConnectionString = connectionStringBuilder.ToString();
48 | entityConnectionStringBuilder.Metadata = "(entity framework metadata here)";
49 | entityConnectionStringBuilder.ToString();
50 |
51 |
52 | There you go! Instead of hand writing your connection strings, take a look to see if there is a StringBuilder class that’ll do the work for you.
--------------------------------------------------------------------------------
/blog/Banks-ATMS-and-Horrible-User-Experiences.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'Banks, ATMS, and Horrible User Experiences'
3 | permalink: banks-atms-and-horrible-user-experiences
4 | categories:
5 | - Deep Thoughts
6 | updated: '2015-08-20 21:52:06'
7 | date: 2015-08-03 09:18:46
8 | ---
9 |
10 | *Note: I'm pretty much going to rant about a bank experience I had. Lessons aren't obvious, but if you're designing something that's pretty dang important... make sure you have failsafes built-in.*
11 |
12 | I went to my local ATM yesterday to deposit a couple checks. I know, I know... why didn't I just use my phone? Turns out banking phone apps have limits on how much you can deposit through the app and I was well past that limit. ATM was a logical second choice if I didn't want to have to make visit to a teller.
13 |
14 | Generally, this type of visit is quick.
15 |
16 | 1. Pull up to ATM
17 | 2. Insert ATM card
18 | 3. Type in PIN number
19 | 4. Press DEPOSIT, select account.
20 | 5. Insert checks (optical reader will automatically figure out amounts)
21 | 6. Receipt, and on my way!
22 |
23 | Problem started around step 5. I put my checks into the reader where it proceeded to give me a "PROCESSING YOUR DEPOSIT" screen. Normally, this process takes 10 seconds.
24 |
25 | Ten seconds pass...
26 | Then a minute...
27 | OKAY.. five minutes...
28 |
29 | I'm starting to get a bit freaked out because I put a couple good sized checks into a machine and it's not doing anything!
30 |
31 | Next step is to try to call someone. My bank provides a 1-800 number for customer service. Turns out, there is no logical path for "OMG THE ATM STOLE MY CHECKS AND IS FROZEN". And really, there is no path for "I request to speak to a human who can properly direct this call."
32 |
33 | 30 minutes into my freak. I turned two other folks away because ATM was borked. All of a sudden, the screen flashes and pretends like NOTHING HAPPENED AT ALL. "Would you like to deposit the checks?" I pressed the **go** button and the ATM spat my checks out and told me to have a nice day. Wat?
34 |
35 | I also had a decent "check hold" on my account, which is normal when checks are processed. The bank is still investigating what the issue might have been.
36 |
37 | I'm pretty fortunate that I decided to stick around - or else someone might have been able to swipe my checks. Why doesn't the ATM go into "maintenance mode" or something after five minutes of not responding? Thirty minutes is way too long to wait for any sort of respond.
38 |
39 | On another note, why is there physically no way to talk to a human on the phone? At a minimum, I wanted the bank to have an option to "Press 0 if you just need to talk to someone."
40 |
41 | Blah. What horrible user experiences have you had with technology?
--------------------------------------------------------------------------------
/blog/Speaker-Gifts.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Speaker Gifts
3 | categories:
4 | - Community, User Groups, and Conferences
5 | permalink: speaker-gifts
6 | date: 2015-01-13 17:47:38
7 | ---
8 |
9 | > This post is a part of a series I wanted to do on simple user group management tips.
10 |
11 | When you visit a user group, the person standing at the computer is most likely not being paid. In fact, a large majority of the technical speaker circuit is filled with unpaid speakers. Not only that, the speaker might incur costs just for having come out.
12 |
13 | **What costs would a speaker have?**
14 | Great question!
15 |
16 | * **Gas**
17 | Let's imagine someone is driving ~4-8 hours round trip to visit a user group. This will include one or two tanks of gas, depending on the type of vehicle you're driving.
18 | * **Hotel**
19 | If I'm driving more than 4 hours in one direction to visit a user group, I probably want to get a hotel for the night.
20 | * **Lost wages**
21 | Odds are if I'm driving to a user group, I need to take the afternoon off work. This means I'm burning PTO or (if you're like me), you're not billing time.
22 |
23 | Organizations like [INETA](http://www.ineta.org) have programs to help offset the costs of for speakers. For example, if I were to travel over 360 miles, INETA will reimburse me $200 for the trip. That's pretty good and covers most of my costs of speaking.
24 |
25 | **How can the user group help?**
26 | I understand that asking you to cover speaker costs is a huge thing. So I'm not going to do that. Still assume that speakers will come of their own freewill and will cover their own costs.
27 |
28 | Consider this: Your goal as a user group leader is to promote the local technology scene. You want to attract people to show up and learn, but you also want to attract great speakers!
29 |
30 | A couple months ago, our user group started a process of giving out speaker gifts. We don't promote it ("HEY EVERYONE! LOOK AT US GIVING A SPEAKER GIFT!"). Instead, the speaker loves the thought behind the gift and keeps us in mind for a return visit in the future.
31 |
32 | These speakers will then talk about you to their speaker friends. "Hey, those guys at the Hampton Roads .NET group are really cool. I definitely recommend getting on their calendar."
33 |
34 | **What kind of gift can we give?**
35 | We just give a $50 Amazon gift card in one of the fancy boxes. That's pretty good, and it's a cost we subsidize with sponsor money.
36 |
37 | A couple months ago, I visited a group called [GANG](http://migang.org) where they gave me a engraved metal mug. That was awesome, and it makes me definitely want to come back.
38 |
39 | Why not start simple and give the speaker a thank you card signed by all the organizers and some of the attendees? Every little bit you can do makes a difference.
40 |
--------------------------------------------------------------------------------
/blog/Are-we-too-dependent-on-the-Internet.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Are we too dependent on the Internet?
3 | permalink: are-we-too-dependent-on-the-internet
4 | categories:
5 | - Deep Thoughts
6 | updated: '2010-01-19 06:00:00'
7 | date: 2010-01-19 06:00:00
8 | ---
9 |
10 | In my office, there lives a monster. This monster is called “The Internet Killer,” and he likes to poke his head out every now. When he does, our internet goes down for hours upon hours. During this time, I still have work too do, but I often find that my production level is limited by the lack of internet.
Are we too dependent on the Internet?
I’m in that weird generation where I have had access to the Internet for most of my life, but I can still remember not having it. I have used a card catalog. I have used an encyclopedia. I have had to retain knowledge for more than a few minutes.
This was also around the time I started learning how to program. My first few BASIC applications were self taught from a help file. I didn’t have an Internet to go to whenever I ran into a problem. I was forced to either figure it out on my own, or travel to the library to reference whatever material (if they had any material at all). Having to work through these issues forced me to retain knowledge for an extended period of time. You never knew when you were going to have use what you had learned before.
Fast forward to today. I’m working on a few features for a project, and we lose our internet. You might be saying, “Kevin, you should be able to code just fine without the internet.” And you are right, I should be able to. However, if you’re venturing into territory that you’re not familiar with, your work is either going to take two or three times as long as it would had you had access to reference materials.
“Have you ever heard of books?” Yes, and I have plenty of them. Books are hard to reference. Books are awful for troubleshooting problems. Can you type an error string or code into a book? How long does it take to find a book that might have the information you’re looking for? Does it actually contain information that is useful, or just code snippets that is causing the error you have?
Google (Bing, or whatever you use) is fast, accurate (for the most part), and easily accessible. The “whole world at your fingertips” is no joke. Within minutes, I have access to references, books, blogs, forums, etc. Your problem is never new, and the Internet is quick to provide answers.
Does the internet make us stronger, or is it making us weaker? I’ll let you decide.
-------------------------------------------------------------------------------- /blog/i-removed-email-from-my-phone.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: I Removed Email From My Phone 3 | categories: 4 | - Deep Thoughts 5 | permalink: good-bye-email 6 | date: 2018-05-01 09:54:52 7 | --- 8 | Several years ago, [I wrote about how I was taking steps to reduce my dependence on email](https://kevgriffin.com/beating-email-addiction/). You should go give it a read if you haven't before. 9 | 10 | Like a good diet, I fell off that bandwagon after months and months of doing `really well`. 11 | 12 | Since I own my [own business](https://swiftkick.in), I spend a lot of time in email conversing with clients, employees, contractors, and random people I'm trying to convince to give me money. I organize [conferences](https://revolutionconf.com), [user groups](http://hrnug.org), and a variety of other professional events. I'm active in my church, and get CCed on just about everything. 13 | 14 | I came to the realization that email itself was making me anxious. 15 | 16 | For example, I'd get up in the morning and quickly check email as a part of my morning routine. Some days were fine, but then other days I'd get an email that would **totally ruin me for the entire day.** 17 | 18 | Email became my fidget. If I was standing in line at the store, at a stop light, or just walking towards a building, I'd get my phone out and quickly check my email. 19 | 20 | The absolute worse time to check email is when you physically cannot respond to it. Some emails I forgot about, accidentally archived, or just said "I'll deal with this later". 21 | 22 | Then one day I came to a realization: the email on the phone had to go. 23 | 24 | It was **so easy**. Delete. 25 | 26 | Additionally, I added a message to my email signature specifically stating that I'm returning to my twice-a-day email routine, and I did not carry it on my device. Emergencies needed to move to phone calls or text messages. 27 | 28 | You'd be amazed how quickly an "emergency" dies down when someone has to pick up a phone. 29 | 30 | As of this writing, I've been without email on my device for two weeks. My level of anxiety is pretty much gone. Email takes all of 5-15 minutes depending on what I need to respond to. And best of all, email can only happen when I'm at my laptop - and that is a controlled situation. 31 | 32 | I encourage everyone to take a break from email. Even if it removing notifications or reducing your time to twice daily -- it is amazing how liberating it can be to not need to check email constantly. 33 | 34 | We cannot forget that email is asynchronous. In the same way we'd have to wait for snail mail or carrier pigeon, and email doesn't need to be received or answered immediately. There is no difference between a 2 minute response time and a 12 hour response time. 35 | 36 | I'd love to hear your thoughts about email. Does it rule your life or have you figure out how to tame it for the best? Leave a comment below! -------------------------------------------------------------------------------- /blog/The-Zen-of-Free-Labor.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: The Zen of Free Labor 3 | categories: 4 | - Deep Thoughts 5 | permalink: the-zen-of-free-labor 6 | date: 2009-06-01 04:00:06 7 | --- 8 | 9 | Lets rewind back two years ago. I was a fresh software developer of our college. The major problem plaguing college students is that they do not have any practical experience. How do you obtain practical experience? You need to work! You need to make the mistakes you need to make to become a productive professional. 10 | 11 | Out of college, I knew exactly one programming language proficiently: C++. Proficiently is probably a poor choice of words. I KNEW C++, but I KNEW enough to make simple decisions and get the job done the best way I could. My first (technically second, but we won't go into that) professional job was all C#. I didn't know C#, but I knew enough C++ to become very comfortable with C#. In fact, one week after starting the job, I was adding new features to the project I was assigned too. 12 | 13 | However, I knew that I needed to expose myself to a several different technologies. My wife and I took a trip to Nashville and visited with some friends of ours. One night, I was having a discussion with my friend about his hobby, photography. We had ended up on the topic of him putting up a web page for all of his photos to sell. I thought it was a wonderful idea, and volunteered to build the site for him. The caveat was that I would do the site for free, seeing as how I needed to build up my skills in ASP.NET. He would pay for hosting, etc, and I would build the site for him. 14 | 15 | This was almost two years ago, and the site still remains undone. 16 | 17 | So what happened? Life happened! Paying jobs happened! Of course its a great idea to say that you're going to do something for free to help someone else. What happens though when you need to mow the yard? Stay late at work? Get sick? Spouse gets sick? The first thing you drop is the project you're not getting paid for. 18 | 19 | Fast forward to a year ago. I volunteered to work on my church website. Same scenario. I wanted an avenue to build on top of the ASP.NET skills I had, and I figured working on my church website was the best way to do that. The difference between this project and the first was that I needed the input of several people in order to make any progress on the site. When you're not being paid, the people you're doing the job for aren't as quick to respond to emails as they would if you were charging per hour for their response. This site will be done, but it's taken several months longer than it needed too. 20 | 21 | What's the moral of the story? You need work to show off in order to get more work. Offer to do a free project every now and then. Use it for experimenting with new technologies. Don't allow the project to get too complex. You don't have time for that. Get it done as soon as possible. If you let it go for too much longer, you're never going to complete it. That is, of course, you have more will power than I do. -------------------------------------------------------------------------------- /blog/Node-js-Using-require-to-load-your-own-files.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Node.js: Using require to load your own files' 3 | categories: 4 | - Development 5 | permalink: node-js-using-require-to-load-your-own-files 6 | date: 2012-12-31 06:00:31 7 | --- 8 | 9 | For a lot of JavaScript developers that are moving over from traditional "browser" development to node.js, they might be casually aware of the require keyword that node.js provides you. 10 | 11 | If you're wondering what I'm talking about, allow me to explain. In node.js, you can use the node package manager (NPM) to install packages that your application can use. Express, for example, is a great framework for serving up web applications, and you can grab it via NPM. 12 | 13 | To load Express into your application, you tell node.js that you "require" it be loading into memory. 14 |var express = require("express");
15 | Node follows a couple rules to find modules. First, you can ask for a module by name or by folder. Let's look at Express more closely. If you were to download Express via NPM, you'd find there is no express.js file in the root directly of the /node_modules/express folder. However, there is a package.json file that defines the main executable file for express (for fun, go look it up).
16 |
17 | Now, if packages.json doesn't exist or the main executable isn't present, node will resort to looking for your filename with either a .js, .json, or .node extension (unless you've specified).
18 | var userRepository = function (){
23 | var self = this;
24 | self.addUser = function (...){
25 | };
26 | self.get = function (...){
27 | }
28 | };
29 |
30 | module.exports = userRepository;
31 | Add this to a file called userRepository.js. The last line is VERY IMPORTANT! It tells node.js what you'd like to export from this file. This should make more since if you try to use the file.
32 |
33 | In your main.js or wherever you'd like to use userRepository:
34 | var userRepository = require("userRepository.js");
35 |
36 | var userRepositoryInstance = new userRepository();
37 | userRepositoryInstance.addUser({...});
38 | userRepositoryInstance.get(...);
39 | Looks simple doesn't it? Pretty much whatever you assign to module.exports will be passed into the variable that calls require().
40 |
41 | Use this to keep your code clean and uncluttered. This is only the basics of using require for your own projects, but I think it's a great starting point for developers building their knowledge of node.js. In the future, I'd like to expand on this topic and show you how you can take this even farther.
--------------------------------------------------------------------------------
/blog/Book-Review-Financially-Stupid-People-Are-Everywhere.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'Book Review: Financially Stupid People Are Everywhere'
3 | date: 2018-08-03 09:34:31
4 | tags:
5 | categories:
6 | - Reviews
7 | permalink: book-review-financially-stupid-people-are-everywhere
8 | ---
9 |
10 | *For this review, I purchased my own copy of the book on Audible. If you buy your own copy, I would love it if you used one of my links.*
11 |
12 | $.connection.hub.start().done(function () {
21 | alert("Connected!");
22 | var myClientId = $.connection.hub.id;
23 | setCookie("srconnectionid", myClientId);
24 | });
25 |
26 | function setCookie(cName, value, exdays) {
27 | var exdate = new Date();
28 | exdate.setDate(exdate.getDate() + exdays);
29 | var c_value = escape(value) + ((exdays == null) ? "" : "; expires=" + exdate.toUTCString());
30 | document.cookie = cName + "=" + c_value;
31 | }
32 | As you can see, this gets the ConnectionId from the hub connection and stores it in a cookie.
33 |
34 | 2) Use your own IConnectionIdFactory
35 |
36 | This might be scary territory for you, but it’s actually pretty simple. We want to create our own version of the IConnectionIdFactory interface for SignalR to use.
37 | public class MyConnectionFactory : IConnectionIdFactory
38 | {
39 | public string CreateConnectionId(IRequest request)
40 | {
41 | if (request.Cookies["srconnectionid"] != null)
42 | {
43 | return request.Cookies["srconnectionid"];
44 | }
45 |
46 | return Guid.NewGuid().ToString();
47 | }
48 | }
49 | This does two things. First, it’ll check your cookie for a ConnectionId it should use. If it exists, we’ll simply return that ConnectionId and all will be good in the world.
50 |
51 | If the cookie does NOT exist, we need to generate one. By default, SignalR uses a GUID, so we’ll just repeat that functionality. You can use any value you want, but make sure it’s unique.
52 |
53 | Don’t forget to wire it up! Add this to you Global.asax file under Application_Start().
54 | AspNetHost.DependencyResolver.Register(typeof(IConnectionIdFactory), () => new MyConnectionFactory());55 | And you’re all set! SignalR will now use your new ConnectionIdFactory to generate or reuse ConnectionIds. 56 | 57 | Enjoy! -------------------------------------------------------------------------------- /blog/Open-Source-Mentality-of-Choosing-Your-Tech-Stack.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Open Source Mentality of Choosing Your Tech Stack 3 | categories: 4 | - Deep Thoughts 5 | permalink: open-source-mentality-of-choosing-your-tech-stack 6 | date: 2016-07-04 16:06:21 7 | --- 8 | 9 | When I initially wrote *Non-Tech Factors to Consider When Choosing Your Tech Stack*, I left out one important conversation point: Open Source. 10 | 11 | [Steve and Carol](http://kevgriffin.com/non-tech-factors-to-consider-when-choosing-your-tech-stack/#comment-2671492103) got me in the comments. 12 | 13 | ###How should Open Source affect your decision to choose a tech stack? 14 | 15 | In a previous life, I used to work for a component vendor. Our company built, sold, and supported a variety of components that saved developers time. I had the opportunity to meet thousands of awesome developers who do the hard work every day in the trenches. 16 | 17 | I always questioned why people bought our stuff. The internet at the time was already full of dozens of comparable or better components which were open sourced. Buying our components seemed like an extreme waste of resources. 18 | 19 | That was until I understood the value-cost of SUPPORT. One of our customer was a large financial firm who bought hundreds of developer licenses to a library. This library wasn't anything special - but any of those developers could instantly request technical support from the project manager for the library. (Normal people would have to go through traditional support means, but still had good service.) 20 | 21 | Imagine same company, same team - they decide to use a popular component that is 100% open source. Same team runs into a technical hurdle: either a flaw in the component, or a flaw in the developer's understanding of the component. 22 | 23 | Where does a developer go in this case? Google? Stack-overflow? Github issues? 24 | 25 | A common phrase amongst open source maintainers is "we accept pull requests". I used to believe this was mean-spirited, but you have to understand that folks that manage an open source project have lives and other concerns then your bug. Roll up your sleeves and dive in. 26 | 27 | ###You didn't answer the question: How should Open Source affect your decision to choose a tech stack? 28 | 29 | In the soft-factors article, I discussed that some developer-types just are not suited to work with new technology. Same goes for open source. 30 | 31 | If a developer or team is not comfortable getting their hands dirty in public code, there is NO WAY they should integrate open source software. Don't expect a maintainer to bend over backwards to solve your problem or push you in the right direction. Some do -- but many don't have the bandwidth for that. 32 | 33 | There are some exceptions to this though. Consider massive open source projects such as jQuery, Angular, React, and the .NET Framework. These products are open source and accept pull requests, but they are backed by large organizations who have a vested interest in keeping the projects up and running. You cannot pick up a phone and dial support, but you can file an issue and a team of developers will take you seriously. 34 | 35 | ###You are not alone 36 | The general developer community is amazing. There are thousands and thousands of developers out there that will at least attempt to push you in the right direction if you hit a snag in an open source project. 37 | 38 | I love open source software, and I greatly take for granted the hard work many people have put into my favorite projects. 39 | 40 | Open Source software isn't going away either. The movement is going to grow larger than it is today, and if you are not on the bandwagon as at least an observer, it is going to leave you behind. 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /blog/How-I-m-Beating-Email-Addiction.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: How I'm Beating Email Addiction 3 | categories: 4 | - Deep Thoughts 5 | permalink: beating-email-addiction 6 | date: 2015-05-21 09:54:52 7 | --- 8 | 9 | Today, I really want to talk about email, because I see people everywhere having the same issue with email that I had. I used to be REALLY addicted to email. When I use to wake up in the morning, first thing I would do is check my email on the phone. After sitting at my desk, I would open my email tab and leave it up all day. At night, I would habitually pull out my phone to see if a new email came in. 10 | 11 | It was like I was a drug addict always needing a fix. I couldn't do it anymore. 12 | 13 | One day, I was watching a video and the gent talking said something that kicked off my intervention. 14 | 15 | >Your email is someone elses TODO list for you. 16 | 17 | Holy crap. That hits home. But think about it! Our email serves a couple purposes: 18 | 19 | **Informational**. Reservations reminders, events coming up, someone's address or phone number. These emails have a purpose, but it's not necessary that you act on them immediately. This email totally falls into that category. Gmail categories these under Social, Forums, and Updates. 20 | 21 | **Request followup**. Let's say you ask someone to provide some information. "Hey Kevin, here is the powerpoint you asked for." Remember, if you sent the request for something, you've injected a TODO into someone's list. 22 | 23 | **Promotional**. People try to sell you stuff, but legitimate. Amazon does this a lot. "Hey Kevin, noticed you were looking at chainsaws. Here's a great list of popular ones online." 24 | 25 | **Spam**. It's meat, in a can. 26 | 27 | Email is also asynchronous. That means when I send an email, it can get a response within five minutes or 5 months. It's safe to send some emails and close the tab! It's also a false expectation of others to think you're going to respond to an email within a few minutes. 28 | 29 | I want to share a couple tips for how I broke my email addiction: 30 | 31 | ##I turned off email notifications on my phone 32 | This is groundbreaking! I was so programmed to look at my phone whenever it beeeped, it was maddening. The phone could even be on the other side of the house, and that beep would cause me to stop what I was doing and hike to get it. For what? A statement from the cell phone company. Not worth it. 33 | 34 | This also had the side effect of increasing battery life of my phone. Since it wasn't consistently checking for email, I was getting more battery life. Did you know if don't touch a phone all day, it'll only use like 5% of it's battery? 35 | 36 | ##I limited email time to twice a day 37 | In the morning, I put together a todo list for the day. Part of that is checking email. Since email is a todo list from others, it makes sense for me to look at my email, determine what needs to be responded to, and add it to my list. Some email will be immediate responses. Why add them to the list if all I need to respond with "yes" or "no"? 38 | 39 | Next, I'll check email towards the end of the day. Any email I sent in the AM might be responded too, unless they read this. It also gives me a chance to look at my todo list, and send emails that needed to be sent. It also prevents me from doing off the cuff emails that I would later not have sent. 40 | 41 | ##Inbox zero should be a goal, not a requirement 42 | A lot of folks talk about empty inboxes, and I agree to a point. I believe all emails that you need to follow up with some be archived off and added to your TODO list. My Todo program Todoist has an add-on that allows me to add emails to my todo list. 43 | 44 | Sometimes you might just want to keep an email front and center. That's okay! But anything that isn't important should hit the trash or the archive. -------------------------------------------------------------------------------- /blog/Managing-Your-User-Group-Sponsor-Relationships.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Managing Your User Group: Sponsor Relationships' 3 | permalink: user-group-sponsor-relationship 4 | categories: 5 | - Community, User Groups, and Conferences 6 | date: 2015-01-26 11:58:38 7 | --- 8 | 9 | As a user group leader, you might have this feeling that you need to get sponsors for your user group. **This is a common feeling!** 10 | 11 | In fact, it's one of the most common questions I get as the Director of Membership for INETA. I've seen groups that bend over backwards for sponsors, such as providing attendee lists (with contact information) or letting them do 15 minute sponsors presentations. Over marketing is a huge turn off for attendees, and has potential to limit the growth of your group. 12 | 13 | > For purposes of this discussion, a sponsor is a recruiter, headhunter, placement firm, etc. Pretty much anyone that wants to hire your talent pool. 14 | 15 | > Yes, venues are sponsors. Vendors are sponsors. But that's a different dynamic. The majority of user group "sponsors" are going to be companies looking to place workers. 16 | 17 | I want to offer you a different perspective before you go out and solicit for user group sponsors: 18 | 19 | **What do you offer?** 20 | 1. Access to a community of professionals interested and dedicated to a particular technology. 21 | 2. An environment specialized for engagement and learning. 22 | 3. Mailing lists (maybe) 23 | 4. Discussion boards (maybe) 24 | 25 | Over all, you have a supply of **talent**. Nevermind the skill ranges, but you have a group of folks who are 10% higher than anyone else on the market. Why? Because they're showing up. That's worth gold and more to the right employer. 26 | 27 | **What do they offer?** 28 | 1. Pizza money 29 | 2. Access to a hidden community of professionals they've placed in positions across the region. 30 | 31 | I'm going to call #2 a farce and this is *totally based on my experience.* I've had many sponsors (recruiters) say "We'll send the word out to our people and see if we can get out to the group." But the people don't come. 32 | 33 | So that leaves #1. Food. Drinks. Substance of some kind. 34 | 35 | **How does this empower you?** 36 | THEY need you more than YOU need them. Let's look at a worse case scenario: *you have no sponsors for food*. 37 | 38 | ***Oh well.*** 39 | 40 | When I started my first user group back in 2009, I was scared silly that people wouldn't show up because there was no free food. Put it this way: if someone is coming only for free food, you don't want them at your group anyway. 41 | 42 | I begged for sponsors. "Please please please bring us free food." 43 | 44 | Later, I started getting competition for sponsorships. These companies know what you have, and they WANT to be involved. Use this to your advantage. For us, it meant paying for the right to sponsor a meeting. Twelve meetings per year, that's something worth monetizing. 45 | 46 | Take that last paragraph with a grain of salt. It's a real *first world problem*. Smaller groups might not want to pull that card, and that's okay. But don't bend over backwards for sponsors. 47 | 48 | >THEY need you more than YOU need them. 49 | 50 | **How can I supplement not having a sponsor?** 51 | Donations? A lot of smaller groups throw out a hat for pizza money, and people put money into it! 52 | 53 | Try a shorter meeting without food? 54 | 55 | Create a post-meeting outing that everyone is invited to. At our group, we started a tradition of going to a local diner for pie. Get creative! 56 | 57 | **Wrapping up** 58 | Running a user group is hard. Your thoughts on priorities might be out of line with what they really should be. Some of the best user groups I've been to have started in IHOPs or as meetings at a Starbucks. 59 | 60 | You don't need sponsors. You *want* sponsors. And you hold the high card in this game. 61 | -------------------------------------------------------------------------------- /blog/Definition-of-a-Computer-Scientist.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Definition of a Computer Scientist 3 | permalink: definition-of-a-computer-scientist 4 | categories: 5 | - Deep Thoughts 6 | date: 2009-03-04 15:26:24 7 | --- 8 | 9 | What is a computer scientist? Google gives the definition: a scientist who specializes in the theory of computation and the design of computers. In most of our minds, a computer scientist is a person that builds computer systems. More recognizable names (at least in terms of what a person with a computer science degree would be hired for) for a computer scientist would be developer, coder, software engineer, or software architect. A lot of people will argue with me that computer scientist is more than just a coder, and I would fully agree. Although, when a person wants to be a software developer, they are forced most of the time into a computer science program, as it's the best way for they to obtain the skills required to build large software systems. 10 | 11 | But the definition is besides the point. The real point of this post is to comment on a conversation retold to me by a colleague who's taking a senior-level college course. To put the conversation into perspective, I need to describe the course (and for the record, I have taken this course myself several years ago). This course is a project management course for wannabe computer scientists. In the first semester of the class, students are required to come up with "problems" and probable solutions to them. The problem and solution are then pitched to a panel of industry professionals. The solution is actually implemented within the second semester. As you might think, developing a problem from within thin air is quite daunting. Eventually though, students discover a problem that obtains approval from the professor. 12 | 13 | This conversation spawned due to my colleague's group not being able to find a problem. As far as I was told, several problems were proposed and spot down. When a particular idea was shot down, the professor said, "Your job as computer scientists is to innovate." 14 | 15 | This statement is just *wrong*. Your job as a computer scientist is not to innovate! Your job as a computer scientist is to SOLVE PROBLEMS. Now, it is possible for a problem to be solved in an innovative manner, but you should never innovate for the sake of innovation. In the real world (definition: the world outside of academia), you will be given problems to solve, and you will be expected to solve them. Furthermore, you will be given your problems, not expected to discover them on your own. Creating your own problems to solve would make you an entrepreneur, not a computer scientist (which you would be when you actually solved the problem). 16 | 17 | For example, let's say I have a glass window and at 5:00 everyday the sun shines through, displaying a terrible glare on my computer screen. An innovative solution to the problem would be to design a microfilm composite that reduced the glare depending on the amount of sunlight shining through. Another solution would be to buy a set of blinds. Not "innovative" by any means, but it solved the problem. 18 | 19 | What advice do I have for the group of computer science student trying to get through this project? Don't try to come up with a brand new problem. That's impractical, or the solution to the problem is to high of a level for you to understand as an undergraduate. Instead, try to take an existing problem with bad solution. I guess you could say you should take a bad solution and *innovate*? Ideally, you just want to get through the semester. When you enter the "real world", the problems will come to you. At least these problems will be paid, and you won't have to worry while worrying about an English midterm, linear algebra homework, and your seventeenth algorithms assignment. 20 | 21 | Finally, take everything your professor says with a grain of salt. They probably haven't seen the real world in a long time. -------------------------------------------------------------------------------- /blog/Colossal-Failures.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Colossal Failures 3 | categories: 4 | - Deep Thoughts 5 | permalink: colossal-failures 6 | date: 2010-03-02 06:00:00 7 | --- 8 | 9 | One of my favorite television shows is Mythbusters. It’s not that I’m enthralled with the myths themselves, but the engineering required prove the myths correct or incorrect (“Confirmed” or "Busted!”). 10 | 11 | Recently, I ran across a session by Adam Savage talking about Colossal Failures. Here is the video if you have an hour to kill (really the first 30 minutes is all you need to listen to), or just skip ahead. 12 | 13 | 14 | 15 | (If you can't see the video above, please view in your browser and not in an RSS reader) 16 | 17 | This video is inspiring for me. Adam talks about two instances where he took on a task where he bit off more than he could chew. First, he talked about having to build a baseball throwing machine for department store display. The store was under tight restrictions, and gave Adam less than a week to design, build, and implement this system. Adam didn’t succeed due to dozens of unforeseen issues. 18 | 19 | Second, Adam talked about having to build a set complete with a talking ATM. He ran into tons of issues, and didn’t have anything done for the first day of filming. He was asked to go home, and then several days later was asked to come back to get a verbal flogging from the crew. 20 | 21 | What does this mean to us? 22 | 23 | Failing is a method of learning. Failing is a bit of a subjective term. If you've made a mistake, you’ve failed. Some failures are easier to rebound from than others. However, failures are worth it if you learn something from them. 24 | 25 | Adam learned that while he does good work by himself, the common trait of both his examples was that he didn’t ask for help. Some jobs are too large for a single person to take on by themselves. Keep a good network around you of people you trust and respect. These people can be lifelines in the most frustrating times of a project. Don’t have a network? Look for a community event in your area. 26 | 27 | How have I failed? 28 | 29 | I’ve walked into several situations where I had no idea what I was doing. Being a younger developer, I don’t have the experience as someone with 10 or 15 years experience. In my current shop, most projects are on the shoulders of one or two developers. With any project that has come across my path, I’ve picked them up and ran with them the best I could. As Adam said, I was “making it up as I went.” I made several poor decisions that seemed good at the time. When I discovered they were bad decisions, I took immediate steps to fix them. Never leave a bad decision for someone else to clean up. Step up and accept them, and then proceed to make it right. Adam talked about providing money back to his customers. He accepted his failures, and wanted to take steps to make it right (even if it meant giving up part of his pay). 30 | 31 | Preventing Failures 32 | 33 | Keep a support structure. Join a user group or visit a code camp. Keep learning. Surround yourself with people smarter than you. Listen to their advice (but take all advice with a grain of salt). One person will sometimes succeed, while a team will never fail. -------------------------------------------------------------------------------- /blog/I-suck-at-writing-unit-tests-but-I-m-trying-to-change.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'I suck at writing unit tests, but I''m trying to change' 3 | permalink: i-suck-at-writing-unit-tests 4 | categories: 5 | - Deep Thoughts 6 | date: 2015-02-26 22:25:55 7 | --- 8 | 9 | *65 tests* 10 | 11 | I have just hit a personal record when it comes to writing unit tests. A measly 65 unit tests. I've always noticed that there are three types of developers: those that never test, those that are pragmatic about testing, and then those that say TEST ALL THE THINGS. 12 | 13 | Most of my career has been in the first camp. I never tested my code. That's what QA departments were for. The team would write a feature, and ship it off for testing. Most of the times it would get a thumbs up, or it would get rejected because if you held the 'T' key while jumping up and down and patting your head, the computer would explode. 14 | 15 | >... those who are out there doing "Unit Testing 101" talks really suck at them. 16 | 17 | *68 tests* 18 | 19 | Within the past five years, I've grown to really appreciate the **WHY** you should unit test - but the **HOW** had left me in stitches. And let's be honest about it: those who are out there doing "Unit Testing 101" talks really suck at them. Not that the material is bad, but the concepts are too simplified. 20 | 21 | *Today, we're going to create unit tests for our calculator service. If I Add 5 and 5, I should get 10. Yay green!* 22 | 23 | *Today, we're going to create unit tests for our bowling score tracker. If I bowl a strike, but then a 7, I should get a 17 in the first frame.* 24 | 25 | No no no. I live in a world where I talk to external dependencies like databases, web services, etc. In .NET land, that's why you start learning about great things like Dependency Injection. *"Oh Kevin, your tests shouldn't talk to a database. Instead, you should have an interface for talking to a datasource and then write a mock implementation of that."* But.. but.. my applications talks to a database. 26 | 27 | I worked on a small project where I wrote a bunch of tests based around mocks only to determine that I wasn't testing any of the freakin' code. My fake code was tested fabulously! 28 | 29 | *72 tests* 30 | 31 | **Seeing the light** 32 | I had this amazing revelation during a 7 hour car ride with my friend, [Kendall Miller](https://twitter.com/kendallmiller). In a nutshell, he said, "We just stand up the database." Mind. Blown. Imagine this concept: being able to stage your entire application in a couple seconds. Not only are you testing that you're able to insert or update records, but you're continuously testing if your database creation scripts are up to date. 33 | 34 | **It's all baby steps** 35 | For a new client, I have pushed myself really hard to make sure that most aspects of the business and data layers have testing around them. All new features get a series of tests. This is well before I start implementation in the UI. As a result, I'm gradually ensuring that my application works the way that I expect it too. 36 | 37 | A lot of code is written to support the tests. For example, between each test I want to wipe the database clean and start with good data. I am testing a "unit", aren't I? No two tests are dependent on each other. 38 | 39 | **Keep on moving** 40 | I feel really good about this code. There isn't anymore of this ridiculous writing of fake implementations. I'm finding that with every test I write, I'm learning something new. If you find yourself in a similar place as me: wanting to write tests, but it has always seemed too impractical or too complex, I want to offer you some advice. 41 | 42 | Just do it. Write one test. Is the code you want to test too complicated or too involved? That is a great excuse to break it up and refactor. Find someone who really knows or really enjoys writing tests and ASK them for feedback and guidance. They might hurt your feelings, but that's okay. Don't forget why you're doing this! Your code will get better. Your code will stay better. Practice makes perfect! 43 | 44 | Now get out there and write some tests! 45 | -------------------------------------------------------------------------------- /blog/SignalR-Transports-Explained.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: SignalR Transports Explained 3 | categories: 4 | - Development - ASP.NET 5 | permalink: signalr-transports-explained 6 | date: 2015-08-17 21:52:00 7 | --- 8 | 9 | When I sit down to talk to people about SignalR, a common discussion we have is around transports and what the difference between them are. While SignalR gives you the flexibility to choose your own transport, it is often a better bet to simply allow the library to choose for you. 10 | 11 | ## How does SignalR determine which transport to use? 12 | 13 | There are two pieces of the puzzle that need to be evaluated before a transport is chosen. The **client** and the **server**. Keep in mind, a SignalR client can be something other than JavaScript.. and the server can be something not running on IIS. 14 | 15 | If you [head over to SignalR documentation](http://www.asp.net/signalr/overview/getting-started/introduction-to-signalr#transports), they provide a really great overview on how SignalR chooses a transport. 16 | 17 | A simple way to explain the process is this: 18 | 19 | 1. If you're using legacy browser (IE8 or later.. *cough*)... use Long Polling. 20 | 2. Do you need JSONP support? Yes? Long polling, for you. 21 | 3. Okay okay. Let's try Websockets! This works well IF: 22 | * You're not doing JSONP 23 | * You're not going cross-domain 24 | * You ARE going cross-domain AND client supports CORS (Cross-Origin Resource Sharing). 25 | * Client supports WebSockets **(IE10+, Chrome, Firefox, Safari, etc)** 26 | * Server supports WebSockets **(IIS 8.0+ or self-hosted SignalR)** 27 | 4. No WebSockets? Sorry. Give Server Sent Events a try (most likely on non-IE browsers). 28 | 5. No SSE? Try Forever Frame (IE browsers). 29 | 6. No FF? MORE LONG POLLING! 30 | 31 | ## What are the pros and cons of each transport type? 32 | Excellent question! Let's walk through the list worse-case to best-case. 33 | 34 | ### Long Polling 35 | Long polling is a game of hurry up and wait. During this process, you are opening up a pipe (AJAX call) for the server to use for possible future communication. Anytime the server needs to send a message, the existing connection can be used. 36 | 37 | However, when a connection is used, the connection is closed. In order to continue communicating with the server, a client will need to reestablish the connection. In a best case scenario, the server is continuously sending data, so a connection is always reestablishing. Worse case, the connection stands open for up to two minutes (default timeout on most browsers). The process of continuously opening and closing connections can be a bit of a strain on the server. 38 | 39 | Long polling works well on old browsers, including some browsers which should have died ten years ago. This is the final fallback position if no other acceptable transport can be used. 40 | 41 | ### Forever Frame 42 | Warning: Forever Frame (FF) is Internet Explorer only, but it's really interesting how this process works. When a connection is established with FF, a hidden Iframe is created on the page. However, the page loaded into the Iframe is special. The connection will never closed. 43 | 44 | Since the connection remains open forever, the server can use it to continuously send new script. These scripts are loaded and executed on the parent page. 45 | 46 | Any client to server communication needs to be done the traditional way, via AJAX calls. 47 | 48 | ### Server Sent Events 49 | Some technologies stand the test of time, and Server Sent Events (SSE) is a great example. SSE is a server to client communication protocol developed in the Netscape days. It creates an object called an EventSource, which is a pipe from the server to the client. Anytime the server needs to send data, the EventSource pipe can be used. 50 | 51 | SSE is supported on all browsers, except Internet Explorer (sorry, but you have Forever Frame). Just as Forever Frame, if the client needs to communicate back with the server, a traditional AJAX call will need to be made. 52 | 53 | ### WebSockets 54 | Holy. Grail. Seriously. There is nothing better than WebSockets. When a WebSocket connection is made, there is a one-to-one connection between the client and server. Both are capable of communicating on the existing pipe. 55 | 56 | Of course, you are technically limited by the browser and server being used for a connection. Internet Explorer 9 and older need not apply (IE10+ are the only versions with WebSockets support). Firefox, Chrome, and Safari generally have no problems. 57 | 58 | For .NET folks deploying to IIS, you better be sure you are using IIS version 8 (or greater). IIS7 did not have support for WebSockets. 59 | 60 | ## Pulling It All Together 61 | As you look at the various transports available, you should start to appreciate what SignalR is doing for you underneath the scenes. What would happen if you had to implement all these different scenarios yourself? -------------------------------------------------------------------------------- /blog/Using-Unity-for-Dependency-Injection-with-SignalR.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Using Unity for Dependency Injection with SignalR 3 | categories: 4 | - "Development - ASP.NET" 5 | permalink: using-unity-for-dependency-injection-with-signalr 6 | date: 2013-01-08 06:00:31 7 | --- 8 | 9 | I've had bit of a day, and a large part of it was learning how to wrangle SignalR into using my dependency injection provider (in this case, being Unity). There are a couple thoughts, that I'd like to communicate to you all in case you're looking to do the same thing. Also, if you have suggestions on what I could do differently, I'm more than open to hearing. This is solution that worked for me, and I'm hoping it'll work for you. 10 | 11 | NOTE: This is built using SignalR v1.0-RC, which is a Prerelease NuGet package. I'll try to update if this changes after release. 12 | 13 | First, what do we want to do? 14 |
public class MyHub : Hub
15 | {
16 | public MyHub(ISomeInterface interface)
17 | {
18 | // handle constructor injection here
19 | }
20 | }
21 | There's a hub, but it doesn't have a default constructor. I'd like to be able to have SignalR automatically INJECT the constructor requirements when we load a new instance of the Hub.
22 |
23 | There are TWO things we need to do. First, we need to build our container (with Unity) and tell SignalR to use it.
24 | public static void Initialise() // this isn't my misspelling, it's in the Unity.MVC NuGet package.
25 | {
26 | var container = BuildUnityContainer();
27 |
28 | var unityDependencyResolver = new UnityDependencyResolver(container);
29 |
30 | // used for MVC
31 | DependencyResolver.SetResolver(unityDependencyResolver);
32 | // used for WebAPI
33 | GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
34 | // used for SignalR
35 | GlobalHost.DependencyResolver = new SignalRUnityDependencyResolver(container);
36 | }
37 |
38 | private static IUnityContainer BuildUnityContainer()
39 | {
40 | var container = new UnityContainer();
41 |
42 | // register all your dependencies here.
43 | container.RegisterType<ISomeInterface, SomeInterface>();
44 |
45 | return container;
46 | }
47 | Simple enough. You might want to know what SignalRUnityDependencyResolver looks like:
48 | public class SignalRUnityDependencyResolver : DefaultDependencyResolver
49 | {
50 | private IUnityContainer _container;
51 |
52 | public SignalRUnityDependencyResolver(IUnityContainer container)
53 | {
54 | _container = container;
55 | }
56 |
57 | public override object GetService(Type serviceType)
58 | {
59 | if (_container.IsRegistered(serviceType)) return _container.Resolve(serviceType);
60 | else return base.GetService(serviceType);
61 | }
62 |
63 | public override IEnumerable<object> GetServices(Type serviceType)
64 | {
65 | if (_container.IsRegistered(serviceType)) return _container.ResolveAll(serviceType);
66 | else return base.GetServices(serviceType);
67 | }
68 |
69 | }
70 | What's going on here? We're creating a new SignalR dependency resolver, and inheriting from the default dependency resolver that SignalR uses. When SignalR goes to resolve a dependency, we're first going to ask Unity if it has an existing implementation. If it does not, we pass the request on to SignalR to get its default (if one is available).
71 |
72 | Why do we have do this? First, you can just replace the IoC container altogether, but I have had no luck registering all the various types that SignalR uses. This was by far an easier approach.
73 |
74 | You'd like to think everything will just work now, right? Wrong. The dependencies in your hub still will not injected. My understanding is that this is by design, so here's how to work with it.
75 | private static IUnityContainer BuildUnityContainer()
76 | {
77 | var container = new UnityContainer();
78 |
79 | container.RegisterType<ISomeInterface, SomeInterface>();
80 | container.RegisterType<MyHub>(new InjectionFactory(CreateMyHub));
81 |
82 | return container;
83 | }
84 |
85 | private static object CreateMyHub(IUnityContainer p)
86 | {
87 | var myHub= new MyHub(p.Resolve<ISomeInterface>());
88 |
89 | return myHub;
90 | }
91 | This should be simple to follow. I'm registering a new type: MyHub, and telling Unity how to create a new instance of it. Creating it involves resolving the interface myself, and creating the new instance. This instance gets routed through SignalR and eventually executed.
92 |
93 | I'm also a user of StructureMap and Ninject, and I need to sit down to figure out this same process with those frameworks (if I even need to). If you already have experience with them, let me know what you did.
--------------------------------------------------------------------------------
/blog/What-Makes-A-Good-Bug-Report.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: What Makes A Good Bug Report?
3 | categories:
4 | - Development
5 | permalink: what-makes-a-good-bug-report
6 | id: 618
7 | updated: '2009-09-23 06:00:39'
8 | date: 2009-09-23 06:00:39
9 | ---
10 |
11 | As developers, we understand one fundamental truth: our software is going to break. It's not a matter of if, it's a matter of when. Hopefully on your team, you have a dedicated testing staff. Other teams are not quite as lucky. Their testers might be the project manager, or a single person who's responsible for testing all software produced by your company.
12 |
13 | Developers are terrible at testing their own software. I'm my own worst tester, and that's because I have a large understanding of how it works. Without trying, I can make the software work flawlessly each and every time. On my teams, I state that I want others using my code as much as possible. But what happens if something breaks?
14 |
15 | Hopefully your company employs a bug track of some sort. For example, my company uses FogBugz for all of our bug tracking. However, not many people in my company understand how to write a useful bug report. My goal is to outline some of the minor things that can be done to make a bug report more helpful to the developer who's going to be using it.
16 | public class ChatHub : SignalR.Hubs.Hub
43 | {
44 | public void BroadcastMessage(string message)
45 | {
46 | // rebroadcast the message to all the connected clients
47 | Clients.writeMessage(message);
48 | }
49 | }
50 | The most confusing thing here might be this mysterious Clients object. The Clients object is dynamic, meaning you can set properties or call methods on it that might not really exist physically. SignalR will take all those calls and translate them into messages that are sent to each client currently connected to the hub.
51 |
52 | Here’s a look at the code over on the client:
53 | <script type="text/javascript" src="~/Scripts/jquery.signalR-0.5.2.js"></script>
54 | <script type="text/javascript" src="SignalR/Hubs"></script>
55 | <script type="text/javascript">
56 | $(document).ready(function () {
57 | var chat = $.connection.chatHub;
58 | chat.writeMessage = function (msg) {
59 | $("#messages").append("<li>" + msg + "</li>");
60 | }
61 |
62 | $("#buttonSubmit").click(function () {
63 | chat.broadcastMessage($("#txtInput").val());
64 | });
65 |
66 | $.connection.hub.start();
67 | });
68 | </script>
69 | The request to the SignalR JavaScript file is straight forward, but then there is this magical request to SignalR/Hubs that you might be wondering about. This file is dynamically generated by SignalR. It gives your page all the information it needs to talk back to any Hubs you might have created. Because of this, I can use the object $.connection.chatHub and JavaScript doesn’t throw a fit. It’s a real object!
70 |
71 | I use the chatHub object in two different ways. First, I create a new function off of it called writeMessage. This is called from the server. WAT? Yes! If you look at the hub code above, I’m calling Clients.writeMessage and the client has a method called writeMessage!
72 |
73 | Just below that is a call to chat.broadcastMessage. Look back at the hub, the method broadcastMessage is defined! The circle of life is complete.
74 |
75 | Ok. LASTLY, there is this call to $.connection.hub.start(). This method kicks off the transport negotiation between your server and client. Websockets? Long pollings? Blah blah blah. You can override all this stuff, but just let SignalR do what it does best.
76 |
77 | And there you have it!
78 |
79 | SignalR is extremely easy to use, and I’m definitely recommending it as a replacement for 90% of the .NET AJAX work I’m seeing done in the community. Take a couple minutes, download the package via NuGet and try it out for yourself. You won’t be disappointed.
80 |
81 | Feel free to ask any questions, and hit me up on the Twitters @1kevgriff.
--------------------------------------------------------------------------------
/blog/The-Non-Techie-Guide-to-Source-Control.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: The Non-Techie Guide to Source Control
3 | permalink: the-non-techie-guide-to-source-control
4 | categories:
5 | - Deep Thoughts
6 | date: 2014-10-30 16:45:19
7 | ---
8 |
9 | _Update 1: Brandon pointed out a mistake in my math. Adjusted to reflect his comments._
10 |
11 | This is one of those posts that I have been meaning to write for a long time.
12 |
13 | As a consultant, I often find myself in a situation where I need to introduce a client to the concept of source control and why it is important for the long term success of the project. This post is meant to serve that purpose for a long time going forward, and also to help anyone else that might have a need in the future.
14 |
15 | > For technology friends: please use this post. Please suggest changes. Let's make it better for everyone!
16 |
17 | ##The Problem I'm Seeing
18 | Recently, I walked onto a project where I was asked to review some source code and see if I could suggest some changes. I had complete access to the original developer, so I asked her if it would be possible for me to get access to source control.
19 |
20 | Ten minutes later, I received a FTP address with username and password. I could have easily taken down the whole system with a keystroke! Hundred of man hours would have gone down the drain!
21 |
22 | This is **NOT** acceptable. Protection is easy and low cost.
23 |
24 | ##What is source control?
25 | This should be an easy one. Source control is a mechanism that allows a development team to track individual changes of files in a project over time.
26 |
27 | Have you ever used "Change Tracking" feature inside a Microsoft Word file? As you type, Word will track what you write, what you delete, and other assorted changes that you make. You are able to comment on each change, and later accept or reject them.
28 |
29 | Source control works the same. As you work on a project that probably contains tens to hundreds of files, the source control system manages what is happening. You can audit the changes, and even rollback changes if they are not acceptable.
30 |
31 | ##Why source control?
32 | There are several great reasons why you want to implement source control into your project.
33 |
34 | ### It prevents against hardware and software malfunction
35 |
36 | Sometimes hard drives go bad. I have lost count of the number of systems I have walked into where the company stored all their code on a server with no protection.
37 |
38 | How many man hours of time have gone into the production code that is running your business? The largest team I have worked on as a professional was about 6-9 people. The project had been in existence for about 10 years. Let us say that one member of the team contributed 2000 hours a year to the project (40 hours per week times 52 weeks, and then adjust for vacation and sick time).
39 |
40 | 2000 man hours * 6 employees = 12,000 man hours
41 | 12,000 man hours * 10 years = 120,000 man hours
42 | 120,000 man hours = 60 man years
43 |
44 | Average salary of a software developer = $75,000 per year (can vary, but bear with me)
45 |
46 | Total replacement cost of software = $75,000 * 13.9 years = **$4,500,000**
47 |
48 | That is a lot of math to do, but the result is realistic. If you bought a car worth 1 million dollars, do you think you would leave it out in the snow, wind, and rain? Why are you leaving the code that runs your business unprotected on hard drives whose chance of failure goes up daily.
49 |
50 | ### It prevents human error
51 |
52 | Developers are human. We make mistakes.
53 |
54 | Once I was called by a developer to help assist with an issue in a web application he was prototyping. The issue he was having was complicated, and seemingly happened *by accident*. His project had no source control, which means that there was no way to determine *what* he did. Even worse, there was no easy way to know *how to fix it*.
55 |
56 | Luckily in his situation, we were able to figure out the problem and correct it. This was after wasting 3 man hours of time on a problem that could have been solved within 10 minutes.
57 |
58 | Source control would have told the young developer what he changed, and provide a simple way to undo the changes.
59 |
60 | ### It allows safe experimentation
61 |
62 | When your software is built like a house of cards, you are less likely to want to make sweeping changes.
63 |
64 | What if we spend 40 hours and build "feature X" which our customers would love? Lets say that 13 hours into the development we discover that a critical bug is preventing users from paying with their credit cards. What do you do?
65 |
66 | Option one is undo all 13 hours of work we've invested, fix the issue, and push it out live again.
67 |
68 | Option two is to fix the issue, and push it live with the half-done "feature X".
69 |
70 | Option three is to postpone implementing the fix until "feature X" is completed.
71 |
72 | Option four, if you had source control, is to stash the changes to "feature X" and fix your issue. Later, you can come back to "feature X" and pick up where you left off.
73 |
74 | Source control gives you the ability to make changes without worrying about the stability of your software. Fix issues as they pop up, but keep pressing forward on new, exciting features!
75 |
76 | ## But We Have Backups
77 | Awesome! You should definitely have backups. Disaster recovery is a real problem, and I hope you never have to use it.
78 |
79 | Imagine my customer from earlier. They had backups. If I took down the system, they could call their hosting provider and ask to restore from backups.
80 |
81 | How long do you think this process would take? Minutes? Hours? _DAYS?_ Can your business survive an outage of unknown time?
82 |
83 | Source control doesn't replace disaster recovery. Instead, consider it a supporting tool. If I maintain a history and backup of the software over time, I can quickly redeploy it instead of waiting for the recovery process to occur.
84 |
85 | ## Recommendation for Source Control
86 | There are many options when it comes to source control. Your first decision is on your source control language (git, mercurial, tfs, svn) but I think **git** is the way to go. It works great in 99% of cases, it's open source and actively developed, and is designed for the modern way we work: disparate team members inside and out of your firewall that may have multiple dev boxes and need online/offline abilities.
87 |
88 | Next is how/where you will host your source control. Here's some options I think are best.
89 |
90 | ### GitHub
91 |
92 | [GitHub](http://github.com) is starting to become the defacto standard for all new software projects. In fact, I recommend it to all my clients. You have the option of using GitHub for free, if you don't mind all your source control being publicly available. If that's NOT an option for you (and it's okay), then you have the option to pay for "private repositories".
93 |
94 | For any repositories that you host, you're able to control who has access to it. There is no limit on the number of users you can add to a repository.
95 |
96 | Plans for individual user private repositories start as low as $7/month. For organizations with multiple users, private repository plans start as low as $25/month.
97 |
98 | ### Bitbucket
99 |
100 | [Bitbucket](https://bitbucket.org/) is another great provider of source control. They currently support unlimited private repositories for free (up to 5 users). Additional plans start as low as $10/month.
101 |
102 | ### Private On-Prem
103 |
104 | Don't want your source code to leave your private network? That's fine, git can do that too.
105 |
106 | Github has a [Enterprise install](https://enterprise.github.com) that you can run inside your network.
107 |
108 | There are open source ways to do this as well, where you have a self-hosted server that stores your code repos and maybe provides a web interface. [Digital Ocean has a good writeup](https://www.digitalocean.com/community/tutorials/how-to-set-up-a-private-git-server-on-a-vps) on this.
109 |
110 | ## Conclusions
111 | Billions of dollars is spent each year on software development and maintenance. We live in a world of bits and bytes. Changes are easy to make, but even the simplest change can be catastrophic.
112 |
113 | Source control systems have existed for over 30 years. They continue to become more sophisticated. Developers around the world trust them with their codebases because they know mistakes will happen. Make sure you're protecting your code.
114 |
115 | > Do you need assistance moving your projects forward? Let me know! Feel free to shoot me an [email](mailto:contact@consultwithgriff.com) and we can discuss options for your project.
--------------------------------------------------------------------------------
/blog/Anatomy-of-an-XNA-Application.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Anatomy of an XNA Application
3 | categories:
4 | - "Development - Game Development"
5 | permalink: anatomy-of-an-xna-application
6 | updated: '2009-01-04 06:54:44'
7 | date: 2009-01-04 06:54:44
8 | ---
9 |
10 | So you have your environment set up, and you create your first XNA project. XNA Game Studio sets up your project, and gives you a great skeleton for developing your game. Below is the complete "Game1.cs" file you're given. I recommend renaming this file and class to something a bit more meaningful.
11 | using System;
12 | using System.Collections.Generic;
13 | using System.Linq;
14 | using Microsoft.Xna.Framework;
15 | using Microsoft.Xna.Framework.Audio;
16 | using Microsoft.Xna.Framework.Content;
17 | using Microsoft.Xna.Framework.GamerServices;
18 | using Microsoft.Xna.Framework.Graphics;
19 | using Microsoft.Xna.Framework.Input;
20 | using Microsoft.Xna.Framework.Media;
21 | using Microsoft.Xna.Framework.Net;
22 | using Microsoft.Xna.Framework.Storage;
23 |
24 | namespace LastAgent
25 | {
26 | ///
27 | /// This is the main type for your game
28 | ///
29 | public class Game1 : Microsoft.Xna.Framework.Game
30 | {
31 | GraphicsDeviceManager graphics;
32 | SpriteBatch spriteBatch;
33 |
34 | public Game1()
35 | {
36 | graphics = new GraphicsDeviceManager(this);
37 | Content.RootDirectory = "Content";
38 | }
39 |
40 | ///
41 | /// Allows the game to perform any initialization it needs to before starting to run.
42 | /// This is where it can query for any required services and load any non-graphic
43 | /// related content. Calling base.Initialize will enumerate through any components
44 | /// and initialize them as well.
45 | ///
46 | protected override void Initialize()
47 | {
48 | // TODO: Add your initialization logic here
49 |
50 | base.Initialize();
51 | }
52 |
53 | ///
54 | /// LoadContent will be called once per game and is the place to load
55 | /// all of your content.
56 | ///
57 | protected override void LoadContent()
58 | {
59 | // Create a new SpriteBatch, which can be used to draw textures.
60 | spriteBatch = new SpriteBatch(GraphicsDevice);
61 |
62 | // TODO: use this.Content to load your game content here
63 | }
64 |
65 | ///
66 | /// UnloadContent will be called once per game and is the place to unload
67 | /// all content.
68 | ///
69 | protected override void UnloadContent()
70 | {
71 | // TODO: Unload any non ContentManager content here
72 | }
73 |
74 | ///
75 | /// Allows the game to run logic such as updating the world,
76 | /// checking for collisions, gathering input, and playing audio.
77 | ///
78 | /// Provides a snapshot of timing values.
79 | protected override void Update(GameTime gameTime)
80 | {
81 | // Allows the game to exit
82 | if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
83 | this.Exit();
84 |
85 | // TODO: Add your update logic here
86 |
87 | base.Update(gameTime);
88 | }
89 |
90 | ///
91 | /// This is called when the game should draw itself.
92 | ///
93 | /// Provides a snapshot of timing values.
94 | protected override void Draw(GameTime gameTime)
95 | {
96 | GraphicsDevice.Clear(Color.CornflowerBlue);
97 |
98 | // TODO: Add your drawing code here
99 |
100 | base.Draw(gameTime);
101 | }
102 | }
103 | }
104 |
105 | Let's evaluate the various parts of this code. We'll ignore the using statements, and get right into the meat of the class. Below is a snippet of the code. We're given two objects, GraphicsDeviceManager and SpriteBatch. The GraphicsDeviceManager helps us determine the type of device we're going to be outputting to. This can range from various PC graphics cards to the Zune or Xbox 360. We'll use this class later to alter our output based on users environment. Next is the SpriteBatch. Think of this as a List<> of images you want to draw to the screen. This will be covered a little bit later in the Draw() method.
106 |
107 | Next is the game class constructor, which sets up the GraphicsDeviceManager and sets our Content pipeline. The content pipeline is a post all in itself, so don't worry too much about it now. The Initialize() method provides you a place to do anything you need to do before the game runs. I'm at a loss for a good example of what you would put here, but if I ever think of one, I'll be sure to let you know.
108 |
109 |
110 | GraphicsDeviceManager graphics;
111 | SpriteBatch spriteBatch;
112 |
113 | public Game1()
114 | {
115 | graphics = new GraphicsDeviceManager(this);
116 | Content.RootDirectory = "Content";
117 | }
118 |
119 | ///
120 | /// Allows the game to perform any initialization it needs to before starting to run.
121 | /// This is where it can query for any required services and load any non-graphic
122 | /// related content. Calling base.Initialize will enumerate through any components
123 | /// and initialize them as well.
124 | ///
125 | protected override void Initialize()
126 | {
127 | // TODO: Add your initialization logic here
128 |
129 | base.Initialize();
130 | }
131 |
132 |
133 | Next are our Load and Unload content methods. The purpose of these methods are to load all the content you need to start the game. The comment says "load all your content", but realistically you don't want to do that. For demos, this is ok. For commercial games, you want to load as little as possible to get the user going and load as necessary. That's what loading screens are for!
134 |
135 |
136 | ///
137 | /// LoadContent will be called once per game and is the place to load
138 | /// all of your content.
139 | ///
140 | protected override void LoadContent()
141 | {
142 | // Create a new SpriteBatch, which can be used to draw textures.
143 | spriteBatch = new SpriteBatch(GraphicsDevice);
144 |
145 | // TODO: use this.Content to load your game content here
146 | }
147 |
148 | ///
149 | /// UnloadContent will be called once per game and is the place to unload
150 | /// all content.
151 | ///
152 | protected override void UnloadContent()
153 | {
154 | // TODO: Unload any non ContentManager content here
155 | }
156 |
157 |
158 | The last two methods are the meat of your XNA application. The Update() method is provided to you as a way to update the state of your game. As the comment says, you use this method to update your world, check for collisions, gather input, play audio, etc. By default, you're given code that will detect a button press from an Xbox 360 controller. Keep in mind when designing your games if you are going to accept input from just a 360 controller, keyboard, mouse, or all of the above.
159 |
160 | Finally, there is the Draw method, and this is where all your content makes it onto the screen. The first line clears the screen. This is a very necessary step. Failing to clear the screen would lead to some wacky results. Think of the screen as a canvas. You can't simply redraw on top of what you've already drawn. Calling the clear method results in a new canvas. This screen is where our friend SpriteBatch will come in handy.
161 |
162 |
163 | ///
164 | /// Allows the game to run logic such as updating the world,
165 | /// checking for collisions, gathering input, and playing audio.
166 | ///
167 | /// Provides a snapshot of timing values.
168 | protected override void Update(GameTime gameTime)
169 | {
170 | // Allows the game to exit
171 | if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
172 | this.Exit();
173 |
174 | // TODO: Add your update logic here
175 |
176 | base.Update(gameTime);
177 | }
178 |
179 | ///
180 | /// This is called when the game should draw itself.
181 | ///
182 | /// Provides a snapshot of timing values.
183 | protected override void Draw(GameTime gameTime)
184 | {
185 | GraphicsDevice.Clear(Color.CornflowerBlue);
186 |
187 | // TODO: Add your drawing code here
188 |
189 | base.Draw(gameTime);
190 | }
191 |
192 |
193 | And that's about it! Press Ctrl-F5 to build and run your first XNA application. You should be greeted with a pretty, Cornflower Blue screen. What you're not seeing is your Update and Draw methods being called continuously.
194 |
195 | What's next for our little application? For starters, we need to get some stuff on the screen. For my game, I'm going to be using a tile based game, so my next entry will revolve around loading tile sets and drawing them to the screen.
196 |
197 | Happy developing!
--------------------------------------------------------------------------------
/blog/Non-Tech-Factors-to-Consider-When-Choosing-Your-Tech-Stack.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Non-Tech Factors to Consider When Choosing Your Tech Stack
3 | categories:
4 | - Deep Thoughts
5 | permalink: non-tech-factors-to-consider-when-choosing-your-tech-stack
6 | date: 2016-05-10 21:33:01
7 | ---
8 |
9 | Greenfield projects are typically a great deal of fun. It is something new and exciting! No legacy code that will bog down or needlessly frustrate the team. *We will finally get to do things the RIGHT way this time.*
10 |
11 | There is a flip side to this excitement, however. The fun and flexibility of a new Greenfield project also comes with the unparalleled responsibility of making hard, up front, technical decisions.
12 |
13 | Ask any developer who has worked on a long-term project and they will tell you that there are some things you cannot simply change halfway through the development of a project. At least not without hundreds of man-hours of effort to remedy. Should we use an ORM or write ADO.NET by hand? ASP.NET Core 1.0 or go with tried-and-true ASP.NET 4.6. MVC or
14 | WebForms? The hard technical decisions you make at the beginning of the project can echo for years!
15 |
16 | >For some guidance on how to select your ASP.NET tech stack, watch this
17 | on-demand webinar on [*Choosing the Right Tech Stack*](http://www.telerik.com/campaigns/devcraft/choosing-the-right-tech-stack?utm_medium=external&utm_source=kgriffin&utm_campaign=dt-devcraft-apr16-webinar&utm_content=article) - (sponsored).
18 |
19 | Because it is so challenging, many developers will concentrate on the technical aspects of selecting a stack while completely ignoring the developers themselves. If you are the technical director of a project, you cannot proclaim “this is the stack we will use” without a firm understanding of how that will be accepted by the team or even simply the knowledge of what the needs of the project will be.
20 |
21 | ##Being on the Cutting Edge
22 | There is a poem by Robert Frost that every high school kid in the US had to memorize. Two roads diverged in a yellow wood, and sorry I could not travel both.* Your tech stack is the same. There are two paths: one that is well worn and one that is thick with undergrowth.
23 |
24 | Which one do you select?
25 |
26 | First, we can examine the well-worn path. ASP.NET WebForms has been around for over fifteen years. There are a million different blog posts on various aspects of WebForms. As it has matured over the years, most of the documentation has stayed relevant. Try Googling for “(something) webforms” and you will be rewarded with thousands of results. All of which are probably still good to examine and use!
27 |
28 | ASP.NET MVC 5 is an in-between of tried and true and cutting edge. With the onset of ASP.NET Core 1.0, using MVC 5 on ASP.NET 4.6 is a bit like buying a car one model year older when the new ones are shipping next week. However, as with cars, the documentation and trailblazing has already happened. You benefit from all the hard work of previous
29 | early-adopters.
30 |
31 | ASP.NET Core 1.0 is the overgrown road. If you were to glance down it, you would see developers who have tripped and fallen. Some might be stuck in holes. The end of the road is a mystery because it isn’t visible from where you are. Ask yourself, "How adventurous do I feel?”
32 |
33 | Projects with strict budgets and deadlines would not be appropriate for cutting edge. That conversation doesn’t go well.
34 |
35 | >“Are we all set with the launch next week?”
36 | >
37 | >“No. Turns out ASP.NET Core doesn’t support SmtpClient yet so we have to push a few weeks.”
38 |
39 | On a personal note, I like to stay on in the middle leaning towards cutting edge. My job dictates that I solve business problems and doesn’t require a specific tech stack. For a current client project, I’m adventuring into ASP.NET Core and I’m hitting far more roadblocks than what I was expecting.
40 |
41 | Trailblazers need to be aware and take their time. Through their efforts, the path will be clearer for other developers who follow.
42 |
43 | ## Developer Ability to Learn Quickly
44 |
45 | When I used to hire developers, our metrics did not put too much concern about what a person knew but how quickly he or she could learn it.
46 |
47 | When choosing a stack, it is important to gauge the team responsible for implementing the stack. A developer fixated with developing for WebForms might have a difficult time moving to the more complex patterns exposed by ASP.NET MVC or WebAPI.
48 |
49 | A colleague of mine has told a story about one of his old bosses who had a deprecated background in software development. In the story, the boss had been spending months trying to learn how C\# worked and he was attempting to cobble together a WinForms application based off knowledge he copied from books and online tutorials. One day, the boss called my colleague into his office and asked him to explain what a class was.
50 |
51 | Our goal isn’t to alienate developers. Everyone learns in different manners and at different rates. When selecting a tech stack, we need to remain conscious of who will be implementing the solutions and if they mentally can handle the pressure of being towards the cutting edge.
52 |
53 | What’s better? A complete solution in an older technology or an incomplete solution that is on the cutting edge.
54 |
55 | ## What does the project need?
56 |
57 | All projects are unique snowflakes. Client needs will vary from “I just need something better than this Excel spreadsheet” to “I want something like Facebook”.
58 |
59 | Simple “forms over data” applications do not need to be single page applications built with Angular 2 or React. A complex solution that would take a small team of developers to implement over a couple weeks can easily be accomplished by one developer within a couple hours with WebForms.
60 |
61 | Large monolithic web applications have a different set of needs. You are expecting these projects to launch with minimum features, but eventually will balloon in size and complexity. The time invested in more cutting edge approaches will pay dividends in the future.
62 |
63 | Your goal as a decision maker is to weigh the needs of the project with the tools available – and even in some cases, looking at the tools on the horizon. If your project is simply forms over data, maybe stick with something simple like ASP.NET WebForms. If you foresee the project growing in complexity over time, maybe start with an ASP.NET MVC and WebAPI stack that could later integrate front-end frameworks like Angular or React.
64 |
65 | ## Team Size and Scalability
66 |
67 | Another important factor to think about in your quest for the perfect tech stack is the size of the team that will construct the project.
68 |
69 | I have had the pleasure of working in both small, one to two person teams and additionally been part of larger teams that have spanned multiple people around the world.
70 |
71 | As the CTO for a startup, our team brushed up against the most bleeding edge technology we could get our hands on. During the course of a day, we would deploy a dozen times to production. There was a mutual agreement and respect for the project, and our team cohesion allowed flexibility to make fast, uncalculated decisions on tools, libraries, or
72 | frameworks. If the tool didn’t work, no big deal – toss it out and try another.
73 |
74 | If I were to travel the startup road again, I would guide my team toward adopting ASP.NET Core. Even in its infancy, there is potential for this platform to allow us more agility than previous versions of ASP.NET.
75 |
76 | The first major development team I worked with out of college was for a large security company developing components for anti-virus software. This team moved at a much slower pace. Our requirements called for a deployment every quarter, and our software was supported across a dozen operating systems. Changes in the tools and frameworks we used impacted dozens of developers across the world.
77 |
78 | If change was enacted, our teams needed to also prepare for the blowback. What happens when you have not considered every angle? What is plan B if you hit a roadblock? Who makes the decision of how to navigate roadblocks?
79 |
80 | Please don’t misunderstand; there are large teams that are perfectly capable of quick deployments and rapidly changing direction when the project calls for it. My argument is that the majority of larger teams I’ve been with absolutely cannot work in this capacity. If you have a 30-person team, and you tell them to use ASP.NET Core 1.0, which is the
81 | bleeding edge of what ASP.NET developers can use, then you need to expect them to adjust for API-breaking changes every couple weeks. It is rare to find a large team able to do that without going insane or ultimately pushing back the schedule.
82 |
83 | ## Conclusions
84 |
85 |
86 | Sometimes we wish decisions could simply be a matter of bits and bytes, but there are many human factors that need to be taken into account.
87 |
88 | The best advice that can be given is to discuss the pros and cons of every choice available within your teams. If teams are completely involved in the process of making technical decisions, the product outcome will be better because of it.
89 |
90 | > What tools are available in the ASP.NET stack then? Jeremy Likness has an [excellent
91 | article](http://developer.telerik.com/featured/how-to-web-asp-net/?utm_medium=external&utm_source=kgriffin&utm_campaign=dt-devcraft-apr16-webinar&utm_content=article) on the current state of ASP.NET development tools. Use the tools discussed in Jeremy’s article to start a dialog with your team. (sponsored)
92 |
93 | A great team, when given flexibility, will always produce a solid product.
--------------------------------------------------------------------------------
/blog/Review-Everleap.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'Review: Everleap'
3 | categories:
4 | - Reviews
5 | permalink: everleap
6 | date: 2014-10-20 17:43:01
7 | ---
8 |
9 | *For this review, I am being provided a free account at Everleap for hosting my user group, the Hampton Roads .NET Users Group. If you are interested in a place to host your own group’s site, please talk to the folks at Everleap!*
10 |
11 | *This review is also cross-posted at http://www.codeproject.com/Articles/827619/Review-Everleap*
12 |
13 | *Interested in trying Everleap out for yourself? Head [here](http://www.everleap.com/a/kevgriffin).*
14 |
15 | Something I haven't had to do in a while is shop around for a hosting provider. To be perfectly honest, since Windows Azure starting offering Websites, there has been little need for me to look elsewhere. With our user group, it has been a hassle to host the site with my personal Azure account. It was natural for us to start looking at alternatives that didn’t tie the group site to me.
16 |
17 | ## What is Everleap? ##
18 | Everleap is a hosting service by the good folks who brought us DiscountASP.NET. It is promoted as a reliable, scalable, and affordable hosting platform built on top of the Windows Azure Pack.
19 |
20 | The Windows Azure Pack is a framework that allows hosting providers to leverage the same technology behind the Windows Azure platform.
21 |
22 | With traditional hosting, you are normally locked into a plan with limited resources. If you were to use more than the resources you were provided, either your site would be taken offline or you would be charged for the overages.
23 |
24 | Cloud services revolutionized the industry by giving us the opportunity to deploy applications once and scale the resources depending on our use cases. If you need more resources, scale up. If you need fewer resources, scale down. Pay for what you use!
25 |
26 | Everleap offers all of the above, but at a low, fixed monthly rate. Need extra resources? Everleap offers the "power pack" which gives you a bump in resources without breaking the bank.
27 |
28 | ## Setting up an account ##
29 | Sign up is painless. Give your name, email, and credit card information and select the type of plan you want to sign up for.
30 |
31 | For my review, I was provided with a complementary license for Everleap’s “Cloud Websites” offering. This option provides me with one website, scalable across 2 servers. There is also an option for “Mulit-Domain Cloud” which gives you the ability to manage up to five websites across two servers. Resources and bandwidth limitations still apply for both, but the limits are not unreasonable.
32 |
33 | One of my largest gripes is that Everleap doesn't let you choose a login name for yourself. After you sign up and confirm all your information, you're left with just a login prompt.
34 |
35 | To get a username, you are supposed to check your email where you realize you have been assigned a random username. I’ve been told by Everleap associates that this is on the product backlog to correct.
36 |
37 | 
38 |
39 | ## Exploring the Control Panel ##
40 |
41 | A great way to describe the control panel for Everleap is "clean".
42 |
43 | 
44 |
45 | 
46 |
47 | Everleap does a great job of giving you "at a glance" information about your sites. How much hard drive space is it taking up? How much bandwidth have you used this month?
48 |
49 | 
50 |
51 | Do you need to take the site down or want to recycle the process? Easy use buttons are on the right of the screen, ready to serve you.
52 | Over in site settings, I had a bit of a weird déjà vu feeling. Going through each section, the settings available to me were identical to those your get in Windows Azure. This is great though! It is a huge benefit of Everleap being built on top of the Azure Pack.
53 |
54 | 
55 |
56 | The settings also give away a couple hints about the type of applications we can deploy to Everleap. On one screen, there is an option for PHP and for Classic ASP. You are not tied to just building ASP.NET applications.
57 |
58 | Most exciting for me is the App Settings screen where one of the options is WEBSITE\_NODE\_DEFAULT_VERSION. A quick double check of https://www.everleap.com/cloud-hosting/web-sites/overview/ shows that node.js is supported and encouraged!
59 |
60 | ## Deploying an Application ##
61 | Everleap provides three ways to deploy your application.
62 |
63 | ● FTP
64 | ● Web Deploy
65 | ● Git
66 |
67 | For FTP and WebDeploy, Everleap provides you with a publish profile to use within Visual Studio. Simply click "Download" next to either option, and save the file somewhere safe.
68 |
69 | 
70 |
71 | Setting up web deploy in Visual Studio is painless. Right click on your web project, and select Publish.
72 |
73 | 
74 |
75 | 
76 |
77 | If you've never published this project before, you will want to "Import" a publish profile. Select the publish profile you downloaded earlier, and Visual Studio will pre-fill all the options with settings from Everleap.
78 |
79 | Press "Publish" and Visual Studio will connect to Everleap, upload all your files, and perform any additional configuration needed (such as setting database strings, etc).
80 |
81 | ## Scaling ##
82 | Depending on the popularity of your application, you might have the need to scale. With traditional hosting platforms, this is where you can hit a wall. With Everleap, scaling is as easy as saying you need "2" cloud servers instead of "1".
83 |
84 | 
85 |
86 | This change doesn’t happen instantly, and Everleap does not communicate the progress between moving from 1 to 2 servers. When I started performance testing, I had to wait about 5 minutes after pressing “Update” until the second server was allocated for me.
87 | Everleap associates made me aware of a backlog issue to implement a system-wide notification system, which would easily correct the issue I had above.
88 |
89 | ## Performance ##
90 | When testing a hosting solution, I like to see how it performs under stress. To test Everleap, I created two different tests. These tests are not meant to be exhaustive. My goal is to see how Everleap handles a decent amount of load over time. The site deployed for this test is the sample ASP.NET application Visual Studio generates.
91 |
92 | ### Test 1: 0 to 1000 clients over 1 minute ###
93 |
94 | This is a test I like to run in order to see how well my site will perform as more and more people start connecting to it.
95 |
96 | 
97 |
98 | This test did very well. The spike in response time at the beginning of the test is due to ASP.NET warm up, but afterwards the response time does a good job of saying underneath 250ms. Our average for this test was 134ms, is nothing to scoff at. The server was performing as expected!
99 |
100 | ### Test 2: 5000 clients per second over 1 minute ###
101 |
102 | 
103 |
104 | This test sent a constant load of 5,000 client connections to the server over a 1 minute period. Imagine your website being posted on Reddit, Slashdot, or Good Morning America. The demand for your page would be immediate over a short period of time. In fact, when I discuss performance with clients, this is a use case we always imagine. You never want your site to error when it is hitting critical mass.
105 |
106 | The average response time hovered around 133ms, which is really good!
107 |
108 | There were 280k successful requests made, and 19k errors (500 status). The error rate of 6.4% should be concerning, but not unwarranted. We are throwing a lot of traffic at one server, and there is only so much traffic a server can take.
109 |
110 | The second part of the test was to scale the environment to 2 servers.
111 |
112 | 
113 |
114 | The response time went from 133ms average to 73ms average and we eliminated all of the errors we were receiving before. Everleap did a great job dealing with the traffic.
115 |
116 | ## Conclusions ##
117 |
118 | Everleap did a great job of giving me what I want from a hosting provider.
119 |
120 | ● Quick, easy registration
121 | ● Multiple, dependable methods of deployment
122 | ● Configuration options
123 | ● Scalable
124 | ● Performant
125 |
126 | During the process of evaluating Everleap, I had coffee with a friend of mine who is a fellow consultant. We discussed the differences between traditional hosting, cloud providers, and then Everleap.
127 |
128 | Everleap popped out as an excellent alternative for him over Windows Azure, since his clients react better to fixed pricing than having to deal with usage scenarios.
129 |
130 | If you're looking for the power and flexibility of Windows Azure and you need the pocket friendliness of a monthly fixed price, then you shouldn't look any farther than Everleap.
131 |
132 | You can visit their site to find out more about the [Everleap](http://www.everleap.com/a/kevgriffin) Cloud.
133 |
--------------------------------------------------------------------------------
/blog/Shedquarters.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Shedquarters
3 | date: 2017-05-26 12:57:44
4 | categories:
5 | - Business
6 | permalink: shedquarters
7 | ---
8 |
9 | ## May 25th, 2017
10 | Since 2009, I have worked out of my home office, the FROG (finished room over garage). Since then, life has changed a bit. I have three awesome little boys who are growing up to be school age, and my wife and I need a part of the house dedicated to homeschooling.
11 |
12 | The FROG is the obvious location. When you have three kids, room to spare is a luxuary not often found.
13 |
14 | But in order to use the FROG for homeschooling, I need to vacate. I could've rented office space for $750-$1500 per month. But have you ever tried to RENT a single or double office? They're **really** hard to find at reasonable rates.
15 |
16 | And I like working at home. Adding a commute back into day to day would really put a bummer on my personal and business life. There needed to be a better alternative.
17 |
18 | Today, I bought my **Shedquarters**.
19 |
20 | >Note: These are the model I bought, but mine is more customized.
21 | >
22 | >
23 | >
24 |
25 | The pictures above show the "base" model of the building I'm buying. My shed will have a real door on the right hand corner, and windows going all the way around.
26 |
27 | And the entire thing will be unfinished. Part of my fun is insulating, drywalling, and running power/internet out to the building.
28 |
29 | This post will be a story of the work I do on my Shedquarters, and also an overview of the costs associated with owning it.
30 |
31 | ## June 17th, 2017 - Area Prep
32 | Here is a *before* picture of where there Shedquarters is going to live.
33 |
34 | 
35 |
36 | Normally with these types of sheds, they can just be dropped on the ground or put up on blocks. That's not a *bad* way to secure the shed, however, this area is prone to holding water when it rains. Several *epic* rainstorms recently have caused me to reevaluate the foundation for my Shedquarters.
37 |
38 | Ideally, I would have just poured a concrete slab. It's most likely to last the longest. The *best* estimate I got was $1,900 and I'd have to wait 2-3 weeks before the work could be done.
39 |
40 | I'm not opposed to a bit of hard work, so I went for a compromise of pouring concrete piers. Think "fence posts" but without the fence.
41 |
42 | Since these sheds are turnkey, I already knew where the piers should go.
43 |
44 | 
45 |
46 | Each "line" is ~64 inches from the other lines and have 5 crosses in them. A total of 15 piers.
47 |
48 | Each "pier" will be 30 inches deep and 8 inches wide. The exposed part of the pier will be 12 inches wide. This should give me PLENTY of margin for measurement errors.
49 |
50 | ## June 23th, 2017 - PERMITS
51 | I decided to get a permit. Technically, it's required by the city even if the structure is non-permanent. But this will add to the resale value of my home, and I need to add it to my homeowners insurance. It's important that I make sure all the details are in place.
52 |
53 | There are three conditions I have to meet:
54 |
55 | 1. Provide architectural drawings of the building
56 | 2. Anchor the building to the ground
57 | 3. Building has to have a flood vent
58 |
59 | Since my area is in a flood zone, it is possible (unprobable) that we could get SO MUCH RAIN that the shed floats away. My shed requires 6 anchors total, one in each corner and two in the middle.
60 |
61 | Getting the drawings was fairly easy! I just asked. Since the company I'm using does this so often, the manager had them ready to go.
62 |
63 | ## June 24th, 2017 - HARD WORK
64 | Digging holes is hard work. I threw money at the problem and rented a towable auger for a day.
65 |
66 | 
67 |
68 | With the help of my dad and brother-in-law, we dug out 15 holes - each about 30 inches deep. As I said above, the area is prone to holding water, so the holes filled up pretty quickly! This process took about 30 minutes total. Much easier than digging out holes by hand.
69 |
70 | 
71 |
72 | Once all the holes were dug, I cut concrete forms and leveled them all with the highest point in the area. Then I dumped a bag or two of concrete into the holes. Because of the amount of water in the holes, we didn't mix the concrete first. If you dump the bag, it can be mixed *in* the hole - saving a ton of time and effort.
73 |
74 | Along with concrete, I added 3 pieces of rebar to secure the bottom part of the pier to the footing itself.
75 |
76 | These had to sit overnight.
77 |
78 | 
79 |
80 | ## June 25, 2017 - Pouring Footings
81 | After giving the base of the footings a day to dry, we poured the footings. The concrete for these had to be mixed by hand
82 |
83 | 
84 |
85 | Next is the FUN part! The shed delivery!
86 |
87 | ## July 10th, 2017 - Shed Delivery!
88 | FINALLY! The Shedquarters came today! After all the prep to ensure that we would have a stable foundation to put the shed on, this was the moment of truth.
89 |
90 | The shed showed up on my driveway!
91 |
92 | 
93 |
94 | The entire process took about 20 minutes. There was a team of 3 guys, and they backed the shed into my backyard and dropped it on the footings I had poured. And guess what, the footings were near perfect!
95 |
96 | Here's a video of the dropping process:
97 |
98 |
99 |
100 | ## August 27th - Progress on the interior
101 | I had several weeks in August that I wasn't able to work on the shed, but progress has been coming along smoothly.
102 |
103 | There are three major things that got done in the Shedquarters.
104 |
105 | First, we ran electrical wiring throughout the entire building. Because outlets are prime real estate, I opted to have as many as I could.
106 |
107 | Soon, my electrician is going to run a 100 amp subfeed from my house out to the shed. This subfeed will run two circuits for outlets, circuits for my AC and heating unit, and circuits for exterior lighting and outlets.
108 |
109 | To test the electrical outlets, we wired up up a heavy duty extension cord to "plug" the shed into my house. Works great until you blow a breaker once or twice. At least it's temporary.
110 |
111 | We also had to install 2x4 beams across the roof to hang drywall from. Here is a picture of the completed work:
112 |
113 | 
114 |
115 | Once the beams were in, we could hang the recessed LED lights I bought. I'll have 8, in total, plus a ceiling fan in the middle of the room. These LEDs throw a ton of light, and do a great job of filtering it across everywhere.
116 |
117 | 
118 |
119 | Next step - ETHERNET and real power.
120 |
121 |
122 | # FAQ
123 |
124 | ## Did you a permit?
125 |
126 | According to the city, I did need a permit. The entire process was painless. I told the building permits people at city hall what I was doing, and they directed me exactly where I needed to go. A couple bucks later - I'm done. After the shed was installed, I had to anchor it and call the city back out to do the final inspection. That process was all online, and literally took 5 minutes when the guy got here. Most of that was chatting about how awesome my Shedquarters is going to be.
127 |
128 | ## Do you have an HOA (Homeowners Association)?
129 |
130 | HECK NO! I won't go into the pros and cons of a HOA - but I prefer not having to ask permission for what I want to do on my property.
131 |
132 |
133 | What are you questions? Ask in the comments or on [Twitter](https://twitter.com/1kevgriff)
134 |
135 | # Costs
136 | How much does it cost to build out a Shedquarters? I'm trying to include Virginia Sales Tax as well (6.00%).
137 | | Item | 141 |Cost | 142 |
|---|---|
| Shed | 147 |$5,796.08 | 148 |
| Building Permit (City of Chesapeake) | 151 |$91.74 | 152 |
| Towable Auger Rental | 155 |$127.01 | 156 |
| 5 - Bags of Gravel | 159 |$20.35 | 160 |
| 45 - 2Ft Rebar | 163 |$88.25 | 164 |
| 4 - 48" Concrete Form Tubes | 167 |$67.71 | 168 |
| 39 - Bags of Concrete (60lbs) | 171 |$176.60 | 172 |
| Electrical Boxes (Home Depot) | 175 |$7.45 | 176 |
| Electrical Boxes (Lowes) | 179 |$4.29 | 180 |
| Anchors (city requirement) | 183 |$44.27 | 184 |
| 8 - LED Recessed Bulbs | 187 |$76.28 | 188 |
| 8 - Recessed Light Housings | 191 |$60.89 | 192 |
| 2 - LED Light Switches | 195 |$48.70 | 196 |
| 2x4 (Variety of Lengths) | 199 |$110.45 | 200 |
| Misc Costs | 203 |$61.56 | 204 |
| Total | 207 |$6,781.63 | 208 |