Jekyll2023-08-01T13:33:01+00:00https://blog.pinarydevelopment.com/feed.xmlPinary Development - A class above binaryBored with CRUD2023-08-01T00:00:00+00:002023-08-01T00:00:00+00:00https://blog.pinarydevelopment.com/bored-with-crud<p>I came across a question on <a href="https://www.linkedin.com/posts/isaacfink123_i-would-like-some-input-from-my-fellow-full-activity-7090312858562879488-Po4r">LinkedIn</a> which I enjoyed reading. I started typing a response and when I went to post it, found that I was grossly over the character limit for a comment. I figured I would make a post out of it instead.</p>
<blockquote>
<p>I would like some input from my fellow full stack developers on my observation</p>
<p>I have worked as a full stack developer for around 5 years now and for the most part my time is consumed by very repetitive and non challenging tasks, most applications are essentially crud applications where you store some data in a database and allow your users to read and modify the data, this is something that I and every other full stack developer has implemented countless times already, it seems like after a while you either have to specialize or somehow only take on challenging parts of the application (like optimization or interesting ui components) but even then as a full stack developer there is not a lot of creativity on a daily basis</p>
<p>When I discussed this with colleagues they recommended using ChatGPT or similar tools to automate the boring parts but as anyone who has been coding for a while would know this is not always good enough, besides using ChatGPT to build websites sounds even more boring</p>
<p>I am interesting in hearing other developers perspective on this, do you feel like you’re being challenged often enough to stay excited about programming? and if yes what could I do to feel the same way?</p>
<p>This is also my long way of saying I am interested in a new challenge, hopefully a position where I could get better at the often neglected aspects of full stack development like managing databases, devops or similar roles where I could grow and learn</p>
</blockquote>
<p>There are a number of very good questions you ask and other issues you touch upon without asking explicitly. I don’t think there is a one size fits all solution, but I can share what has worked for me and how I’ve tried to guide others over the years.</p>
<p>To me, this could be compared to riding a bike. I learned to ride a bike when I was a young kid. These days, it doesn’t really interest me, but I see plenty of grown-ups biking all the time. Some frequently and for really long periods of time. Why? Its so boring. Its the same thing over and over.</p>
<p>I think the answer is, that at some point, they took it ‘beyond the bike’. They wanted to lose weight, they wanted to get healthier, they wanted to cut down on green house gases, they wanted to socialize or wanted to compete against themselves or others.</p>
<p>At some point, in order for you to retain interest, it has to go beyond the CRUD. At the heart of any real software that is useful to others, there is a need to store data and to retrieve it for later use. What the user/business needs to utilize that data for will change and the requirements around how quick/reliable/fool-proof that process is will influence how the data is processed, stored and retrieved. But in order for the development of software to retain its excitement, you need to find what gets you excited.</p>
<p>Early in my career I felt very inadequate compared to my peers. Mind you, I had a Master’s degree in Computer Science, but there were multiple things that I encountered on day one of work that everyone seemed to ‘just get’ that were nothing I’d ever seen before. This ignited within me a burning curiosity around the career path I’d embarked on. To satisfy this curiosity, I started following a few blogs and skimming a couple of articles daily to expand my horizons. I also started a habit which I attribute to most of my successes and career satisfaction, which was a habit of always having a side-project.</p>
<p>The first side project was an attempt at a better experience for our customers. Instead of requiring a business to input all of their information, I thought it would be nice if they could put in the URL for their company website and we could scrape/fill in the contact info for them. I was never able to complete the project, as web-scraping was much harder than I had assumed, but I learned so much about HTML, browsers, the DOM, string parsing/manipulation, etc, etc in the process. While I couldn’t improve the product for that company at that time, the knowledge/experience that I gained benefited them and everyone else I’ve worked for since then.</p>
<p>I’ve created a basic ORM, explored a variety of front-end frameworks, created an SSO implementation, probed a number of approaches to automated testing, delved into JavaScript promises, dependency injection and so much more. All of this has helped me evolve my approach to software development and form opinions on how best to approach a wide variety of solutions. I’ve done a lot of this during regular working hours, 15 minutes at a time. Instead of taking 3 coffee breaks, I’d take 2 and use one for exploration.</p>
<p>That is one technique that I think has helped me the most. Some people need to find an industry that they are passionate about in order to feel the impact of what they are developing. Some find people/business problems much more interesting and move into leadership while others enjoy the very technical aspects of data systems and go towards architecture. Some like aesthetics and easing user interactions with a system and will drift more towards the front-end.</p>
<p>Another thing that excites me is helping others. As caustic as Stack Overflow can be at times, I’ve found a lot of enjoyment learning how to ask good questions, getting help and being able to help others. I’ve gotten a few comments from people all over the world around how my answer helped them understand something or saved them hours of work and have found that immensely rewarding. Mentoring others, writing blog posts or trying to contribute to open-source projects are other techniques.</p>
<p>The world of software is gigantic and full of possibilities. I believe there is a niche for just about any personality type. You need to find what motivates you though instead of waiting for something external to do it for you. You can and probably should solicit advise from others, especially initially, to find what would be a good area to explore/grow in, but you shouldn’t wait for someone to come along and ignite your flame.</p>
<p>Create your passion and utilize it to improve the company you are currently with as well as your future career projection. Feel free to PM me if you would like to discuss your specific situation. Hope this helps.</p>My thoughts on fighting becoming bored with software development, in response to a question posed on LinkedIn.The Story Behind the Application - Micro-project 22023-02-24T00:00:00+00:002023-02-24T00:00:00+00:00https://blog.pinarydevelopment.com/architecture/the-power-of-micro-projects/micro-projects/2/micro-project-2<aside>Starting any software development task has the potential to be daunting. There are a million details to be worked out, from business logic to technical details, implementation details to validation that all of the above works, in tandem, as expected. The process of going from ideation to delivery can be daunting. I'm taking a number of posts to walk through the development process I used to create a product from scratch. Attempting to discuss each stage of the process and document the approach I took to iteration and delivery.</aside>
<p><em>In the previous post, I discussed the first micro-project I utilized to get this application started. It discussed my exploration around Azure blob storage and some of the data models I utilized to get the application off of the ground.</em></p>
<blockquote>
<p>This series of posts is intended to walk through the development lifecycle I took for this application as well as to document different approaches to software design and development that I’ve utilized along the way. One piece that I feel has been very important to my approach to software development, both professionally and personally is the power of what I like to refer to as the ‘micro-project’. In the introduction, I mentioned three micro-projects I utilized for the initial delivery of this application. I would like to focus on each one a bit and discuss the explorations/benefits of each.</p>
</blockquote>
<h1 id="micro-project-2">Micro-project #2</h1>
<p>Launching off of the previous micro-project, I now knew how I was going to store the audio files. I wanted to delve into the manipulation of those files. <em>To be clear, this step was entirely unnecessary. The application could’ve taken the files sent by the lecturers and provided them directly to the attendees via a web interface. I took this detour for a couple of reasons.</em></p>
<ol>
<li>I believe it is worthwhile to be a responsible steward of the World Wide Web. We are all in this together and the more irresponsible we are with the applications we develop, the more everyone is effected.</li>
<li>As these lectures are publicly available and free of charge, there is a wide variety of people that participate. Some are in lower income brackets. I didn’t want to assume that everyone utilizing the application had high-speed internet or unlimited data plans on their cellphones.</li>
<li>Since I was doing this on a volunteer basis, I wanted to utilize the opportunity to explore new vistas with the project and push myself technically.</li>
<li>Seeing that this step was completely unnecessary to achieve an entirely functional application. I knew that I could time-box this effort and if it wasn’t working within x amount of time(in this case a week), I could set aside the work for a later date. As this approach would effect the pathing of files and have a few other downstream effects, it made sense though to try to have this functionality from day 1.</li>
</ol>
<h3 id="research-problem-space">Research problem space</h3>
<p>The first step of this process was research. As I’d never worked with audio files before, I started searching around for how to make audio files smaller. There were some results around the compression algorithm used by the server to return the http response. While this would positively impact every request responded to by the server, not just the audio file responses, for the audio files specifically there was a minimal amount of savings.</p>
<p>Looking at the C# landscape, there was one library that seemed to be the main library for audio manipulation, <a href="https://github.com/naudio/NAudio">NAudio</a>. Looking at the docs and reading many articles by <a href="https://markheath.net/">the author</a> of the library, this seemed very promising. The library is well documented and has many examples. There were also a few PluralSight courses on the library by the author and there just so happened to be a ‘free weekend’ on the horizon. After quite a bit of reading and watching, I’d learned quite a bit about how audio files are created and what some of the differences were between some of the main audio encodings. This area was fun to explore and helped me to understand why the mp3 files that I received were so much smaller than wav files of similar playback length(40MB vs 1GB).</p>
<p>Through this exploration as well, I understood that what would have a minimal impact on the audio quality of the files I was working with, but would effect a meaningful reduction of the end file size was the bitrate. In short, the higher the bitrate, the larger the file size and the higher the audio fidelity. BUT, the fidelity matters most when there is a lot of subtlety to the audio, i.e. music. When the audio is someone speaking, where there is really just one sound of interest and not a whole lot of variety in that sound, then the bitrate becomes less important. In fact, utilizing a bitrate of 32kbps effects an imperceptible change in the quality of the audio for lectures, whereas 320kbps would be a bitrate recommended more for music files.</p>
<h3 id="attempt-1">Attempt #1</h3>
<p>I set out trying to learn how to reduce the sample rate with NAudio and…well, I couldn’t get it to work. As I stated, there are some really good docs and walk-throughs out there on the library itself, but no matter what I tried, I couldn’t get it to work. It seemed as though there were aspects of the library that relied upon certain executables or libraries that were Windows OS specific. So after a day of exploration on that front, I put the work with NAudio aside and decided to do a bit more research.</p>
<h3 id="back-to-the-drawing-board">Back to the drawing board</h3>
<p>Knowing now the specific aspect of the data manipulation I wanted to focus on, I changed the focus of my search. I also tried to look into <a href="https://www.audacityteam.org/">Audacity</a> a bit to see what they used under the hood. And that is when I stumbled upon <a href="https://ffmpeg.org/">ffmpeg</a>. It is cross-platform, is invocable via the cli and seemed to not only have what I was looking for currently, but so much more that could be utilized for additional functionality later on.</p>
<h3 id="attempt-2">Attempt #2</h3>
<p>Seeing that this was an executable and not a library to be referenced in code, I needed a bit of a different approach than what I’m used to. I started out by downloading the executable into a directory on my machine and then proceeded to try to invoke commands against the cli with a sample audio file. I wanted to see if I could effect the file reduction, but was also hoping to listen a bit to the before and after files to validate what I’d read on ‘the webs’ about the imperceptible-ness of the loss of quality. Utilizing their docs, in a relatively short amount of time, I was able to get what I wanted to happen from the cli, which looked roughly as follows: <code class="language-plaintext highlighter-rouge">ffmpeg.exe -y -i \"{TempLocalFilePath}\" -codec:a libmp3lame -b:a {ReducedBitRate} -ac 1 \"{outputFilePath}\"</code>. That was such a great feeling. Step 1 complete! Still had a ways to go though.</p>
<h3 id="taking-one-step-at-a-time">Taking one step at a time</h3>
<p>The next step was to get the cli invocation working from C#. For that, I created a small console program, utilizing my already downloaded executable. This was new to me. I’m used to writing programs that do things, not writing programs that utilize other programs to do things. It struck me as a great way forward though. We utilize libraries all the time to perform a variety of actions without the need to write it all ourselves. Why not extend this further? Why not take specialized programs, that have been written in any language at all, and utilize them for their specialty without any understanding of their inner workings. This also turned out to be surprisingly easy:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
</pre></td><td class="code"><pre><span class="kt">var</span> <span class="n">workingDirectory</span> <span class="p">=</span> <span class="n">Path</span><span class="p">.</span><span class="nf">Combine</span><span class="p">(</span><span class="s">"C:\...\MyProgram\bin"</span><span class="p">,</span> <span class="s">"ffmpeg"</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">pathToExecutable</span> <span class="p">=</span> <span class="n">Path</span><span class="p">.</span><span class="nf">Combine</span><span class="p">(</span><span class="s">"C:\...\MyProgram\bin\ffmpeg"</span><span class="p">,</span> <span class="s">"ffmpeg.exe"</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">outputFileName</span> <span class="p">=</span> <span class="s">$"</span><span class="p">{</span><span class="n">Lecture</span><span class="p">.</span><span class="n">Title</span><span class="p">}</span><span class="s"> - </span><span class="p">{</span><span class="n">Lecture</span><span class="p">.</span><span class="n">Subtitle</span><span class="p">}</span><span class="s"> (</span><span class="p">{</span><span class="n">Lecture</span><span class="p">.</span><span class="n">RecordedOn</span><span class="p">.</span><span class="nf">ToString</span><span class="p">(</span><span class="s">"MMM d yyyy"</span><span class="p">)}</span><span class="s">).mp3"</span><span class="p">;</span>
<span class="kt">var</span> <span class="n">outputFilePath</span> <span class="p">=</span> <span class="n">Path</span><span class="p">.</span><span class="nf">Combine</span><span class="p">(</span><span class="n">TempFileDirectory</span><span class="p">,</span> <span class="n">outputFileName</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">info</span> <span class="p">=</span> <span class="k">new</span> <span class="n">ProcessStartInfo</span>
<span class="p">{</span>
<span class="n">FileName</span> <span class="p">=</span> <span class="n">pathToExecutable</span><span class="p">,</span>
<span class="n">WorkingDirectory</span> <span class="p">=</span> <span class="n">workingDirectory</span><span class="p">,</span>
<span class="n">Arguments</span> <span class="p">=</span> <span class="s">$"-y -i \"</span><span class="p">{</span><span class="n">OriginalFilePath</span><span class="p">}</span><span class="s">\" -codec:a libmp3lame -b:a </span><span class="p">{</span><span class="n">ReducedBitRate</span><span class="p">}</span><span class="s"> -ac 1 \"</span><span class="p">{</span><span class="n">outputFilePath</span><span class="p">}</span><span class="s">\""</span><span class="p">,</span>
<span class="n">RedirectStandardInput</span> <span class="p">=</span> <span class="k">false</span><span class="p">,</span>
<span class="n">RedirectStandardOutput</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span>
<span class="n">UseShellExecute</span> <span class="p">=</span> <span class="k">false</span><span class="p">,</span>
<span class="n">CreateNoWindow</span> <span class="p">=</span> <span class="k">true</span>
<span class="p">};</span>
<span class="k">using</span> <span class="nn">var</span> <span class="n">proc</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Process</span>
<span class="p">{</span>
<span class="n">StartInfo</span> <span class="p">=</span> <span class="n">info</span>
<span class="p">};</span>
<span class="n">proc</span><span class="p">.</span><span class="nf">Start</span><span class="p">();</span>
<span class="n">proc</span><span class="p">.</span><span class="nf">WaitForExit</span><span class="p">();</span>
<span class="n">File</span><span class="p">.</span><span class="nf">Delete</span><span class="p">(</span><span class="n">OriginalFilePath</span><span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></figure>
<p>At this point, my optimism was really picking up. After days of research and tinkering, significant progress was happening. While the above took a few hours, I was able to see/feel continuous, incremental progress. Following the previous steps, I wanted to perform this invocation from an Azure Function app instead of the Console app.</p>
<p>There are a number of different ways that an Azure function can be triggered. For my specific use case, I saw the easiest way to get started with this was to utilize the <code class="language-plaintext highlighter-rouge">BlobTrigger</code> provided by the SDK. This is basically a message queue. Azure seemingly emits events when something happens within a blob storage container. The <code class="language-plaintext highlighter-rouge">BlobTrigger</code> attribute sets up a listener for those events and then gets invoked in response to them. When a new audio file was uploaded into a given root path, via the Azure UI, the Azure function would get triggered in response to the Azure blob storage event and the associated method would get invoked. While this definitely took some time digging through Microsoft’s docs, it was relatively easy. The above function was encapsulated in an <code class="language-plaintext highlighter-rouge">AudioFileService</code> and the resulting function code looked like this:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="code"><pre><span class="p">[</span><span class="nf">FunctionName</span><span class="p">(</span><span class="s">"OriginalFileListener"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">BlobListener</span><span class="p">([</span><span class="nf">BlobTrigger</span><span class="p">(</span><span class="n">StaticData</span><span class="p">.</span><span class="n">ContainerName</span> <span class="p">+</span> <span class="s">"/"</span> <span class="p">+</span> <span class="n">StaticData</span><span class="p">.</span><span class="n">UploadedFileRootContainerPath</span> <span class="p">+</span> <span class="s">"/{name}"</span><span class="p">,</span> <span class="n">Connection</span> <span class="p">=</span> <span class="s">""</span><span class="p">)]</span><span class="n">ICloudBlob</span> <span class="n">blob</span><span class="p">,</span> <span class="kt">string</span> <span class="n">name</span><span class="p">,</span> <span class="n">ILogger</span> <span class="n">log</span><span class="p">,</span> <span class="n">ExecutionContext</span> <span class="n">context</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">log</span><span class="p">.</span><span class="nf">LogInformation</span><span class="p">(</span><span class="s">$"Executing directory: </span><span class="p">{</span><span class="n">context</span><span class="p">.</span><span class="n">FunctionAppDirectory</span><span class="p">}</span><span class="s">"</span><span class="p">);</span>
<span class="n">log</span><span class="p">.</span><span class="nf">LogInformation</span><span class="p">(</span><span class="s">$"Processing Name: </span><span class="p">{</span><span class="n">name</span><span class="p">}</span><span class="s">, Size: </span><span class="p">{</span><span class="n">blob</span><span class="p">.</span><span class="n">Properties</span><span class="p">.</span><span class="n">Length</span><span class="p">}</span><span class="s">b"</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">podcastMetadata</span> <span class="p">=</span> <span class="n">StaticData</span><span class="p">.</span><span class="n">OriginalLectureSeriesMetadata</span><span class="p">;</span>
<span class="kt">var</span> <span class="n">audioFileService</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">AudioFileService</span><span class="p">(</span><span class="n">blob</span><span class="p">,</span> <span class="n">context</span><span class="p">);</span>
<span class="k">await</span> <span class="n">audioFileService</span><span class="p">.</span><span class="nf">ProcessFile</span><span class="p">(</span><span class="n">podcastMetadata</span><span class="p">).</span><span class="nf">ConfigureAwait</span><span class="p">(</span><span class="k">false</span><span class="p">);</span>
<span class="n">log</span><span class="p">.</span><span class="nf">LogInformation</span><span class="p">(</span><span class="s">$"Uploaded Name:</span><span class="p">{</span><span class="n">Path</span><span class="p">.</span><span class="nf">GetFileName</span><span class="p">(</span><span class="n">audioFileService</span><span class="p">.</span><span class="n">OutgoingBlobReference</span><span class="p">.</span><span class="n">Name</span><span class="p">)}</span><span class="s">, Size: </span><span class="p">{</span><span class="n">audioFileService</span><span class="p">.</span><span class="n">OutgoingBlobReference</span><span class="p">.</span><span class="n">Properties</span><span class="p">.</span><span class="n">Length</span><span class="p">}</span><span class="s">b"</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></figure>
<blockquote>
<p>Reviewing the code after all these years, its semi-amusing to see some of the naming and other inconsistencies that were a part of the project in the early days. I remind myself though that the initial release happened in around 10 days. I was definitely moving quickly and spending a lot of time naming things wasn’t a priority. I believe that most of that has been corrected over the course of time. I also remember that this project initially felt like I was building a podcast. I even did research into the xml format required for a podcast as that was a desired feature initially. While I have the code to make that happen(not fully tested yet), it hasn’t been used to date. It was a good reminder for me though to try to name things for what they are/represent and not for how you think they might be utilized as a part of an application.</p>
</blockquote>
<h3 id="the-rough-waters">The rough waters</h3>
<p>Reviewing the code above again also allowed me to remember that it wasn’t all smooth sailing. Getting the above to work locally went relatively smoothly. At this point, I utilized the Azure DevOps UI to create a build/deploy pipeline(utilizing their ‘Classic’ UI which was all drag and drop) and was able to integrate that into the GitHub repo. I created my Azure function via the Azure UI as well and had the pipeline deploy any code changes out to the function. This went relatively smoothly. My experience with Azure DevOps has been that they are pretty well documented, but it isn’t always easy to find the documentation and there are quite a few variables that relate to the built-in paths on the build agent that are very similar but not quite the same. It took quite a number of failed builds and digging through logs to get everything working as expected. Still, it was a relatively easy win.</p>
<p>That is when the next set of difficulties set in though. While everything was working well with my function locally, there were a few things that still needed to be worked out to get it working in Azure. For starters, GitHub doesn’t allow you to upload an exe as a part of your repository. That meant that the ffmpeg executable that I’d downloaded locally needed to get into my build artifacts somehow. Luckily, someone else had already created a NuGet package to do just that. I deleted the .exe I had downloaded, installed the <code class="language-plaintext highlighter-rouge">FFmpeg.Win64.Static</code> NuGet package and was past hurdle #1.</p>
<p>The next hurdle turned out to be much more difficult to track down and to solve. When executing code via an Azure function, it is obviously being run on a computer in Azure’s cloud. Since that is the case, Azure, understandably, has some security measures in place to protect the execution of any given function code from effecting the machine its running on and the other code that is also running on that machine. These measures are intended to shield the execution from constraining resources for other code running on the same machine as well as protecting the code from any sort of cross contamination. One function app shouldn’t be able to have an effect on any other function app, including its code files, etc.</p>
<p>That being the case, via multiple failed attempts and copious amounts of logging, I discovered that there were two main hurdles to work around. Invoking the .exe as I had done above worked great locally, but the Azure function only allowed execution like that to be performed from within a specific directory. Apparently that directory is the one given the permissions, by the executing context, to perform such actions. Presumably it is a well known location and extra locked-down to allow this capability. The other location to pin down was one in which file manipulation was allowed. The function needed to read(exe had to read it in order to change the bitrate) and write(download the original file from blob storage and write the reduced file post-manipulation) files to the directory in order to function correctly.</p>
<p>The location required for the file manipulation turned out to have a relatively straightforward solution. There are many things I like and find intuitive about .NET, but the APIs around the file system have always been tricky for me. Combine that with the fact that the Azure function is working in a virtual file system and the problem felt even tougher. <code class="language-plaintext highlighter-rouge">Directory</code> has a method <a href="https://learn.microsoft.com/en-us/dotnet/api/system.environment.getfolderpath?redirectedfrom=MSDN&view=net-7.0#System_Environment_GetFolderPath_System_Environment_SpecialFolder_"><code class="language-plaintext highlighter-rouge">GetFolderPath</code></a> which takes in an <a href="https://learn.microsoft.com/en-us/dotnet/api/system.environment.specialfolder?view=net-7.0"><code class="language-plaintext highlighter-rouge">Enum</code></a> that enables the retrieval of ‘special’ folders in Windows. Scrolling through the list in Microsoft’s docs, I didn’t see any that seemed to point to the ‘temporary’ file location. After a quick search I came up with <code class="language-plaintext highlighter-rouge">Path.GetTempPath()</code>. On a Windows machine, this points to <code class="language-plaintext highlighter-rouge">C:\Users\{UserName}\AppData\Local\Temp</code>. This is a folder used by many programs to temporarily place files needed for a specific, usually, short-lived action. I didn’t know how it would work in an Azure function, but thankfully it ‘just’ worked.</p>
<p>The other issue I needed to figure out was how I could get the path to the exe and execute it. While the Microsoft docs are pretty good, most of the examples show the most basic function/trigger and don’t provide too much more. Anything more advanced than that usually takes quite a bit of Bingling and investigation. For this, I needed to look at the WebJobs SDK documentation to discover the <a href="https://learn.microsoft.com/en-us/azure/app-service/webjobs-sdk-how-to#executioncontext"><code class="language-plaintext highlighter-rouge">ExecutionContext</code></a>. The <code class="language-plaintext highlighter-rouge">ExecutionContext</code> has two properties of interest: <code class="language-plaintext highlighter-rouge">FunctionDirectory</code>, <code class="language-plaintext highlighter-rouge">FunctionAppDirectory</code>. Through a little trial and error, I discovered that the <code class="language-plaintext highlighter-rouge">FunctionAppDirectory</code> was the one that worked for me. While not hard to discover, the fact that I had to push/build/deploy multiple times throughout the investigation process, made the work tedious.</p>
<p>While the file manipulation piece of the code was definitely the most time intensive portion of the original development, it was also the most rewarding. I was able to time-box the effort, push my creativity and development chops and walk away from it with something that I was quite proud of. I was able to meet my timeline and not compromise on what I felt was the ‘right way’ to building the application. In a world where software development is often prodded to skip steps and compromise on software quality for a business’ bottom line, it was invigorating to instead put the stewardship of the web and the end user first.</p>
<h3 id="gained-focus">Gained focus</h3>
<p>Through this initial micro-implementation, I was able to focus on one aspect of the broader problem to solve. In doing so I had to:</p>
<ol>
<li>Understand what optimizations could be made to an audio file and which of those optimizations would effect a lower file size without impacting perceptible quality.</li>
<li>Determine how to reduce the bitrate of an audio file.</li>
<li>Learn how to execute an executable via C#.</li>
<li>Understand the directory structure/permissions for an Azure function.</li>
</ol>
<h3 id="reduced-distractions">Reduced distractions</h3>
<p>In the previous micro-project, I was able to reduce distractions from the outset by breaking the entire application I wanted to develop into 3 areas of focus. As I progressed through this micro-project, I reduced distractions by determining what was the next incremental piece of code that would get me closer to the over all target. By taking the project in small increments, I was able to remove big distractions via focusing on little problems every step of the way. This reduced the unknown ‘big problem’ that would’ve compounded if the whole process was tackled at one go. Knowing each step of the way that 90% of that particular problem was solved made solving the remaining 10% seem achievable.</p>
<ol>
<li>I was able to research to know what problem I needed to solve to reduce the file size.</li>
<li>Identify a program that was able to perform the reduction.</li>
<li>Iterate quickly via the cli on exactly which parameters were needed to perform the reduction.</li>
<li>Focus on how to invoke an executable with C#.</li>
<li>Determine how to get an executable into the release package since source code’s limitations wouldn’t allow it there.</li>
<li>Pinpoint how to run the entire piece of code via a deployed Azure function.</li>
</ol>
<p>The difficult and most unknown portion of the initial deliverable was now out of the way. In addition to this, I added two small endpoints, one to return the audio file and one to return information about the lecture. The next step was to create the frontend so that users could actually access these files.</p>Micro-project #2 in the series explores reducing the size of audio files and executing an executable within an Azure function via C#.The Story Behind the Application - Micro-project 12023-01-27T00:00:00+00:002023-01-27T00:00:00+00:00https://blog.pinarydevelopment.com/architecture/the-power-of-micro-projects/micro-projects/1/micro-project-1<aside>Starting any software development task has the potential to be daunting. There are a million details to be worked out, from business logic to technical details, implementation details to validation that all of the above works in tandem as expected. The process of going from ideation to delivery can be daunting. I'm taking a number of posts to walk through the development process I used to create a product from scratch. Attempting to discuss each stage of the process and document the approach I took to iteration and delivery.</aside>
<p><em>In the previous post, I started walking through the impetus behind the application and the progression of the first phase of the project. To recap, the goal of the application was to provide a site for a non-profit organization that delivers a lot of classes to the public. Due to the nature of the classes and the fact that there was a large long-running series that was starting soon, there was a desire to have a web app to go along with the series to enable attendees to catch up on classes that they missed or get an introduction to the material outside of the scheduled in-person lecture.</em></p>
<blockquote>
<p>This series of posts is intended to walk through the development lifecycle I took for this application as well as to document different approaches to software design and development that I’ve utilized along the way. One piece that I feel has been very important to my approach to software development, both professionally and personally is the power of what I like to refer to as the ‘micro-project’. In the introduction, I mentioned three micro-projects I utilized for the initial delivery of this application. I would like to focus on each one a bit and discuss the explorations/benefits of each.</p>
</blockquote>
<p>Micro-projects have been a very beneficial approach for me for a number of reasons. One is that it helps me break down problem spaces into small bite-sized chunks. While this application wasn’t meant to be a huge project, even the initial deliverable had a number of things that were unknown to me when I started it. One problem I knew I would need to solve was a way/means to store all of the audio files.</p>
<h1 id="micro-project-1">Micro-project #1</h1>
<p>As mentioned in the previous post, I’m familiar with Azure as a cloud provider and had settled on Azure blob storage as the means of storing all of the audio files. I knew that the initial iterations on the app were going to be rough and raw. So I wanted to test out the ability to connect to Azure storage and upload a file to it. I also wanted to organize the files in storage in a way that I would easily be able to find them if/when something went wrong.</p>
<blockquote>
<p>As this project is now three years old, the packages referenced and related code aren’t current. They are using previous(now deprecated) sdks/apis. I believe that they are fine to share still though as this is about the process of development and not showing the current way of making this specific functionality work. The code has been updated to the latest SDKs in the current codebase.</p>
</blockquote>
<p>I decided to use WinForms to create a small application that I would use initially for uploading the new files to blob storage. While setting up the UI and the event handling of a WinForms app can mostly be done via the UI provided in Visual Studio, I’m not familiar with how asynchronicity works in WinForms events. As this fact isn’t critical to the functioning of the application and I didn’t want to deep dive or get sidetracked by trying to learn that and the fact that the SDK’s all provide asynchronous methods, I call each method in a synchronous fashion by appending <code class="language-plaintext highlighter-rouge">.ConfigureAwait(false).GetAwaiter().GetResult()</code> to the end of each invocation that returns a <code class="language-plaintext highlighter-rouge">Task</code>.</p>
<p>I could’ve put all of the asynchronous code in one method and would’ve only had to have done the above once, but I just wanted it working, so I didn’t do any method extraction, but used one long method instead. The relevant code looked as follows:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="code"><pre><span class="kt">var</span> <span class="n">cloudBlobClient</span> <span class="p">=</span> <span class="n">CloudStorageAccount</span><span class="p">.</span><span class="nf">Parse</span><span class="p">(</span><span class="n">ConfigurationManager</span><span class="p">.</span><span class="n">ConnectionStrings</span><span class="p">[</span><span class="s">"AzureStorage"</span><span class="p">].</span><span class="n">ConnectionString</span><span class="p">).</span><span class="nf">CreateCloudBlobClient</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">containerReference</span> <span class="p">=</span> <span class="n">cloudBlobClient</span><span class="p">.</span><span class="nf">GetContainerReference</span><span class="p">(</span><span class="s">"lectures"</span><span class="p">);</span>
<span class="n">containerReference</span><span class="p">.</span><span class="nf">CreateIfNotExistsAsync</span><span class="p">().</span><span class="nf">ConfigureAwait</span><span class="p">(</span><span class="k">false</span><span class="p">).</span><span class="nf">GetAwaiter</span><span class="p">().</span><span class="nf">GetResult</span><span class="p">();</span>
<span class="k">static</span> <span class="kt">string</span> <span class="nf">createPathPart</span><span class="p">(</span><span class="kt">string</span> <span class="n">str</span><span class="p">)</span> <span class="p">=></span> <span class="n">str</span><span class="p">.</span><span class="nf">ToLowerInvariant</span><span class="p">().</span><span class="nf">Replace</span><span class="p">(</span><span class="s">" "</span><span class="p">,</span> <span class="kt">string</span><span class="p">.</span><span class="n">Empty</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">cloudFilePath</span> <span class="p">=</span> <span class="n">Path</span><span class="p">.</span><span class="nf">Combine</span><span class="p">(</span><span class="s">"src"</span><span class="p">,</span> <span class="nf">createPathPart</span><span class="p">(</span><span class="n">author</span><span class="p">.</span><span class="n">Fullname</span><span class="p">));</span>
<span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">grouping</span> <span class="k">in</span> <span class="n">lecture</span><span class="p">.</span><span class="n">Groups</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">cloudFilePath</span> <span class="p">=</span> <span class="n">Path</span><span class="p">.</span><span class="nf">Combine</span><span class="p">(</span><span class="n">cloudFilePath</span><span class="p">,</span> <span class="nf">createPathPart</span><span class="p">(</span><span class="n">grouping</span><span class="p">));</span>
<span class="p">}</span>
<span class="n">cloudFilePath</span> <span class="p">=</span> <span class="n">Path</span><span class="p">.</span><span class="nf">Combine</span><span class="p">(</span><span class="n">cloudFilePath</span><span class="p">,</span> <span class="s">$"</span><span class="p">{</span><span class="n">lecture</span><span class="p">.</span><span class="n">Topic</span><span class="p">}</span><span class="s">-</span><span class="p">{</span><span class="n">lecture</span><span class="p">.</span><span class="n">Version</span><span class="p">}</span><span class="s">-</span><span class="p">{</span><span class="n">date</span><span class="p">.</span><span class="nf">ToString</span><span class="p">(</span><span class="s">"yyyy.MM.dd"</span><span class="p">)}{</span><span class="n">Path</span><span class="p">.</span><span class="nf">GetExtension</span><span class="p">(</span><span class="n">originalFileName</span><span class="p">).</span><span class="nf">ToLowerInvariant</span><span class="p">()}</span><span class="s">"</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">blockBlobReference</span> <span class="p">=</span> <span class="n">containerReference</span><span class="p">.</span><span class="nf">GetBlockBlobReference</span><span class="p">(</span><span class="n">cloudFilePath</span><span class="p">);</span>
<span class="n">blockBlobReference</span><span class="p">.</span><span class="nf">UploadFromStreamAsync</span><span class="p">(</span><span class="n">fileDialog</span><span class="p">.</span><span class="nf">OpenFile</span><span class="p">()).</span><span class="nf">ConfigureAwait</span><span class="p">(</span><span class="k">false</span><span class="p">).</span><span class="nf">GetAwaiter</span><span class="p">().</span><span class="nf">GetResult</span><span class="p">();</span>
</pre></td></tr></tbody></table></code></pre></figure>
<p>A brief explanation of the preceding code is as follows:</p>
<ol>
<li>Get the configuration necessary to create a connection to Azure storage.</li>
<li>Get a reference to the container that will contain all of the files for the organization. <em>Each storage account can have multiple containers. These are the partitions used within a storage account.</em> I chose to create a container named specifically for the organization, so that I could utilize the application to support additional organizations in the future and have the partitioning make sense.</li>
<li>Create the filename, including the virtual directory it is contained within. <em>Inside of the containers, there aren’t really directories. Each blob is just a filename and its contents. If the filename includes a <code class="language-plaintext highlighter-rouge">/</code> then blob storage creates virtual directories to represent that segmentation even though in actuality that segmentation doesn’t exist.</em> More information about naming restrictions can be found in <a href="https://learn.microsoft.com/en-us/rest/api/storageservices/naming-and-referencing-containers--blobs--and-metadata">Microsoft’s docs</a>. As can be seen or assumed from the above though, I own all of the data at this point, nothing is user entered from a webpage, so I skipped any sort of name validation or enforcement and just utilized the hard-coded data I created. I was careful with the data that was created to not include any characters (like an <code class="language-plaintext highlighter-rouge">'</code>)that might be an issue with Url encoding or Azure’s restrictions in order to move quickly on the project and avoid errors.</li>
<li>Get a reference to the actual blob(this is in the container, which in turn is in the storage account). A blob is the actual file contents as well as the metadata associated with said file.</li>
<li>Upload the file.</li>
</ol>
<p>And that was it…</p>
<p>While small and simple, it was a very impactful first step.</p>
<h3 id="gained-focus">Gained focus</h3>
<p>Through this initial micro-implementation, I was able to focus on one aspect of the broader problem to solve. In doing so I had to:</p>
<ol>
<li>Work out how to connect to Azure blob storage.</li>
<li>Determine what the correct connection string format was.</li>
<li>Learn the different Azure blob storage concepts.</li>
<li>Understand the correct order in which to invoke all of the methods.</li>
<li>Figure out how to craft a valid filename</li>
<li>Successfully upload the file(use a stream or a bytearray?, etc).</li>
</ol>
<p>I was also able to iterate quickly on the format of the filename and the virtual directories associated with each one to get a feel for which felt more intuitive for me to maintain long-term. Azure blob storage’s UI has the ability to ‘search’ on a blob name, but the search is really a ‘starts with’ filter. This realization led me to iterate on the best virtual directory structure and filename for quickly locating files that seemed to have processed incorrectly. I was also able to manually download the file from storage post-upload to verify that my implementation didn’t create and corruption in the file itself.</p>
<h3 id="reduced-distractions">Reduced distractions</h3>
<p>In my experience, the ability to narrow down the problem space and focus on small parts of the larger problem/implementation at a time, really enables cleaner, clearer code. Creating a ton of abstraction from the get go or trying to anticipate every eventual possibility, often leads to overly complicated, confusing, hard to read/hard to debug code. In utilizing the approach above, even for this small problem, I was able to create a small application with a UI. The UI was created via drag and drop in Visual Studio. It won’t win any design awards, but it was easy for me to launch everyday and easy for me to upload new lectures. This limited the potential for typos and allowed me to iterate quickly.</p>
<p>I was able to ignore a number of things that could’ve been distractions from this core problem, such as:</p>
<ol>
<li>I was able to utilize <code class="language-plaintext highlighter-rouge">ConfigurationManager</code> to do so and didn’t have to worry about how Azure functions deals with configurations/connection strings.</li>
<li>I ignored the retrieval of files.</li>
<li>I didn’t need to concern myself with the user interface and the validation concerns that would be much more relevant if the data was coming from the user.</li>
</ol>
<p>With the proof of concept one out of the way, I had something of value, that took me one step closer to my initial launch goal and allowed me to move on to problem #2, namely utilizing an Azure function to perform file manipulation to reduce the sampling size and file size of each audio file.</p>Micro-project #1 in the series explores iterating on the utilization of Azure storage for the audio files and exploring some of the data modeling needed for the project.The Story Behind the Application - Introduction2023-01-13T00:00:00+00:002023-01-13T00:00:00+00:00https://blog.pinarydevelopment.com/architecture/the-power-of-micro-projects/introduction<h1 id="background">Background</h1>
<p>I started a new development project a while back, one that I noodle on ‘when I find time’, and wanted to document some of the thought processes behind the development process and project itself. Anytime I find myself in some sort of a mentorship role, I encourage developers to utilize a lot of little side projects. This isn’t the ‘trite’, 120%-time or the ‘going above and beyond’ side projects that I’m referring to, but rather small, easily set-up, easily tossed away projects that can aid in quickly iterating on ideas. I’ve found these to provide a lot of rapid feedback and over time, have found that they’ve influenced the way I approach software development and the architecture of the systems I write. I’ve utilized many prototyping tools to aid in this process: CodePen, DotNetFiddle, StackBlitz, Docker and my local machine.</p>
<p>A project that I took on in the recent past was a good example of this for me. It required quite a number of these prototypes and has led to a full-fledged iteratively developed application. First I would like to describe the project at its inception, describe the process I’ve used along the way to create it and then provide some documentation of where it stands now with an eye towards future growth.</p>
<h1 id="application-description">Application description</h1>
<p>There is an organization I’m involved with that provides a number of services. One of them is educational classes. The classes are drop-in(no registration required), happen on a regular basis, usually are around 1hr long and are audio recorded. Some are stand alone classes, while others are short class series and some are long running series. The initial goal of the application was to be able to quickly setup an application that would take in the recorded classes, store them and present them to users via a web interface so attendees could catch up on lectures they missed, sample new topics or explore new vistas. As it happened, there was a long-running series that was going to start in the near future that seemed a great use-case for this app. The goal was that the initial implementation would be done quickly to enable the best adoption.</p>
<h1 id="initial-decisions">Initial decisions</h1>
<p>Seeing as I wanted the initial implementation to be very delivered on a very short timeline, it seemed logical to start with the development stack I know best. The elements of the development stack that I use regularly are: Angular for the front-end, C# for the back-end, Azure as the cloud provider and GitHub as the source repository as well as the host for the static web application assets. While Azure DevOps would have also been a logical choice for the source code, I was hoping to get others involved in the development of the application and the public model that GiHub has, seemed to be the easiest way to enable that. GitHub also has a very easy way of hosting static applications via HTTPS.</p>
<p>I’ve written before about the segmentation of projects I use for a <a href="/architecture/patterns/service-oriented/overview">C# micro-service</a> and while I’m aware of other micro-service architectures, this is still the one that I’ve seen to be most effective and easy to understand. I wanted to follow web best practices and also wanted to challenge myself in the realm of cost to run the application. The organization the application was being built for is a not for profit organization and I would be footing the bill as a part of my contribution to the organization.</p>
<p>Knowing that I was going to utilize Azure as the cloud provider for the application, I looked into its offerings regarding file storage and creating REST apis. Azure Blob Storage seemed logical for the first piece, but the second decision had a few more options. I wanted something as light weight as possible and landed on Azure Functions for the job.</p>
<h1 id="micro-project-1">Micro-project #1</h1>
<h3 id="getting-started-with-azure-blob-storage-sdk">Getting started with Azure Blob Storage SDK</h3>
<p>With those decisions made, I began my first micro-project. I set out trying to get a bare-bones app that could upload files to Azure Blob Storage. For this, I decided to use <a href="https://github.com/PinaryDevelopment/torahis.life/commit/e024992281946c8a7cc6445cd88875f0fe2be886">WinForms</a>. While there are many jokes around the battleship looking applications that WinForms produces, the drag and drop style of creating controls and the small amount of code required to interact with those controls made it a great option. This allowed me to quickly iterate on the data model to use for the metadata associated with each lecture uploaded and allowed me a sandbox for understanding the Azure Blob Storage apis. As I never planned on distributing the WinForms app out to the lecturers, the initial release required the lecturer to email the class to me every day, which I would then download and use the app to upload. To achieve a faster time to delivery, I also utilized embedding some of the metadata(Lecturer name, Date of class, etc) for each class in the name of the file itself.</p>
<h1 id="micro-project-2">Micro-project #2</h1>
<h3 id="getting-started-with-audio-file-manipulation">Getting started with audio file manipulation</h3>
<p>As mentioned previously, I wanted to not only challenge myself regarding the ongoing costs of the application, but I also wanted to try to be a responsible contributor to the world wide web. To enable the most users benefit from the application, I wanted the class’ on-disk sizes to be the smallest they could. No matter a user’s type of connection, I wanted the data download required to run the app to be as small as possible. This would make the app faster, but also reduce the cost to the end user if they are paying for cellular data. The classes that were being uploaded, on average, were an hour in length. The recording device used and the settings selected on it, could cause the file to be anywhere from 40MB to 1GB each. While this was surprising to me at first, after doing some research and understanding better how audio files are created, I came to realize that there are different standards around encoding audio files and as time has gone on, newer standards have a number of efficiencies built in that weren’t there previously. I also learned that the ‘sampling rate’ of the audio file plays a big role and for regular speech, the sampling rate can be dialed way down without any noticeable difference in the perceptible audio quality. Now I experimented with my second micro-project in which I created a proof-of-concept of how to do this locally via an <a href="https://github.com/PinaryDevelopment/torahis.life/commit/562e142efea510d02030d08e20554dbdafd3953c">Azure Functions project</a> running through Visual Studio. By the end of this iteration, the classes that were downloaded by the users were now consistently in the 10MB range…quite an improvement.</p>
<p>With those items in place, I manually created an Azure Function in the cloud on a Windows machine, created an <code class="language-plaintext highlighter-rouge">azure-pipelines.yml</code> file by walking through the Azure DevOps UI, finding the steps I wanted and then copying the yaml they produced for each step to my file. The tools worked so well that I was able to complete all of this in a week and a half, most of which was spent trying to get the audio file manipulation working correctly.</p>
<p>The process of utilizing micro-projects to prove certain aspects of the application and then working on stitching them together to create the complete application is similar in concept to unit tests. I was able to prove aspects of my design with the micro-projects, but that didn’t prove that they all worked together to create a functioning application. There was definitely some time spent on getting it worked when deployed to Azure as I had to learn how to connect the function to blob storage and what directories were available to me in the running function to find the deployed executable used for audio manipulation as well as which directories I could write the output, reduced-file-size file to. At this point though, I was confident that it could work due to the micro-projects.</p>
<h1 id="micro-project-3">Micro-project #3</h1>
<h3 id="learning-about-media-controls-in-the-browser">Learning about media controls in the browser</h3>
<p>At this point, I still needed two things: a datastore to hold the metadata for the class information(not all of it was a part of the filename) and a frontend application. GitHub pages provides a very convenient, free and fast option for hosting static web sites. The code is all public and the site has to adhere to their terms and agreements, but again, the goal was to get this out as quickly and cheaply as possible. There is one small DNS entry that needs to be entered in your DNS provider and a CNAME file needs to be added to the repo and GitHub then does all of the work for the application to be completely HTTPS. GitHub handles the certs and everything in that regard for you. Once support was there for the first series of classes, I was anticipating a much slower-paced iteration of development from there on out. I created a very small <a href="https://github.com/PinaryDevelopment/torahis.life/commit/cfe39429796f29a8572f12fc4153b5097d3f5d26">Angular application</a> with two pages: one to show the list of recordings and one that contained the audio player for a given class. As for the datastore, I decided to utilize a json file, hosted as a part of my GitHub repository that I would have to <a href="https://github.com/PinaryDevelopment/torahis.life/commit/a2dfc005f4a5c5f81d14948316baaab22d5e9675">manually update</a> after every class upload.</p>
<h1 id="initial-delivery">Initial delivery</h1>
<p>For starters, that was it. As far as the attendees were concerned, there was a fully functioning website that they could go to to catch up on or review any lectures that they wanted to. From the administrative perspective, the lecturer would need to email me the class, I would utilize the WinForm app to upload the lecture to Azure blob storage, a queue based Azure function listened for changes to the blob storage container which then kicked off a process to read the file, manipulate its sample-rate/etc and re-upload. I was then required to go into the GitHub repo and update the metadata json file. With this complete, the new lecture would show up on the website. The initial lecture in this series started on Jan 5, 2020 and the initial application was live Jan 17, 2020.</p>
<p>I’ve worked in the industry for over 10 years now and every place I’ve worked at has been ‘agile’. Every place has had VERY different interpretations as to what agile means though. I don’t fully know how to define ‘agile’, but to me, this project seems to have embraced an agile approach. Deliver MVP, then iterate in small iterations, delivering value all the way. Try to make decisions now that won’t cripple a specific development approach later on, but don’t over-engineer it to do so either.</p>
<p>At this point, while I had a fully functioning application for the end user, the manual effort on my end was small, but daily. That was to be the next focus of my efforts. Deliver value to the site maintainer :) The only long term decisions I’d made at this point were that I wasn’t maintaining the original filename of the file that was sent to me by the lecturer, but I would retain the initial file. While the filename decision resulted in a small loss of data, I deemed it to be insignificant and a worthwhile sacrifice to enable the quick release of the application. I did retain the original file and the reduced file but was only exposing the reduced file via the web application.</p>
<p>As I intended this series to document some of my development/thought processes, I also wanted to emphasize the power of the ‘micro-project’. For this application prototype, I already mentioned three that I had utilized. Before I document the next development evolution of the application, I’d like to utilize the next few posts to discuss the micro-projects I’ve mentioned so far. I hope to dive into what proof-of-concept each helped me iterate on and just as importantly, what potentially complicating issues each helped me to temporarily ignore. I’ve found this to be a very powerful way to break large difficult problems into much smaller and more manageable ones.</p>An approach to software development as documented by walking through the development of an actual application from the ground up.Development on a Budget2020-04-20T00:00:00+00:002020-04-20T00:00:00+00:00https://blog.pinarydevelopment.com/development-on-a-budget<p>Recently I volunteered to create a website for an organization with which I’m affiliated. The organization provides a number of communal educational opportunities. Most of the lectures that are given are recorded and we wanted to create a site to host all of them. The goal was to enable those in attendance to review previous material as well as enable those who were unable to attend to listen in on what they missed. The spur for this was one particular series that is going to be on-going with a new segment released every day. The lectures got underway and before I volunteered to make the website, they were being distributed via email and WhatsApp.</p>
<p>I blogged previously about ‘blogging on a budget’. This concept was inspired from two different areas. I had read about “<a href="https://code-golf.io/">Code Golf</a>”. While I found this very interesting and some of the solutions very creative, I could never really get in to doing it myself. I’ve done code katas and other coding challenges before, but had a hard time sustaining momentum as they all felt very contrived and repetitive. There are a number of blogs that I follow regularly, one of them being <a href="https://www.troyhunt.com/">Troy Hunt’s</a>. He had <a href="https://www.troyhunt.com/serverless-to-the-max-doing-big-things-for-small-dollars-with-cloudflare-workers-and-azure-functions/">an article</a> about the costs involved in running his wildly popular website <a href="https://haveibeenpwned.com/">HaveIBeenPwned</a>. This really piqued my interest and while I’m not anywhere close to his volume in terms of data or traffic, I appreciated the concept of seeing how far one could stretch a dime in the creation of their websites. The blog this article is on was the first attempt at putting these concepts into practice. Since this new website was being done on a volunteer basis, I thought it would be a good second.</p>
<p>After I had completed the initial launch of the website(done in roughly 1.5 weeks in my free time), I had some friends request knowledge of how it was done. I figured documenting it on my blog would be a great start, so here we go…</p>
<p>As discussed in the post about re-doing my blog on the cheap, GitHub Pages has been a very solid platform for me to use. It is easy to setup, SSL comes along for free and it seems to serve sites very quickly. I didn’t want to use Jekyll this time as there were too many curve-balls I encountered previously with it. I decided to use <a href="https://docs.aurelia.io">Aurelia v2</a> for the front end. This is a framework that I’ve used in the past and really enjoyed. It enjoys a very small following, but is clean, mostly straight-forward and fast. I have used Angular exclusively for my day job for the last number of years and wanted to kick the tires on something else. I’ve tried a few times, but never really been able to wrap my head around React. I’ve played with Vue before, but there seems to be a bit of turmoil in that space as of late and I really like that Aurelia and Angular have more of a full-fledged framework built into them. I don’t have to find a routing library, or any of the other pieces contained in most front-end code-bases that aren’t purely components.</p>
<p>With those decisions in place, I needed to figure out more of the backend. The original audio files I was given were sometimes mp3s, sometimes mpegs, were usually ~30min - 1hr long and anywhere from 20 - 50MB each. I wanted to be able to upload the files, create something that would automatically resize them(saving end-users bandwidth), add metadata tags to them(for nicer user experience when opening the files in an audio player application) and update the website to reference them. Nice-to-haves in the short term also included automated email/text and potentially WhatsApp notifications. A little bit more long-term goals include the creation/updating of an rss/podcast feed(s). I also wanted to have some insights into how much use the application was actually receiving.</p>
<p>Given the above, GitHub Pages would serve my static files, but I would need something to store and manipulate and retrieve the audio files. For that I decided to utilize Azure. I’ll discuss the specifics of this decision later in the article.</p>
<p>The first thing I did was buy a domain. To be clear, you don’t need to buy a domain, especially if you host it via GitHub Pages, but I enjoy giving sites a brand of their own. There are a number of vendors that provide this service. I knew that I was going to handle hosting through GitHub, so I was solely looking for a cheap place to buy a domain. The vendor I found referenced in a few places as being a good, cheap choice was NameCheap. I’ve used Google Domains in the past for this, but when pricing out the domains that interested me, NameCheap was consistently cheaper.</p>
<p>Once this was complete, I did a number of quick website-y initial setup things to get the ball rolling.</p>
<ol>
<li>I setup a repository on GitHub for the project.</li>
<li>I enabled GitHub Pages.</li>
<li>I created the CNAME document for the site to enable using my custom domain name.</li>
<li>I then pointed the CNAME DNS entry in NameCheap to point to the GitHub server IP addresses.</li>
<li>I enabled HTTPS on the website in GitHub.
As I’ve documented these steps in my article on refreshing this blog and they are well documented on <a href="https://help.github.com/en/github/working-with-github-pages/configuring-a-custom-domain-for-your-github-pages-site">GitHub Pages</a> documentation, I won’t go into more detail on these steps here.</li>
</ol>
<p>At this point, one could argue that I developed things out of order. Usually when working with clients, I try to drive the conversation towards determining what is the minimum viable product and how can we get there in the shortest amount of time. This allows one to get to market quickly(or at a minimum in front of potential users quickly), receive feedback and iterate on the product to suit the end users needs. Seeing as the audio files were being recorded and delivered to me daily, the MVP-driver in me would say to build the front-end web app to expose those files to consumers quickly and then iterate from there. That is NOT what I did though. While I’m in favor of not prematurely optimizing applications, I’m also not a proponent of ignoring those concerns completely and kicking them down the road to bite me later. The dance of all of these competing concerns is one every dev should have to grapple with on a regular basis. In this instance, the calculation was pretty clear to me. A number of people utilizing the site were going to be doing so from a mobile device and they were going to want to keep on top of the material, as new content was released daily. The size of each file, on average, was 40MB. Looking at one months worth of lectures, that would come out to 1.2GB of content which could be quite the whopper for someone’s data plan. What could be done?</p>
<p>As I’m not an expert with digital audio(only dabbled here and there), but have used a free product called <a href="https://www.audacityteam.org/">Audacity</a> to perform some basic file manipulation in the past, I downloaded and got to work seeing what I could do about the file size. In pretty quick order I saw that, due to the fact that the files were only someone speaking, I could alter the file from studio to mono and reduce the bitrate quite a bit and create a file ~1/4 of the size with non-noticeable reduction in sound quality. Once I realized this, and the impact it would have on the end user, I was hooked on trying to find a way to automate this process.</p>
<p>While it seemed as though there were a few libraries out there that should be able to accomplish the above audio file manipulation, I wasn’t able to figure them out in the time I had allotted for this task. I did find many references to an executable called <a href="https://ffmpeg.org/">FFMPEG</a>. I downloaded it and fired up Visual Studio to see if I could get it to run as a process and do the dirty work for me. After a number of iterations and A LOT of bingle-ing, I found the correct incantations. At this point, I could have left it as such and run this program daily to shrink the file sizes before uploading them to the cloud. I really wanted this process to be almost entirely automated though and eventually wanted to allow the lecturers to upload their lectures directly through the website. I decided to push my luck, take things a step further, and put this process into an Azure Function.</p>
<p>Why Azure Functions? I’ve utilized Azure Functions in the past for a number of different things and have really found them a pleasure to work with. Since the focus of this article is doing things on the cheap, lets talk about pricing. To be very honest, I don’t fully understand their pricing structure, but I do know that I’ve created functions in the past on the “consumption plan”. This is where they calculate the ‘compute’ your function uses into some measurement and then you get charged per unit of that measurement. There are quite a number of those units that you get free monthly, to the extent that I have yet to reach the point where I’m getting charged for the functions I’ve created. Azure DevOps has integrations with Azure Functions and GitHub as well. This allowed me to setup an automated build when I check-in code to GitHub which then automatically deploys the code changes, upon successful build, to the Azure Function…all for free.</p>
<p>There are also two, free tools Microsoft has produced that make this experience even better. <a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-use-emulator">Azure Storage Emulator</a> and <a href="https://azure.microsoft.com/en-us/features/storage-explorer/">Microsoft Azure Storage Explorer</a>. These two tools allow you to create an Azure Function entirely locally on your machine. The function I had envisioned was one that would listen to blob storage. Anytime a new file got dropped into the container, my function would fire, manipulate the audio file to reduce its size, add metadata to it and then upload it again into another blob storage container which would be exposed to the end-users through the website.</p>
<p>While I’m in Azure-land, I setup one other function. It was a very small function. It is an HTTP trigger function, which means that it is exposed via a URL. It was a <code class="language-plaintext highlighter-rouge">GET</code> function that takes a string and returns an audio file. If you are familiar with Azure Storage, you might wonder why I would structure things this way. If you are not familiar with Azure Storage, then the reason there would be to question this decision is that Azure Storage has different levels of exposure you can specify for your blobs. I could have just exposed all of them publicly and had the website reference those urls directly. There are a handful of reasons why I chose the route I did and they are as follows:</p>
<ol>
<li>I wanted to see every time someone requested one of the files. Application Insights is another free offering on Azure and it is integrated very nicely with Azure Functions.</li>
<li>I wanted to de-couple the front-end request from the backend response. If I directly exposed the URL, this would make future migrations more difficult as I would have to maintain those urls and their relationships to the UI. My initial implementation had the GET request string strongly resemble the Azure Blob Storage URL, but I could see as the website grows, the desire to move to something a little more dynamic than that.</li>
<li>Not all of the files that were uploaded on the backend should be exposed publicly and these settings applied to the container as a whole, not on each individual file.</li>
</ol>
<p>Once all of this was done, I felt as though I had an “MVP” back-end and wanted to do the same for the front-end.</p>
<p>As the initial thrust of this website was for this daily lecture series, I focused on creating (literally) a single-page app that could display the information about the series reasonably well and play an audio file. I started with the ‘cli’ setup. Created one component. Added some style. And…that was it. It was approximately ~500 lines of code total, half of them being css. I added another site entry into my Google Analytics account, and copied the relevant js code into the <code class="language-plaintext highlighter-rouge">index.ejs</code> file so that I would get additional insights into my users, what types of devices they are visiting the site on and where they are accessing it from around the globe. The only other, semi-interesting, decision I made at this point was to put all of the data for the lectures into a static json file in GitHub. I didn’t want to pay for a database of any kind and didn’t really want to go through the development overhead of needing to configure/code it all. In retrospect, it probably would have been slightly better to put it behind an Azure Function as well, but…I didn’t :).</p>
<p>Now it was time to launch. As mentioned above, all of the above was accomplished in ~1.5 weeks in my free time. The site was launched and started getting use. So far, the site is costing me ~40¢ a month to run. Within a few days, I got a few feature requests and I had a queue of clean-up/enhancement things I wanted to tackle for the ongoing maintainability/extension of the site. I was pretty happy with the turn around time and cost to run, but there was still work to be done.</p>
<p>Post launch there were a number of things I wanted to tackle in short-order to reduce the daily amount of work I had to maintain the site. The top two were:</p>
<ul>
<li>Automate the posting of new data to github.</li>
<li>Automate the emailing individuals to inform them when new lectures were available.</li>
</ul>
<p>As this post it getting a bit lengthy, and since there were a few other iterations I made in short order after launch, I’ll save the details for all of those for another post!</p>I recently developed a website on a volunteer basis for a non-profit organization I'm affiliated with. I wanted to do so in as cost-effective a manner as possible. This details the steps I took to get the site up and running and the associated costs incurred through those hosting decisions..NET Standard - WHAT?!?2019-11-08T00:00:00+00:002019-11-08T00:00:00+00:00https://blog.pinarydevelopment.com/c-sharp/understanding-dotnet-standard<p>I watched an entertaining <a href="https://channel9.msdn.com/Shows/Careers-Behind-the-Code/Building-Careers-with-Empathy-with-Scott-Hanselman">video</a> the other day on Channel 9. This is an interview with Scott Hanselman discussing his career over time. At the end he is asked about his #1 piece of career advice. He states: “Jon Udell told me - ‘Don’t waste your keystrokes.’”. He continues to discuss this mantra that he has applied to his professional life. If someone asks him a question and the answer is getting a bit long, he says he won’t IM or email the answer because “Email is where keystrokes go to die.”. Instead he says he will write a blog post and in doing so, “Every additional person that reads my blog post multiplies my power.”</p>
<p>As with a lot of what Mr. Hanselman says and writes about, this made a lot of sense to me. I work with a number of different developers in a variety of locations, industries and skill levels. A lot of the work is done via IM(mostly Slack) because it is easy to have a conversation that can span multiple days and enables me to participate in the discussion on my desktop or my phone. A few days after hearing the above advice I got the following question:</p>
<blockquote>
<p>Is it correct to say that .net core implements .net standard?</p>
</blockquote>
<p>To which my answer was:</p>
<blockquote>
<p>yes <br />
more accurately, a given version of .net core implements a given version of .net standard</p>
</blockquote>
<p>At first I thought that was it, but my friend continued to investigate and clarify in a chat that went on for ~300 lines over the course of ~2hrs. When we were done I thought…I should make this into a post :). So here it goes…</p>
<blockquote>
<p>Most basically what the heck is .net standard?</p>
</blockquote>
<p>There is a ton of digital ink that has been spilled on this topic. I think this goes to show the general confusion that is out there regarding .NET Standard/Framework/Core, etc. <a href="https://devblogs.microsoft.com/dotnet/introducing-net-standard/">One such post</a> on the .NET Blog simply states: “.NET Standard is a set of APIs that all .NET platforms have to implement. This unifies the .NET platforms and prevents future fragmentation.” To be clear, API stands for <a href="https://en.wikipedia.org/wiki/Application_programming_interface">Application programming interface</a>.</p>
<p>In OOP developer speak, .NET Standard is a set of <em>interfaces</em>. In fact, if you wanted to look at what is in .NET Standard v2.1 you can do so on <a href="https://raw.githubusercontent.com/dotnet/standard/master/docs/versions/netstandard2.1_ref.md">GitHub</a>. If you do so, you will see a huge file of…well…C#. There are a number of class declarations, but if you peruse through, they are all method/property signatures without any implementations.</p>
<blockquote>
<p>Ok, so what does this mean? Who is implementing these interfaces?</p>
</blockquote>
<p>While in reality, anyone could implement the interfaces if they wanted to, in actuality, this is the work being done by a variety of teams at Microsoft. A table of .NET Standard versions and their implementations can be seen on <a href="https://github.com/dotnet/standard/blob/master/docs/versions.md">GitHub</a> as well. As stated in the document on GitHub, the versions of .NET Standard are <em>“additive”</em> and <em>“immutable”</em>. Meaning once interfaces have been established, they will not be changed and higher versions of the standard will have at least what was in the previous version.</p>
<p>Now that we have the base information stated, lets proceed to some of the questions that were asked and their answers to better understand what all of this means.</p>
<blockquote>
<p>Does that mean to say that .NET Core is only using libraries specified in .NET Standard?</p>
</blockquote>
<p>No. Again, .NET Standard is an interface. .NET Core is a framework used for building applications and a version of .NET Core provides implementations for given version(s) of .NET Standard interface(s). So, if you need something in .NET Standard version X, you will have to use(at a minimum) .NET Core Y to do so, as that is the version of the framework guaranteed to have the implementation for that .NET Standard X interface.</p>
<p>I think this is where things become confusing for a lot of developers, so lets provide some concrete examples to help better illustrate this.</p>
<p>There is a very important point that should be called out at this point to aid further understanding/exploration. <strong>One version of .NET Core can implement multiple versions of .NET Standard</strong></p>
<p>Before getting specific with Standard/Framework stuff, let’s look at a simple C# example that I think will help illustrate this point. Let’s say we want to have a few classes that implement logging and we want our application to choose the actual logger class it uses at runtime based on environment. For instance, if we are developing locally, we want to put the message in the Console, and if we are in production, we want to log the message to a database. We could define an interface as such:</p>
<p><strong><em>DISCLAIMER:</em></strong> <em>What follows is code that I wouldn’t use for real, but is for explanatory purposes relating to the discussion topic. DbLogger contains ‘inline’ sql which one shouldn’t do for security reasons. Actual instantiation of classes would most likely be handled by a DI container in the real world, etc, etc.</em></p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="code"><pre><span class="k">public</span> <span class="k">interface</span> <span class="nc">ILogger</span>
<span class="p">{</span>
<span class="k">void</span> <span class="nf">Log</span><span class="p">(</span><span class="kt">string</span> <span class="n">message</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></figure>
<p>And classes as follows:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre></td><td class="code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">ConsoleLogger</span> <span class="p">:</span> <span class="n">ILogger</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">Log</span><span class="p">(</span><span class="kt">string</span> <span class="n">message</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="n">message</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">DbLogger</span> <span class="p">:</span> <span class="n">ILogger</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">Log</span><span class="p">(</span><span class="kt">string</span> <span class="n">message</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="s">"CONNECTION_STRING"</span><span class="p">))</span>
<span class="p">{</span>
<span class="n">connection</span><span class="p">.</span><span class="nf">Open</span><span class="p">();</span>
<span class="k">using</span> <span class="p">(</span><span class="n">SqlCommand</span> <span class="n">cmd</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlCommand</span><span class="p">(</span><span class="s">$"INSERT INTO Log(Message NVARCHAR(MAX)) VALUES (</span><span class="p">{</span><span class="n">message</span><span class="p">}</span><span class="s">)"</span><span class="p">))</span>
<span class="n">cmd</span><span class="p">.</span><span class="nf">ExecuteNonQuery</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></figure>
<p>Then in our application we could do something like:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
</pre></td><td class="code"><pre><span class="n">ILogger</span> <span class="n">logger</span> <span class="p">=</span> <span class="n">Environment</span><span class="p">.</span><span class="nf">GetEnvironmentVariable</span><span class="p">(</span><span class="s">"Environment"</span><span class="p">)</span> <span class="p">==</span> <span class="s">"local"</span> <span class="p">?</span> <span class="k">new</span> <span class="nf">ConsoleLogger</span><span class="p">()</span> <span class="p">:</span> <span class="k">new</span> <span class="nf">DbLogger</span><span class="p">();</span>
<span class="n">logger</span><span class="p">.</span><span class="nf">Log</span><span class="p">(</span><span class="s">"Log me a test message."</span><span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></figure>
<p>Now let me ask a question…Are <code class="language-plaintext highlighter-rouge">ConsoleLogger</code> or <code class="language-plaintext highlighter-rouge">DbLogger</code> limited to only one method or could they include methods other than the one in the interface <code class="language-plaintext highlighter-rouge">ILogger</code> as provided above?</p>
<p>The answer is that they are not limited to only that one method. An interface is a contract of sorts. If a class implements an interface, then it is ‘contractually obligated’ to provide what is stated in that interface. Both classes above do this as they both provide implementations of a method called <code class="language-plaintext highlighter-rouge">Log</code> that takes one string as a parameter and returns nothing. BUT, nothing says that <code class="language-plaintext highlighter-rouge">ConsoleLogger</code> can’t also have a <code class="language-plaintext highlighter-rouge">LogError</code> method as well. The following code is still valid.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">ConsoleLogger</span> <span class="p">:</span> <span class="n">ILogger</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">Log</span><span class="p">(</span><span class="kt">string</span> <span class="n">message</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="n">message</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">LogError</span><span class="p">(</span><span class="kt">string</span> <span class="n">message</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">Console</span><span class="p">.</span><span class="n">ForegroundColor</span> <span class="p">=</span> <span class="n">ConsoleColor</span><span class="p">.</span><span class="n">Red</span><span class="p">;</span>
<span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="n">message</span><span class="p">);</span>
<span class="n">Console</span><span class="p">.</span><span class="nf">ResetColor</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></figure>
<p>Take this understanding and now apply it to .NET Standard/Core. .NET Core 1.0 implements .NET Standard 1.0 - 1.6. What this means is that the implementations provided in .NET Core 1.0 contained more than what was defined in the .NET Standard 1.0 interfaces. As .NET Standard was growing, codified and versioned, it added more interfaces which .NET Core 1.0 already had implemented. For instance, <code class="language-plaintext highlighter-rouge">ConcurrentBag</code>(which is a thread safe collection) was added to .NET Standard 1.1, but already was implemented in .NET Core 1.0. Alternatively, .NET Framework 4.5 implemented .NET Standard 1.0 and 1.1, but not 1.2. To utilize all of the interfaces in .NET Standard 1.2, the target .NET Framework for an application would need to be 4.5.1.</p>
<blockquote>
<p>Hopefully now you are at least thinking: Ok, conceptually this is starting to make sense, but when/why do I need to care? I don’t plan on thinking through all of the method calls I plan on making in my application and then hunting through .NET Standard versions to make sure they all exist there before I start development.</p>
</blockquote>
<blockquote>
<p>Also, how does Visual Studio have an option to create a class library using .NET Standard if all it is is a set of interfaces?</p>
</blockquote>
<p>These questions really go hand-in-hand. Let’s start with the second one and work our way back to the first one. In the world of .NET, our code gets compiled to a <code class="language-plaintext highlighter-rouge">.dll</code> or a set of <code class="language-plaintext highlighter-rouge">.dll</code>s. There needs to actually be some sort of executable in order for the code in the <code class="language-plaintext highlighter-rouge">.dll</code>s to get executed on a machine though. Visual Studio provides an option to create a class library ‘using .NET Standard’ because the output of that class library on build will be a <code class="language-plaintext highlighter-rouge">.dll</code>, not an executable.</p>
<blockquote>
<p>OK…sounds like semantics?</p>
</blockquote>
<p>It’s really not though. In order for your code to build and create a <code class="language-plaintext highlighter-rouge">.dll</code>, it needs to have the definitions for the interfaces it is relying on but doesn’t need to actually have the implementations of those interfaces. Back to our C# example above, if we wanted to get this line to compile:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
</pre></td><td class="code"><pre><span class="n">ILogger</span> <span class="n">logger</span> <span class="p">=</span> <span class="n">Environment</span><span class="p">.</span><span class="nf">GetEnvironmentVariable</span><span class="p">(</span><span class="s">"Environment"</span><span class="p">)</span> <span class="p">==</span> <span class="s">"local"</span> <span class="p">?</span> <span class="k">new</span> <span class="nf">ConsoleLogger</span><span class="p">()</span> <span class="p">:</span> <span class="k">new</span> <span class="nf">DbLogger</span><span class="p">();</span>
<span class="n">logger</span><span class="p">.</span><span class="nf">Log</span><span class="p">(</span><span class="s">"Log me a test message."</span><span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></figure>
<p>We could refactor it a bit to this:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="code"><pre><span class="k">public</span> <span class="k">interface</span> <span class="nc">ILogger</span>
<span class="p">{</span>
<span class="k">void</span> <span class="nf">Log</span><span class="p">(</span><span class="kt">string</span> <span class="n">message</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">ILogger</span> <span class="n">logger</span> <span class="p">=</span> <span class="k">null</span><span class="p">;</span>
<span class="n">logger</span><span class="p">.</span><span class="nf">Log</span><span class="p">(</span><span class="s">"Log me a test message."</span><span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></figure>
<p>Now of course, this will throw an <code class="language-plaintext highlighter-rouge">Exception</code> at runtime, but the code will compile.</p>
<p>Back to our library, by selecting .NET Standard for it in Visual Studio, we are declaring that our library will only depend on methods declared in the version of .NET Standard we have selected for our library. So, if we select .NET Standard 1.0, our library code won’t be able to use <code class="language-plaintext highlighter-rouge">ConcurrentBag</code> because that wasn’t added to .NET Standard until version 1.1. This is so EVEN IN A CASE where the application executing this library is a .NET Core 1.0 application(which implements .NET Standard 1.0-1.6, meaning that it actually has an implementation for <code class="language-plaintext highlighter-rouge">ConcurrentBag</code>).</p>
<p>When/why do I need to care? The most common scenario I’ve found for when developers really need to be aware of all of this is if you are a library maintainer(think AutoMapper, Serilog, etc) or you are in an organization that is trying to migrate its applications from a version of .NET Framework to .NET Core.</p>
<p>The ‘.NET’ recommendation for deciding which .NET Standard version to use for a library is: “Pick the lowest one that has all of the interfaces required in your library.” This is great and makes a ton of sense. I have found that it can be tedious to determine what version this might be though for any given dependency.</p>
<p>If you are migrating an application, I have found that it is important to be mindful of what .NET Framework version your application is currently on, find the highest .NET Standard implementation that that version of the Framework adheres to and create libraries of ‘migrate-able’ code based on that.</p>
<blockquote>
<p>Ok, so rewind a bit. You’re saying the only reason why my library can run <code class="language-plaintext highlighter-rouge">Console.Writeline</code>(for example) is because the application running the library is using a concrete framework that actuality implements <code class="language-plaintext highlighter-rouge">Console.Writeline</code>?</p>
</blockquote>
<blockquote>
<p>yes</p>
</blockquote>
<blockquote>
<p>What is the point of having the other 2 options for a class library (.NET Core and .NET Framework)? Shouldn’t .NET Standard suffice for anything?</p>
</blockquote>
<p>Not exactly. Again, the frameworks have to implement the interfaces of .NET Standard AT A MINIMUM. But they aren’t limited to those interfaces. They can(and do) give you more above and beyond what is declared in the standard. In fact, this is something I’ve found you need to keep in mind while migrating applications from .NET Framework to .NET Core. .NET Core is built to be cross-platform. This means that it can be compiled to run on Linux, Mac or Windows(others as well). If your current application is logging events to the Windows Event Log, there won’t be a direct migration path as the ‘Windows Event Log’ doesn’t make sense on Linux or Mac. These types of dependencies will need to be isolated in .NET Framework libraries to enable the current application to function as usual while a .NET Standard version is worked on that could execute similarly in the new & old applications.</p>
<p>It is understandable why this topic can seem a little obtuse. I hope that this article was able to help clarify some of these topics!</p>What is .NET Standard? How does it relate to .NET Core and .NET Framework? Also, why should I care?The Curious Encoding Caper2019-09-11T00:00:00+00:002019-09-11T00:00:00+00:00https://blog.pinarydevelopment.com/c-sharp/curious-encoding-caper<p>I came across an interesting thing while working on a project the other day. There was a bug that was logged for the product.</p>
<p>When a customer entered some French into one of our forms(some of the words had special French symbols and accents, i.e.: Contrecœur, sécurité) and submitted the form. The information, as entered, was saved into our database. We could open that record back up in the web application and everything would display as expected. The web application had a button that allows customers to export some data to a csv file and this is where things got interesting. When clicking on the button, the csv file would download and clicking on the file would open it up by default in Excel. The above words were then displayed as: ContrecÅ“ur, sécurité respectively. An internal member of our team noted that they were able to export the same record to csv from SSMS(Sql Server Management Studio) and it would display correctly in Excel.</p>
<p>Looking into the code, the line in question looked as follows: <code class="language-plaintext highlighter-rouge">return File(new UTF8Encoding().GetBytes(sb.ToString()), "application/octet-stream", "mycsv.csv");</code>.</p>
<p>Those were the details I had to work with and as all good developers do, I started Bingling. I noticed that if I opened the csv in Notepad++, the characters would display as expected which led me to start thinking there was some issue with Excel. I searched for properly encoding csv’s for Excel and found some interesting and seemingly related posts talking about Excel’s inability to do this and exporting to csv well. This gave me false hope that I was getting close, but throughout it all, I didn’t see anything that seemed to answer the difficulty we were facing.</p>
<p>I changed search tactics a bit and found a bunch of seemingly related Stack Overflow Q&As.</p>
<ul>
<li><a href="https://stackoverflow.com/questions/393647/response-content-type-as-csv">#1</a>
<ul>
<li>I tried changing the mime-type provided to the <code class="language-plaintext highlighter-rouge">FileResult</code> to be the proper one for csv files(<code class="language-plaintext highlighter-rouge">text/csv</code>).</li>
<li>I tried utilizing ASCII encoding instead(this was really just fumbling in the dark, but I was trying things to see if I could get any differences to occur to possibly help my future guesswork).</li>
<li>I tried updating the <code class="language-plaintext highlighter-rouge">Response.Charset = "utf-8";</code>.</li>
</ul>
</li>
<li><a href="https://stackoverflow.com/questions/2014069/windows-1252-to-utf-8-encoding">#2</a>
<ul>
<li>Seeing an answer from Jon Skeet got me quite excited.</li>
<li>I tried a few different encodings such as <code class="language-plaintext highlighter-rouge">Encoding.GetEncoding(1252);</code>. Reading more about this online seemed to indicate that this is a windows specific encoding and our users aren’t limited to windows users, so I didn’t want to take this route.</li>
</ul>
</li>
<li><a href="https://stackoverflow.com/questions/3777874/write-to-csv-file-and-export-it">#3</a>
<ul>
<li>I found this <a href="https://stackoverflow.com/questions/3777874/write-to-csv-file-and-export-it#answer-28806716">answer</a>.</li>
<li>This led to a <a href="https://github.com/jitbit/CsvExport">GitHub project</a>.</li>
<li>I perused the code and stumbled across <a href="https://github.com/jitbit/CsvExport/blob/master/CsvExport.cs#L202">this line</a></li>
</ul>
</li>
</ul>
<p>After all of the above, I was able to try a few things and came up with the following change:</p>
<ul>
<li>before -> <code class="language-plaintext highlighter-rouge">return File(new UTF8Encoding().GetBytes(sb.ToString()), "application/octet-stream", "filename.csv");</code>
<ul>
<li>after -> <code class="language-plaintext highlighter-rouge">return File(Encoding.UTF8.GetPreamble().Concat(Encoding.UTF8.GetBytes(sb.ToString())).ToArray(), "text/csv", "filename.csv");</code></li>
</ul>
</li>
</ul>
<p>Once all was said and done, the fix seemed pretty straight forward and insignificant. I struggle to understand why I couldn’t find any questions/documentation relating to this as once I knew what the fix was, the method in use seems pretty well documented by <a href="https://docs.microsoft.com/en-us/dotnet/api/system.text.encoding.getpreamble?view=netframework-4.8">Microsoft</a>.</p>
<p>Basically, without this Byte Order Mark(<a href="https://en.wikipedia.org/wiki/Byte_order_mark">BOM</a>) on the file, Excel wasn’t sure what the proper encoding was for the file and was taking an incorrect guess(what it was guessing, I’m not sure :) ).</p>
<p>FWIW, if you are as curious as I am, the BOM in this instance seems to consist of three bytes: <code class="language-plaintext highlighter-rouge">239 187 191</code> OR <code class="language-plaintext highlighter-rouge">11101111 10111011 10111111</code> in binary!</p>Fix for an ASP.NET application returning a csv FileResult that was UTF-8 encoded, not displaying French accent symbols properly in Excel.Blogging on a Budget2019-08-09T00:00:00+00:002019-08-09T00:00:00+00:00https://blog.pinarydevelopment.com/blogging-on-a-budget<p>About a year ago, I set about to redesign my blog. I had used <a href="https://blog.ghost.org/">ghost</a> for the first implementation of my blog. It was a pretty nice platform, but running it on the cheap was always an issue(their hosted platform isn’t cheap). Obviously, paying for hosting on a variety of platforms is an option, but none that I found were inexpensive and given that I’m not making a penny on the site currently…</p>
<h1 id="azure">Azure</h1>
<p>Upon signing up for Azure, one is given a number of free items. One of those is 10 free webapps. I set up the first implementation on an Azure website utilizing the <a href="https://github.com/felixrieseberg/Ghost-Azure">Ghost-Azure</a> tool. This is a slick tool that sets everything up nicely for you, but I found that I didn’t understand it very well and it became clear pretty quickly that upgrading with it wasn’t going to be easy. The version of ghost I was running, quickly became out-dated and I knew eventually I would want to find something else.</p>
<p>In addition, while Azure provides some free websites when you sign up, the sites are limited. For instance, it is only free if you don’t use a custom domain. There were a number of different options I explored to get around this limitation, like using Cloudflare in front of the webapp, but either a) I never properly figured out how to set it up or b) the setup that I was going for wasn’t possible with their free offerings. Long term, that ruled it out for me. There were a few other annoyances such as setting up SSL with a custom domain and getting posts routed to properly while trying to setup a custom domain through Google Domains and having it route properly to the Azure app.</p>
<p>All of these factors, made it clear to me that I would have to look down a different path for a better free long term solution.</p>
<p>Initially I created an <a href="https://github.com/peinearydevelopment/peinearydevelopment">ASP.NET Core solution</a> for a blog. This gave me the ability to start kicking around some design ideas as well as to play around with a few proof-of-concept ideas. The thought being that if I would need to run the blog on a managed platform, the cheapest solution would be to run it on a Linux box. After completing this and looking around for a way of hosting the blog, I quickly grew tired of the exercise. There are so many solutions out there, none of which are super cheap and I found it hard to evaluate the pluses and minuses of each. I had heard of <a href="https://pages.github.com/">GitHub Pages</a> before, but never really had the time to investigate them. I figured now would be an opportune time. What I found was quite eye-opening, enjoyable and affordable.</p>
<h1 id="github-pages">GitHub Pages</h1>
<p>GitHub Pages serves static files. As stated on their homepage, that can be as easy as creating an <code class="language-plaintext highlighter-rouge">index.html</code> file in your repository(named with a certain convention, also detailed very nicely in their documentation). I was looking to do a bit more and their most frictionless way of doing so is through <a href="https://jekyllrb.com/">Jekyll</a>. Jekyll is a static site generator built with ruby. All of that mumbo-jumbo means that I could create all of my blog posts in markdown and style the whole thing with scss. The jekyll ‘engine’ will take those files and create static html files and the routing in between the files. Essentially it allows one to dynamically generate static files.</p>
<p>With this plan of action as a goal, I found I had one main issue. I don’t have ruby on my computer and didn’t want to go through all the setup steps to get it working properly. I’m sure if I was more familiar with this platform, I could just create the files, push them to the GitHub repo and have things work, but I wanted to iterate on a number of different areas of the site development and wanted to be able to do so locally. This is where Docker really came in handy.</p>
<aside>This post isn't about Docker which is good because I don't know too much about it and am exploring it more at the moment. I would just like to take a moment to detail what I did with Docker for this blog. This is to point the curious reader in the right direction if they wanted to try this out as well. I have [Docker Desktop](https://www.docker.com/products/docker-desktop) installed on my Windows 10 machine. I then created a [`docker-compose.yml`](https://github.com/PinaryDevelopment/blog/blob/master/docker-compose.yml) file at the root of my GitHub repository. From that directory, with Docker Desktop installed, I'm now able to run the command `docker-compose up` from a powershell window. That will cause the jekyll engine to create all the static files in a `_site` folder, launch a server and put the website on `http://localhost:4000`.</aside>
<p>At this point the site is completely empty, but I utilized the Jekyll docs to conform to a recommended project structure. Along the way, I also referenced a few big name projects’ repos to try to understand other possibilities and approaches to common problems.</p>
<p>Let’s walk through a few of those.</p>
<h1 id="secure-custom-domain">Secure Custom Domain</h1>
<p>As detailed in the GitHub pages documents, this was relatively easy to setup.</p>
<ul>
<li>Buy a domain. I bought my through <code class="language-plaintext highlighter-rouge">domains.google.com</code> and I believe it costs me around $12/yr.</li>
<li>Configure a DNS entry with your domain provider. <img src="/assets/images/cname_record.png" alt="Google Domains Example" /></li>
<li>Add a file called <code class="language-plaintext highlighter-rouge">CNAME</code> at the root of the repository whose only contents consist of the site domain. For me this was <code class="language-plaintext highlighter-rouge">blog.pinarydevelopment.com</code></li>
<li>Then in the <code class="language-plaintext highlighter-rouge">Settings</code> tab in GitHub, <code class="language-plaintext highlighter-rouge">Options</code> subtab, you need to add the same domain to the <code class="language-plaintext highlighter-rouge">Custom domain</code> section and click the checkbox for <code class="language-plaintext highlighter-rouge">Enforce HTTPS</code></li>
<li>The <code class="language-plaintext highlighter-rouge">Enforce HTTPS</code> isn’t available immediately. I had to check back a few times before I was actually able to check it off.</li>
</ul>
<p>And thats it. I know its a few steps, but the whole time, GitHub pages manages getting and renewing the certificates for the site to ensure it is served over HTTPS and it doesn’t cost a thing.</p>
<h1 id="sass-y-styling">Sass-y Styling</h1>
<p>Through a number of projects that I’ve worked on in the past, I’ve become comfortable working with scss files for my site’s styling needs. I like the ability to utilize a number of its functions to compose different shared stylings together. This wasn’t a big deal to do at the end of the day, but it took me a little stumbling to get there. As Jekyll is a static files generator, the actual reference in the html file to the stylesheet needs to point to a css file(this gets generated by Jekyll, so you won’t see it the checked-in source files). In my default layout, I have the following reference <code class="language-plaintext highlighter-rouge"><link rel="stylesheet" href="/main.css" /></code>. The <code class="language-plaintext highlighter-rouge">_config.yml</code> file specifies the sass directory, but the main entry point for the sass styles isn’t there. In order for this to work, I had to put a <code class="language-plaintext highlighter-rouge">main.scss</code> file in the root of project. As can be <a href="https://github.com/PinaryDevelopment/blog/blob/master/main.scss">seen also</a>, it is a little strange. It references the <code class="language-plaintext highlighter-rouge">site.scss</code> file that’s in the sass directory as if they are adjacent to each other. In addition it needs to have the special <code class="language-plaintext highlighter-rouge">---</code> enclosed <a href="https://jekyllrb.com/docs/front-matter/">‘front matter’</a> header.</p>
<h1 id="limitations">Limitations</h1>
<p>Just to be clear though, not all is as rosy. The above was relatively easy to accomplish, smooth to setup and affordable to maintain. The fact that it is relying on a static site generator inherently introduces some limitations. Two big areas that come to mind are giving the ability for people who visit your site to leave comments on posts and the ability to search across the site for finding posts of interest. There are a few different potential approaches to enable these pieces of functionality in the site though.</p>
<h3 id="comments">Comments</h3>
<p>There are a few plugins/extensions that have been written to accomplish the above. <a href="https://disqus.com/">Disqus</a> is a service that can be signed up for and then with the addition of a script tag on each page, your site magically has comments. There are many pluses to this approach. It is easy to setup, its free and handles all the storage and logic around infinitely nested comments/replies, etc. Once a user signs up with it as well, they are able to track, manage all of the activity related to their comments across the web in one place. The downsides are that it is a bit clunky/slow to load and not straightforward to skin inline with your brand.</p>
<p>Some others that I found were: <a href="https://github.com/wireddown/ghpages-ghcomments">GitHub Comments</a> and <a href="https://staticman.net/">StaticMan</a>. I tried to setup StaticMan, but ran into many issues to the point that I gave up and moved on. Another option that I explored is to create my own <a href="https://github.com/PinaryDevelopment/GitHubApp.Commentary">GitHub App</a> that would, through the help of an Azure Function, create a PR to my repository anytime someone wanted to comment on a post. This would provide me the ability to screen the comments before they got added to any post and would provide me a bit more control over the comments section itself. The downside here is that it is a dev effort that I haven’t had the ability to complete to date :(.</p>
<h3 id="search">Search</h3>
<p>Another nice to have on most sites these days is search. This becomes even more helpful the more prolific one’s writing becomes. Again, this doesn’t come out of the box and requires a dev effort to implement. There are a few
<a href="http://www.jekyll-plugins.com/plugins?utf8=%E2%9C%93&query=search">plugins</a> that could help with the effort, but I haven’t had a chance to test any of them out.</p>
<h1 id="additional-resources">Additional Resources</h1>
<p>There were a number of other things that I tried to do with the site that took some serious fiddling. I found a few resources along the way that were helpful though. Jekyll is a ruby executable, so there were occasions that I found myself needing to do something in Ruby(that I have no experience with). For instance, I needed to utilize Ruby to format some dates and found <a href="https://hackhands.com/format-datetime-ruby/">this very useful guide</a>. The markup syntax that Jekyll utilizes is called liquid. The most useful reference I could find on this came from <a href="https://shopify.github.io/liquid/">Shopify</a>. As mentioned above, I referenced some other popular sites out there that are utilizing GitHub Pages as well for troubleshooting and patterns/practices. The one I referenced the most was <a href="https://github.com/twbs/bootstrap">Bootstrap</a>. Just going to the <a href="https://pages.github.com/">GitHub Pages</a> main page and looking at the ‘carousel’ though, provides many more example sites to reference.</p>About a year ago, I set about to redesign my blog. This is my journey through trying to identify a free option for my blog. I explored Ghost, Azure WebApps and GitHub Pages. The post details the pros and cons I encountered along the way.Byte-sized C# Programming: Classes2019-01-13T00:00:00+00:002019-01-13T00:00:00+00:00https://blog.pinarydevelopment.com/byte-sized/c-sharp/classes<aside>Getting started with programming can prove to be very overwhelming as there is so much to learn. The byte-sized series is intended to break topics into small, digestible, easy-to-understand chunks.</aside>
<blockquote>
<p>As stated in the end of the previous post, we are eager to get programming. There are two more main concepts that need to be discussed before we can create our first program. The main focus of this article will be classes. The end of the article will briefly discuss namespaces and point out a few resources to show how to get started writing your first program.</p>
</blockquote>
<p>An easy way to start thinking about classes would be to envision them as digital representations of real world objects. Every time we create a new ‘instance’ of the class, it will contain all the pieces we have defined in our class. To continue with the example we’ve been using thus far in the series…</p>
<blockquote>
<p>Let’s assume the CEO is so pleased with the progress of this rewards program that he wanted to print off membership cards for all of his staff members. To help facilitate the further automation of this system, we are going to want the program to be able to store information about this card and utilize this information in the program.</p>
</blockquote>
<p>When creating a class, a good place to start, is to think of the characteristics that the item to be represented possess. There are many characteristics that could come to mind like card size, the material the card is made of, color of the card, etc. When creating a class though, one should try to think of the characteristics of the card that will make a difference to the program. When creating a user interface, the above characteristics might define how we represent the card on the screen. When starting with programming, the user interface adds a whole level of complexity that could easily detract from the core concepts that we are trying to focus on.</p>
<p>For the moment then, let’s think of other characteristics of the card that would be more meaningful for the program we are creating. The card really represents a member of the program. So far, we want to track a few data points for each program member. The rewards program we’ve discussed needs to know the number of miles the member has traveled this year and the number of months they’ve been employed in this organization. As a person travels, we know that they will need to add miles to their account and at the end of the year, we know we will want to get a monthly average of their miles traveled.</p>
<blockquote>
<p>Thanks for the overview, but I already know what a rewards program is. What is this ‘class’ business and how do they synthesize?</p>
</blockquote>
<p>Patience young grasshopper. <em>“Be not afraid of growing slowly, be afraid only of standing still.”</em></p>
<p>All joking aside, I’ve found that those who are better at thinking about the things they want to represent in an abstract manner, as we did above, have a much easier time creating code and communicating intent through their code. Variables are a necessary part of any program. Understanding what a method is and what it does is also critical for being able to write code(if for no other reason than you want to be able to rely on the genius of others and not write every piece of functionality yourself).</p>
<p>To create an executable(a runnable program) you technically need one class and one namespace. If one wanted to, they could always use the default for both of these, cram all of their code into the defaults and not have to understand them that well. Classes and namespaces are a very powerful tool for communication in code though and practically speaking are the only real way programs are written. That being the case, it makes sense to discuss the thought process behind the creation of these items to shape the discussion.</p>
<blockquote>
<p>Zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz, <em>drool</em> <em>drool</em>, <em>Bueller</em> <em>Bueller</em></p>
</blockquote>
<p>Ok, wake up, wake up. Let’s dive in. Here is how our first class will start off looking:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
</pre></td><td class="code"><pre><span class="k">class</span> <span class="nc">RewardsMember</span>
<span class="p">{</span>
<span class="kt">string</span> <span class="n">Id</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="kt">string</span> <span class="n">Name</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="kt">int</span> <span class="n">MilesTraveledYearToDate</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="kt">int</span> <span class="n">MonthsWorkedYearToDate</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="nf">RewardsMember</span><span class="p">()</span>
<span class="p">{</span>
<span class="n">Id</span> <span class="p">=</span> <span class="n">Guid</span><span class="p">.</span><span class="nf">NewGuid</span><span class="p">().</span><span class="nf">ToString</span><span class="p">();</span>
<span class="p">}</span>
<span class="k">void</span> <span class="nf">UpdateMilesTraveled</span><span class="p">(</span><span class="kt">int</span> <span class="n">milesToAdd</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">MilesTraveledYearToDate</span> <span class="p">=</span> <span class="n">MilesTraveledYearToDate</span> <span class="p">+</span> <span class="n">milesToAdd</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">decimal</span> <span class="nf">GetEmployeesMonthlyAverage</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">return</span> <span class="n">MilesTraveledYearToDate</span> <span class="p">/</span> <span class="n">MonthsWorkedYearToDate</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></figure>
<blockquote>
<p>Woah, overload…</p>
</blockquote>
<p>Yes, it can look a bit overwhelming at first glance, but I think if you don’t get lost in the code and read the words that are there, you will start to see the items we outlined above.</p>
<p>Let’s break it down step by step(or byte by byte ;) ).</p>
<p>To start off, there is the keyword <code class="language-plaintext highlighter-rouge">class</code>. This tells the compiler that what comes next is the characteristics that the item to be represented by this class possess. This is followed by the name we chose for our class <code class="language-plaintext highlighter-rouge">RewardsMember</code> because we want each instance of our class to represent one member in the rewards program. The first and last <code class="language-plaintext highlighter-rouge">{}</code> provide the syntactical bookends for the block of code that encases the characteristics for our rewards member class.</p>
<p>Within those curly braces are three distinct areas.</p>
<p>The first four lines contain the class’ properties.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="code"><pre><span class="kt">string</span> <span class="n">Id</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>
<span class="kt">string</span> <span class="n">Name</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>
<span class="kt">int</span> <span class="n">MilesTraveledYearToDate</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>
<span class="kt">int</span> <span class="n">MonthsWorkedYearToDate</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></figure>
<p>The easiest way to look at a property is a class instance’s variable. <em>This isn’t 100% accurate as there is more you can do with them than variables, but let’s start by envisioning them as variables.</em> So what exactly does this mean? Every new <code class="language-plaintext highlighter-rouge">RewardsMember</code> we create will have 4 <em>variables</em> inside of it. One representing the unique identifier assigned to this member(Id) which is of type <code class="language-plaintext highlighter-rouge">string</code>. One representing the reward member’s name, also of type <code class="language-plaintext highlighter-rouge">string</code>. The last two are of type <code class="language-plaintext highlighter-rouge">int</code> and will represent the reward member’s year-to-date miles traveled and months worked respectively.</p>
<p>The next four lines are called an instance constructor.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="code"><pre><span class="nf">RewardsMember</span><span class="p">()</span>
<span class="p">{</span>
<span class="n">Id</span> <span class="p">=</span> <span class="n">Guid</span><span class="p">.</span><span class="nf">NewGuid</span><span class="p">().</span><span class="nf">ToString</span><span class="p">();</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></figure>
<p>When creating a new <code class="language-plaintext highlighter-rouge">RewardsMember</code> in our program, this is the method that will be called. If there is anything that needs to happen to setup any of the properties in the class with initial values, those steps should be placed here. Here(with a little bit of hand-waving), I’m creating a unique value to assign to the rewards member when they are created. This would be likened to the random group of numbers that appear on a credit card. It is meaningless to the holder, but that is how the cardholder and their transactions are identified in the billing system. Here, that is how our reward’s member can be identified in our system. One quick note, while I’ve referred to it as a method, you will notice two distinct qualities about it. It has the same name as the class and it doesn’t define a return value(actually the return value is of type <code class="language-plaintext highlighter-rouge">RewardsMember</code>). While we won’t go into more detail now, know that these properties hold true of all ‘instance constructors’.</p>
<p>Finally we gave the class two methods.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="code"><pre><span class="k">void</span> <span class="nf">UpdateMilesTraveled</span><span class="p">(</span><span class="kt">int</span> <span class="n">milesToAdd</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">MilesTraveledYearToDate</span> <span class="p">=</span> <span class="n">MilesTraveledYearToDate</span> <span class="p">+</span> <span class="n">milesToAdd</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">decimal</span> <span class="nf">GetEmployeesMonthlyAverage</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">return</span> <span class="n">MilesTraveledYearToDate</span> <span class="p">/</span> <span class="n">MonthsWorkedYearToDate</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></figure>
<p>With this, every instance of the <code class="language-plaintext highlighter-rouge">RewardsMember</code> class will have the ability to update its <em>variable</em> that stores how many miles the member has traveled this year and another that will be able to return to the program the monthly average miles traveled for the rewards member.</p>
<blockquote>
<p>Double Woah. What you just wrote feels like it should make sense, but also feels full of jargon. One thing you repeated a bunch was an ‘instance’ of a class. What does this mean and how do we create one?</p>
</blockquote>
<p>Both are excellent questions and I think walking through the answers to them will help elucidate the rest of the above jargon. One further point about classes. In addition to all of the above, by creating a class definition, we are also creating a new type in C#.</p>
<blockquote>
<p>Huh?</p>
</blockquote>
<p>Ok, let’s start looking at how to use this class now. To utilize this class after it has been defined as above would be to create a new ‘instance’ of this class. Here is how we would do that.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
</pre></td><td class="code"><pre><span class="n">RewardsMember</span> <span class="n">johnDoe</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">RewardsMember</span><span class="p">();</span>
</pre></td></tr></tbody></table></code></pre></figure>
<p>We declare a variable of type <code class="language-plaintext highlighter-rouge">RewardsMember</code>, call it <code class="language-plaintext highlighter-rouge">johnDoe</code>, create a <code class="language-plaintext highlighter-rouge">new</code> instance of our <code class="language-plaintext highlighter-rouge">RewardsMember</code> class and assign it to that variable.</p>
<blockquote>
<p>Great…I think. We now have an ‘instance’ of our class, but what can we do with it?</p>
</blockquote>
<p>Well, as was stated before, with each ‘instance’ of our class we get the ‘variables’ we defined in it and their methods. So now if we wanted to access the Id for John Doe, we would do that as follows: <code class="language-plaintext highlighter-rouge">string johnDoesId = johnDoe.Id;</code>. If we wanted to record the miles traveled on a trip for John Doe, that would be done as follows: <code class="language-plaintext highlighter-rouge">johnDoe.UpdateMilesTraveled(859);</code>.</p>
<p>If we wanted to create a reward member for Jane Doe? Yup, you guessed it, we would do <code class="language-plaintext highlighter-rouge">RewardsMember janeDoe = new RewardsMember();</code>. If we wanted to see how many miles she’s traveled thus far, we would do <code class="language-plaintext highlighter-rouge">int janeDoesYearToDateMilesTraveled = janeDoe.MilesTraveledYearToDate;</code>.</p>
<p>What value do you think <code class="language-plaintext highlighter-rouge">janeDoesYearToDateMilesTraveled</code> would hold now? If you guessed <code class="language-plaintext highlighter-rouge">859</code>, you wouldn’t be correct, but is a common source of confusion when getting started. Since the <code class="language-plaintext highlighter-rouge">RewardsMember</code> class is a set of characteristics and each ‘instance’ of that class has its own set of ‘variables’ and methods, <code class="language-plaintext highlighter-rouge">janeDoesYearToDateMilesTraveled</code> would hold the value <code class="language-plaintext highlighter-rouge">0</code> currently. It wouldn’t hold <code class="language-plaintext highlighter-rouge">859</code> as that value was stored in <code class="language-plaintext highlighter-rouge">johnDoe</code>’s <code class="language-plaintext highlighter-rouge">MilesTraveledYearToDate</code> ‘variable’. <em>The <code class="language-plaintext highlighter-rouge">0</code> value is the default value for an <code class="language-plaintext highlighter-rouge">int</code>, not a topic for this post, but just an FYI as to where that value came from.</em></p>
<p>Great!</p>
<blockquote>
<p>I think I’m starting to grasp classes, you mentioned that you would talk about ‘namespaces’ as well though. What are they and why do I need to care?</p>
</blockquote>
<p>Yeah, you’re right. I think this is a good start for understanding classes. There is so much more to talk about, but it will have to wait for later as this post is getting a bit long. On to namespaces.</p>
<p>I mentioned before that, “To create an executable(a runnable program) you technically need one class and one namespace. If one wanted to, they could always use the default for both of these…”. Let’s take a look at what that looks like now, give a brief explanation, point out some tools to utilize to get started and send you on your way until next time.</p>
<p>If you were to create a new ‘Console App’ project with one of the tools that will be discussed soon, you will get a few files, but the main one will look as follows.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="code"><pre><span class="k">using</span> <span class="nn">System</span><span class="p">;</span>
<span class="k">namespace</span> <span class="nn">ConsoleApp1</span>
<span class="p">{</span>
<span class="k">class</span> <span class="nc">Program</span>
<span class="p">{</span>
<span class="k">static</span> <span class="k">void</span> <span class="nf">Main</span><span class="p">(</span><span class="kt">string</span><span class="p">[]</span> <span class="n">args</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">"Hello World!"</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></figure>
<p>There are a few things in here that we haven’t discussed yet. For the sake of brevity, I’m going to skip them and come back to them another time. Most of it should look familiar though. We have a <code class="language-plaintext highlighter-rouge">Program</code> class and a method called <code class="language-plaintext highlighter-rouge">Main</code>. In C# land, when any program is started, the method named <code class="language-plaintext highlighter-rouge">Main</code> will be the first method invoked, kicking off the program. Now, methods and classes are familiar, but what is the first line <code class="language-plaintext highlighter-rouge">namespace ConsoleApp1</code>? It might be a little hard to imagine now, but as your code grows in size and complexity, it is very possible you will want to create two classes with the same name or a class with a name that is used in a common external library. A namespace creates a segregation of code that can allow this.</p>
<p>I know this is a little abstract, I’ll try to explain a little more and then it will just have to be taken on faith until we go further down the coding rabbit hole. Let’s say we created our <code class="language-plaintext highlighter-rouge">RewardsMember</code> class in the <code class="language-plaintext highlighter-rouge">ConsoleApp1</code> namespace as follows:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="code"><pre><span class="k">namespace</span> <span class="nn">ConsoleApp1</span>
<span class="p">{</span>
<span class="k">class</span> <span class="nc">RewardsMember</span>
<span class="p">{</span>
<span class="p">...</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></figure>
<p>If we wanted to create our two members in the program above instead of the <code class="language-plaintext highlighter-rouge">Console.WriteLine</code> bit, we could do:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="code"><pre><span class="k">namespace</span> <span class="nn">ConsoleApp1</span>
<span class="p">{</span>
<span class="k">class</span> <span class="nc">Program</span>
<span class="p">{</span>
<span class="k">static</span> <span class="k">void</span> <span class="nf">Main</span><span class="p">(</span><span class="kt">string</span><span class="p">[]</span> <span class="n">args</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">RewardsMember</span> <span class="n">johnDoe</span> <span class="p">=</span> <span class="k">new</span> <span class="n">ConsoleApp1</span><span class="p">.</span><span class="nf">RewardsMember</span><span class="p">();</span>
<span class="n">RewardsMember</span> <span class="n">janeDoe</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">RewardsMember</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></figure>
<p><code class="language-plaintext highlighter-rouge">ConsoleApp1.RewardsMember()</code> is the ‘fully qualified way of referring to our class. In this scenario, <code class="language-plaintext highlighter-rouge">RewardsMember()</code> would be the more common way to utilize the class though. Since both <code class="language-plaintext highlighter-rouge">Program</code> and <code class="language-plaintext highlighter-rouge">RewardsMember</code> classes are in the same namespace, you don’t have to fully qualify it for the program to work.</p>
<blockquote>
<p>Maybe I understand what you are saying, but if so, does that mean that in the default program, <code class="language-plaintext highlighter-rouge">WriteLine</code> is in the <code class="language-plaintext highlighter-rouge">Console</code> namespace?</p>
</blockquote>
<p>Excellent observation! The answer is no, but I see why you would say that. Honestly, the answer to your question should really be the topic of another post. For now though, if you want to use it in your program, you do have to fully qualify it as it is in a different namespace. The way you would do that would be to call it as follows <code class="language-plaintext highlighter-rouge">System.Console.WriteLine("Hello World!");</code>. A topic for another time will be how the program above is able to call it not fully qualified. The answer lies in the <code class="language-plaintext highlighter-rouge">using System;</code> statement, but will have to wait for another time.</p>
<blockquote>
<p>Wow, that was a lot. To be honest, I’m a little overwhelmed at the moment.</p>
</blockquote>
<p>Don’t fret. That is very normal. As you continue to progress in your education and employment, you will find that there is so much to know that no one knows it all. The goal is to be continually growing and building that knowledge base to allow you to continue tackling bigger and harder ‘automation’ problems.</p>
<p>As mentioned previously, there are a number of tools out there to help with writing C# code. The easiest place to get started is provided by <a href="https://docs.microsoft.com/en-us/dotnet/core/get-started">Microsoft</a>. In that document, they list tools, with links on how to get them installed, for every operating system. Take a look, get one installed and be ready to start writing your first program in the next post.</p>
<h2 id="until-next-time"><strong>Until next time!</strong></h2>C# topics: What is a class? How do I define a class? How do I instantiate a class?Byte-sized C# Programming: Methods2018-11-27T00:00:00+00:002018-11-27T00:00:00+00:00https://blog.pinarydevelopment.com/byte-sized/c-sharp/methods<aside>Getting started with programming can prove to be very overwhelming as there is so much to learn. The byte-sized series is intended to break topics into small, digestible, easy-to-understand chunks.</aside>
<blockquote>
<p>Let’s continue the example project from the previous post. Towards the end we created a variable <code class="language-plaintext highlighter-rouge">employeesMonthlyAverage</code> that was meant to store the monthly average value of how many miles an employee traveled over the last year. We discussed how we would assign a value to that variable, but no where did we mention where that value came from. So…</p>
</blockquote>
<p>At a high level, methods can be likened to the steps of an assembly line. I’ve been on a number of factory tours and in them have seen a number of assembly lines. Let’s think about an assembly line at a brewery. At the beginning of the line, a stack of bottles are provided to the line as well as a beverage, some labels and some caps. There are a number of steps it passes through on the line. The bottle has to be rinsed. The bottle is filled with the liquid. The label is glued on. The cap is stamped on. It goes through the line, until it reaches the end where the case of beer emerges. The assembly line doesn’t care if the bottles are green, brown or clear. It doesn’t matter if the beverage is a lager, stout or a soda. It performs the same steps in the same order again and again to produce the case of filled bottles.</p>
<p>A method allows a developer to create an ordered set of instructions for a computer to run. Similar to the assembly line’s instructions, the method’s instructions will perform the same steps in the same order every time the method is run. At the end of the day, the whole point of programming is to create something that will allow a computer to do certain tasks so that a person doesn’t have to do it. A method is one of the core building blocks enabling that.</p>
<blockquote>
<p>This sounds exciting! How do I get started?</p>
</blockquote>
<p>The first order of business is to know how to define a method. One <a href="https://www.bing.com/search?q=define+define#b_results">definition for the word define</a> is: “mark out the boundary or limits of”. That seems to be a pretty accurate definition for what it means to define a method. In order to define a method, we need to answer(at a minimum) these three questions:</p>
<ol>
<li>What external information needs to be given to the method in order for it to run its set of instructions? This can be likened to the raw materials provided to the assembly line at the beginning of the line.</li>
<li>What name do we want to use to refer to this method?</li>
<li>What type of result is returned from the method? This can be likened to the case that emerged from the end of the assembly line.</li>
</ol>
<p>In answering these questions, we can understand the boundaries and/or limits of our method.</p>
<blockquote>
<p>Uh, I think this makes sense, but how do we accomplish this in practice?</p>
</blockquote>
<p>Great question! Let’s look at the question we started with. Where does the value for <code class="language-plaintext highlighter-rouge">employeesMonthlyAverage</code> come from in our program? Currently, the user has to make the calculation and assign that value to the variable. This is something a computer should be doing so let’s see how we would make a method for this instead.</p>
<p>First, let’s answer the questions presented above.</p>
<ol>
<li>In order for the method to calculate the monthly average for a given employee it needs to be given the total number of miles an employee has traveled and the total number of months they have worked this year.</li>
<li>This is mostly arbitrary though it does need to follow a few rules which, for all intents and purposes, are the same as those for variables. To recap(not an exhaustive list), the name can’t have a space, apostrophe or a dash in it. In this instance, <code class="language-plaintext highlighter-rouge">CalculateEmployeesMonthlyAverage</code> seems appropriate, so that’s what we’ll use.</li>
<li>The whole point of the method is to calculate the average, so that is what it will return. If you look at the previous post, we determined that the average should be of type <code class="language-plaintext highlighter-rouge">decimal</code>, so that is the type of the returned result.</li>
</ol>
<blockquote>
<p>Great, but all of this was the preparation, right? How do we actually program our function?</p>
</blockquote>
<p><em>As a word of warning, while we’ve discussed the problem above in the order I generally tend to think about problems, from start to finish, the definition of a function is done in reverse.</em></p>
<p>Our function would be defined as follows:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
</pre></td><td class="code"><pre><span class="kt">decimal</span> <span class="nf">CalculateEmployeesMonthlyAverage</span><span class="p">(</span><span class="kt">int</span> <span class="n">employeesMileage</span><span class="p">,</span> <span class="kt">int</span> <span class="n">monthsEmployed</span><span class="p">)</span> <span class="p">{}</span>
</pre></td></tr></tbody></table></code></pre></figure>
<p>The <code class="language-plaintext highlighter-rouge">decimal</code> at the beginning is stating that a decimal value will be returned from the method. It is similar to saying a case of filled bottles will be returned from the assembly line. After that you see the name we decided on above. Ignoring the <code class="language-plaintext highlighter-rouge">(</code>, <code class="language-plaintext highlighter-rouge">)</code>, <code class="language-plaintext highlighter-rouge">{</code> and <code class="language-plaintext highlighter-rouge">}</code> for now, we can see that the other two items presented here are the ones we stated above were “external information to be given to the method in order for it to run its set of instructions”. In order for the method to compute the average it needs to be given the employee’s total mileage for the given year and the number of months they were employed during the year. Just like the assembly line needs to be given bottles, a beverage, labels and caps in order to produce the case.</p>
<blockquote>
<p>Thanks for the explanation. This is starting to make sense, but what are the other symbols and what do they do?</p>
</blockquote>
<p>That is a great question and is something that definitely takes some getting used to. Just as there are rules about names given in our program, there are other specifications that need to be met for a given program to be valid. These specifications are called syntax. In our discussion of variables, we glossed over the fact that every line we wrote had to end with <code class="language-plaintext highlighter-rouge">;</code>. This is ‘syntax’ that defines the end of a statement, without which our program would be invalid.</p>
<p>Likewise, <code class="language-plaintext highlighter-rouge">(</code>, <code class="language-plaintext highlighter-rouge">)</code>, <code class="language-plaintext highlighter-rouge">{</code> and <code class="language-plaintext highlighter-rouge">}</code> are symbols used to signify certain things in our code. In the example of our method so far, the parentheses perform two functions.</p>
<ol>
<li>It declares the function’s external boundary, as we have discussed, where it advertises what information it needs to perform it’s function and what type each piece of information must be. This will make more sense when we discuss how to use the method in our code.</li>
<li>In addition, it is declaring variables available to the function as we will demonstrate shortly.</li>
</ol>
<p>Brackets group together the set of instructions the method will run.</p>
<blockquote>
<p>I’m going to be honest. Some of this makes sense, but my eyes are starting to glaze a bit. Can we get back to the example?</p>
</blockquote>
<p>Sure, we’ll throw down some more code with a bit of explanation and see if it helps clarify everything. First let’s complete our example method by ‘implementing’ it. That means, let’s add the instructions to it.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="code"><pre><span class="kt">decimal</span> <span class="nf">CalculateEmployeesMonthlyAverage</span><span class="p">(</span><span class="kt">int</span> <span class="n">employeesMileage</span><span class="p">,</span> <span class="kt">int</span> <span class="n">monthsEmployed</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">return</span> <span class="n">employeesMileage</span> <span class="p">/</span> <span class="n">monthsEmployed</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></figure>
<p><em>(Technically speaking, the code above won’t do what we expect it to. It is fine for now though to discuss method syntax. We can understand the technicalities later and fix it then.)</em></p>
<p>Hopefully the code is pretty readable as is. Just to elucidate it a bit though. <code class="language-plaintext highlighter-rouge">return</code> is another piece of syntax. It is a “reserved keyword”. That means a couple of things in C# land. It is given special meaning and it can’t be used as a name. <code class="language-plaintext highlighter-rouge">return</code>’s special meaning is that it is used to signify an explicit end to a method. In this case, it is also used to signify what value is going to be returned from the method, namely the value that is the result of dividing <code class="language-plaintext highlighter-rouge">employeesMileage</code> by <code class="language-plaintext highlighter-rouge">monthsEmployed</code>. Hopefully one can see the resemblance to the assembly line as well. The method is stating: “Give me an employee’s mileage and month’s employed and I will give you back the employee’s monthly average.”.</p>
<blockquote>
<p>OK, very nice. I still don’t know how to use the method though. It seems like we have the pieces in place, but how do I actually get it to calculate an average for me?</p>
</blockquote>
<p>The way to ‘invoke’ our method is as follows: <code class="language-plaintext highlighter-rouge">decimal employeesMonthlyAverage = CalculateEmployeesMonthlyAverage(15013, 6);</code>. This says, run the <code class="language-plaintext highlighter-rouge">CalculateEmployeesMonthlyAverage</code> code provided that the value <code class="language-plaintext highlighter-rouge">15013</code> is the employee’s mileage for the year and <code class="language-plaintext highlighter-rouge">6</code> is the number of months they worked this year. Store the value that gets returned from that method into the space reserved by the variable <code class="language-plaintext highlighter-rouge">employeesMonthlyAverage</code>. The code is calling the method with ‘hard-coded’ values as it is passing <code class="language-plaintext highlighter-rouge">15013</code> and <code class="language-plaintext highlighter-rouge">6</code> into the method as would be done in a calculator. The method can also accept variables assuming that their types match those of the method declaration.</p>
<p>To demonstrate, our code above could also look as follows:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="code"><pre><span class="kt">int</span> <span class="n">employeesMileage</span> <span class="p">=</span> <span class="m">15013</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">monthsEmployed</span> <span class="p">=</span> <span class="m">6</span><span class="p">;</span>
<span class="kt">decimal</span> <span class="n">employeesMonthlyAverage</span> <span class="p">=</span> <span class="nf">CalculateEmployeesMonthlyAverage</span><span class="p">(</span><span class="n">employeesMileage</span><span class="p">,</span> <span class="n">monthsEmployed</span><span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></figure>
<p><em>The values passed to the method are assigned to the variables of the method in order, so don’t make a mistake and assume that the names of the variables are what is used. Calling the method like: <code class="language-plaintext highlighter-rouge">decimal employeesMonthlyAverage = CalculateEmployeesMonthlyAverage(monthsEmployed, employeesMileage);</code> will produce an entirely different result as it will perform the calculation 6/15013 instead of 15013/6.</em></p>
<p>Now we know where our average value comes from and have explored another of the core building blocks of software development.</p>
<h2 id="once-again-nice-work"><strong>Once again, Nice Work!!!</strong></h2>
<p><em>As an eager-to-get-started-developer, while following along, you might have opened up Notepad or Word and typed in the code we have discussed hoping to create your first program. If so, you would have been pretty disappointed. What comes next? How is this supposed to run on the computer?</em></p>
<p><em>Those are all valid questions and the real answer is that you need more information before you can start to create a real program. At the end of the next article, we should be able to actually create our first full program.</em></p>
<p><strong><em>Stay tuned.</em></strong></p>C# topics: What is a method? How do I program with methods? What does it mean to pass and return values from a method?