tag:blogger.com,1999:blog-32565411136129064672024-03-18T11:46:58.098+02:00Alberto on code lifeMy take on my coding life as I experience it through the years. Opinions are my ownUnknownnoreply@blogger.comBlogger28125tag:blogger.com,1999:blog-3256541113612906467.post-22319652812318764102020-09-29T08:49:00.004+03:002020-09-29T09:16:21.517+03:00NUnit Console Runner and NLog extension logging for your tests<p>Have you experienced the frustration of tests running perfectly well on your local machine and then failing in CI? This all too familiar "It worked on my machine" comes to mind. You set off to investigate and after a while you realize you are too far into the rabbit hole between code and logs in <a href="https://www.elastic.co/kibana" target="_blank">Kibana</a> and this investigation is getting you nowhere. Wouldn't it be nice if you could hijack the logger and print the logs in the test runner's console? <i>TL;DR <a href="https://nlog-project.org/" target="_blank">NLog</a> can be extended easily and <a href="https://nunit.org/" target="_blank">NUnit</a> Console Runner does not play well with simple console logs.</i> </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQf7T0XlRNZXqboh0Rd3inTTLbAl6XyOpCUv6s0R4Ey7n9zsiSBstAllGZFYKybe-1260UlvWRBwdMPfydpXfP_837_5G9tqoBfqaAoCFV7WHGPVbVUYQsrf1-d8mR3QuMOUVHvv9BeKo/s640/pexels-kaboompics-com-6089.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="426" data-original-width="640" height="426" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQf7T0XlRNZXqboh0Rd3inTTLbAl6XyOpCUv6s0R4Ey7n9zsiSBstAllGZFYKybe-1260UlvWRBwdMPfydpXfP_837_5G9tqoBfqaAoCFV7WHGPVbVUYQsrf1-d8mR3QuMOUVHvv9BeKo/w640-h426/pexels-kaboompics-com-6089.jpg" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;"><span face="-apple-system, BlinkMacSystemFont, "segoe ui", roboto, oxygen, cantarell, "helvetica neue", ubuntu, sans-serif" style="background-color: #e8e8e8; color: #1a1a1a; font-size: 16px; text-align: start;">Photo by </span><span face="-apple-system, BlinkMacSystemFont, "segoe ui", roboto, oxygen, cantarell, "helvetica neue", ubuntu, sans-serif" style="background-color: #e8e8e8; box-sizing: border-box; color: #1a1a1a; font-size: 16px; font-weight: 600; margin-bottom: 0px; margin-top: 0px; text-align: start;"><a href="https://www.pexels.com/@kaboompics?utm_content=attributionCopyText&utm_medium=referral&utm_source=pexels" style="box-sizing: border-box; margin-bottom: 0px; margin-top: 0px; text-decoration-line: none;">Kaboompics .com</a></span><span face="-apple-system, BlinkMacSystemFont, "segoe ui", roboto, oxygen, cantarell, "helvetica neue", ubuntu, sans-serif" style="background-color: #e8e8e8; color: #1a1a1a; font-size: 16px; text-align: start;"> from </span><span face="-apple-system, BlinkMacSystemFont, "segoe ui", roboto, oxygen, cantarell, "helvetica neue", ubuntu, sans-serif" style="background-color: #e8e8e8; box-sizing: border-box; color: #1a1a1a; font-size: 16px; font-weight: 600; margin-bottom: 0px; margin-top: 0px; text-align: start;"><a href="https://www.pexels.com/photo/wood-ii-6089/?utm_content=attributionCopyText&utm_medium=referral&utm_source=pexels" style="box-sizing: border-box; margin-bottom: 0px; margin-top: 0px; text-decoration-line: none;">Pexels</a></span></td></tr></tbody></table><br /><h2 style="text-align: left;">Enter Console logging</h2><div>In .Net in general it is not advisable to log to console in a multi-threaded environment, because the console is not thread safe. While logging simple strings may not cause any problems logging strings with interpolated variables may very well be sub optimal to say the least. Should you use any such debugging technique you are better off with a thread safe file logging framework. </div><div><br /></div><div>NUnit console runner in that respect is no different. It executes tests in batch and produces results in its own colorful console. In fact, there is also a big chance you will see any regular <span style="font-family: Share Tech Mono;">Console.WriteLine </span><span style="font-family: inherit;">messages when you run it on your local machine. </span></div><div><span style="font-family: inherit;"><br /></span></div><div><span style="font-family: inherit;">Things however get weird when you are trying to see these logs in your CI. We are using </span><a href="https://www.jetbrains.com/teamcity/" style="font-family: inherit;" target="_blank">Teamcity</a><span style="font-family: inherit;"> at work and the logs are scarce. Everything not assertion or exception related is just </span>filtered<span style="font-family: inherit;"> out. This coincides </span><span style="font-family: inherit;">with my experience when debugging thread heavy applications. Logs would not appear in the console and the only way to debug those apps was via a thread safe logger. </span></div><h2 style="text-align: left;"><span style="font-family: inherit;">Extending your logging framework (in this case NLog)</span></h2><div>There are a few ways to extend a logger. Depending on the architecture of your code you may be able to implement an interface and inject that to you tests or inherit a wrapper around your logger and override its methods. In the case of NLog however all one has to do is create an <a href="https://nlog-project.org/2015/06/30/extending-nlog-is-easy.html" target="_blank">NLog extension</a> and tweak the <span style="font-family: Share Tech Mono;">nlog.config</span> file. The article may be from 2015 but the information is extremely accurate.</div><div><br /></div><div>The extending part is easy. Now to tackle the logging part. Where do we want to print the logs? If we wanted to use files we needn't extend anything. What we do want is see our system's logs in our CI's logs. If we do want to do that we want to make sure that our logger is not under an <span style="font-family: Share Tech Mono;">AsyncWrapper</span> in our <span style="font-family: Share Tech Mono;">nlog.config. </span><span style="font-family: inherit;">That may work if your system is simple and doesn't have threads involved, chances are however it is not and it has threads and I/O connections of all sorts and colors (on integration or E2E tests for example), not to mention async/await calls. So regular console logging will not work here. It can help us for an initial test to check the </span>extension<span style="font-family: inherit;"> is registered and working properly.</span></div><h2 style="text-align: left;"><span style="font-family: inherit;">Printing the logs</span></h2><div><span style="font-family: inherit;">Since we are trying to print logs via flows in our system produced by our tests and test runners run tests in batches (which would also mean threads) and we are testing pars of a complex system and we want to make sure the logs appear as part of the test result.</span></div><div><span style="font-family: inherit;"><br /></span></div><div>In the case of NUnit the most usual runner plugin in a CI like Teamcity is the <a href="https://github.com/nunit/nunit-console" target="_blank">NUnit Console Runner</a>. While it encompasses the NUnit engine it also has its own colorful console.</div><div><br /></div><div>Since the runner in Teamcity is the console runner what one can do is download and install the runner and see the logs for oneself. This is all fine but how do we write those logs? Well NUInit gives us a few options:</div><div><br /></div><div><ul style="text-align: left;"><li>Regular logging: <pre><code>TestContext.WriteLine("This is my log line")</code></pre>Will not work acts like a regular console</li><li><span style="font-family: inherit;">Current test's context: </span><pre><code>TestContext.CurrentContext.WriteLine("This is my log line") </code></pre>Will not work acts like a regular console</li><li><span style="font-family: inherit;">Using the console runner's different out streams as quoted in the <a href="https://docs.nunit.org/articles/nunit/writing-tests/TestContext.html">NUnit documentation</a>:</span></li></ul></div><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div><blockquote style="text-align: left;"><div><div><b>Out</b></div></div></blockquote></div><div><blockquote style="text-align: left;"><div>Gets a TextWriter used for sending output to the current test result.</div></blockquote></div><div><blockquote style="text-align: left;"><div><b>Error</b></div></blockquote></div><div><blockquote style="text-align: left;"><div>Gets a TextWriter used for sending error output intended for immediate display.</div></blockquote></div><div><blockquote style="text-align: left;"><div><b>Progress</b></div></blockquote></div><div><blockquote style="text-align: left;"><div>Gets a TextWriter used for sending normal (non-error) output intended for immediate display.</div></blockquote></div></blockquote><div style="text-align: left;">Out of the three last options the only one who worked properly in the NUnit-NLog-Teamcity setup was TestContext.Progress.WriteLine("My message"). And when I say properly I mean that the relevant logs showed up in the Teamcity build log before and after a failing or succeeding test but the ones set to output on the test result where nowhere to be found. I would guess that this is the cause of threads over the system, NLog and NUnit Console Runner altogether. That does not mean however that you should not try them all and see what fits best to your setup.</div><h2 style="text-align: left;">Tests reporting tools and logging </h2><div>Among other things in our pipelines we are also using the <a href="https://docs.qameta.io/allure/" target="_blank">Allure Framework</a> of <a href="http://allure.qatools.ru/">Allure Reports</a> to visualize our test results and look up on trends and groups of errors. The above logging methodology does not provide any logs in test outputs because we are using the Progress <span style="font-family: Share Tech Mono;">TextWriter</span><span style="font-family: inherit;">. However, if we want to have some particular </span>logging<span style="font-family: inherit;"> on a test on an overnight report we make sure to add calls to the Out or Error </span><span style="font-family: Share Tech Mono;">TextWriter</span><span style="font-family: inherit;">s on that test's code.</span></div><h2 style="text-align: left;">Final words</h2><div>I hope this post will save you, oh lucky reader, from the arduous task of having to figure out all these permutations on your own. I sure had an interesting couple of days arguing with myself over the code and the CI, and so I thought I would spare you the long hours of search and frustration with this post</div>Unknownnoreply@blogger.com3tag:blogger.com,1999:blog-3256541113612906467.post-52801565160335455342020-01-02T14:43:00.001+02:002020-01-02T14:52:20.891+02:00Reviving old hardware en mass or: How I Learned to Stop Worrying and Love the ZorinOS Linux Distribution<a href="https://www.albertobarnoy.blog/2019/12/volunteering-in-school-it-retrospective.html" target="_blank">Let's see how we can help upgrade and stabilize the school's computers in the classes and labs he said</a>. <a href="https://www.albertobarnoy.blog/2019/12/volunteering-in-school-it-retrospective.html" target="_blank">But as I wrote before the Local Council's finances are in dire straights.</a> <i>TL;DR The end may be happy. but the journey was glorious.</i><br />
<i><br /></i>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-rWV-INNzC1kwPcL1DUzWU0bop0vxRcQTC8sRunPs9-7Z204Lb7X78aSTsd1LFAru8YEyPmA2cKI4B0E43KlK5SEb8UNR8U2Ymb1_hZNbmc99BRVQ76cGdhzRLfpnyeCQpfzZdHgTgCs/s1600/Raster.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="651" data-original-width="750" height="277" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-rWV-INNzC1kwPcL1DUzWU0bop0vxRcQTC8sRunPs9-7Z204Lb7X78aSTsd1LFAru8YEyPmA2cKI4B0E43KlK5SEb8UNR8U2Ymb1_hZNbmc99BRVQ76cGdhzRLfpnyeCQpfzZdHgTgCs/s320/Raster.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">ZorinOS Logo Copyright © 2014 - 2020 Zorin Technology Group Ltd. All Rights Reserved.</td></tr>
</tbody></table>
<i><br /></i>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<h3>
The state of computers in classes and labs</h3>
<div>
Hardware ranging from the last generation of dual core Pentiums to 4th generation i7s with a sprinkle of, surprisingly fast but with very low memory and cache, dual core 64bit AMDs. Packed with dust, ridden with useless software and desktops full of documents over Windows 7 and some Windows 10 build 1803 or less. The list of complaints on slow or stuck PCs is getting longer by the day. The phrase "It does not work" appears in every other row on a spreadsheet. It is the end of June 2019, School year starts September 1st, the teachers do not know what they need on the PCs but they need it working and time is running out.</div>
<h3>
250 Windows and Office licences...</h3>
<div>
Apparently Windows and Office licenses was the easy part. There is a business arrangement between the ministry of education and Microsoft for sponsored licenses for educational institutions. But would anyone install Windows 10 on a last generation dual core Pentium? Is it even possible? Does the bios support it? </div>
<h3>
Vendors, BIOS and promises promises</h3>
<div>
Depending on the vendor a bios update would sometimes help with Windows 10 installations and sometimes not. The machines would run faster, albeit their slow HDDs, but eventually some windows update would come along and break things. There is also no domain controller available to regulate updates (see dire finances). So what can one do until new hardware is purchased or hardware donations come though? Push for Linux.</div>
<h3>
Convince us on Linux</h3>
<div>
When I was asked to "put my money where my mouth is" I had a huge dilemma... Use an XFCE based Ubuntu or Arch derivative or use the somewhat heavier Gnome Desktop on either. Gnome however is "strange" to the eyes of long time Windows users. I took a leap of faith with a Gnome based Arch derivative which was light enough for this ageing hardware.</div>
<div>
The requirements I had to fulfill were "<i>simple" </i>enough: </div>
<div>
<ul>
<li>Disable background changes</li>
<li>Provide password-less login for students</li>
<li>Ease of use</li>
<li>An Office suite which is Microsoft Office compatible, it uses Microsoft fonts in Hebrew and saves as a Microsoft Office document by default.</li>
<li>Ease of upgrades</li>
</ul>
</div>
<div>
After a few hours of digging through online communities I had the whole thing set up. All I needed to do was convince the stakeholders. The demo went fine and the stakeholders where content albeit concerned. I made a case for students needing to think outside the box and be free of the chains of one OS. After all their cell phones are neither Linux or Windows and yet they manage. It is probably us, the grown ups, who are more worried. However convinced and confident I was there were still some islands of doubt as to how Linux would be welcomed by students and teachers alike.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGtSaQGO-P9edP65BbQ42ogS3gCwKcvkbF5IWGve470VfyVQGnu66v-kxdP8h2fENEj9ySZGRR9IWLyApCQCpsei_2NezswNbN7rbWjX4PljmQV_qIQfkHS3pQGn6HoXX5avBZdIJU5lM/s1600/gray-concrete-pavement-between-green-tall-trees-1042441.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="426" data-original-width="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGtSaQGO-P9edP65BbQ42ogS3gCwKcvkbF5IWGve470VfyVQGnu66v-kxdP8h2fENEj9ySZGRR9IWLyApCQCpsei_2NezswNbN7rbWjX4PljmQV_qIQfkHS3pQGn6HoXX5avBZdIJU5lM/s1600/gray-concrete-pavement-between-green-tall-trees-1042441.jpg" /></a></div>
<div>
<br /></div>
<h3>
Final stretch <a href="https://zorinos.com/" target="_blank">ZorinOS </a>to the rescue</h3>
<div>
It was decided that Linux will go into computer labs with the thought that we would introduce some Scratch and Python courses to primary and middle school students and whatever is salvageable and upgrade-able will go to the class where teachers will not have to worry about meeting an unknown OS (at least visually).</div>
<div>
<br /></div>
<div>
After receiving some 32 ageing laptops (dual cores and first gen i3) we decided to take 10 of them and use them as the first Linux pilot in a special teamwork space/class. With 10 days to go I stumbled upon one more article about a surprising Linux distribution named <a href="https://zorinos.com/" target="_blank">ZorinOS </a>that runs fast on ageing hardware. Going through their web site I discover they have an <a href="https://zorinos.com/education/" target="_blank">education version</a> with requirements half the CPU and RAM I have in my ageing hardware across the board. I spun up a virtual machine and my mind was blown away!</div>
<h3>
Worry free and super fast</h3>
<div>
After initial installation one can see a clean desktop with calming pastel colors, such that even one who cannot stand bright backgrounds, like me (due to many years of bright CRT monitors and theme-less development environments), will not feel overwhelmed by the colors, a Windows like experience with the <a href="https://zorinos.com/" target="_blank">Zorin </a>menu and all the apps neatly tucked away in categories. I only needed to add one application for video editing and the image was ready.</div>
<div>
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeHha8RuVsAL_Q0IJDlkquuxZNYU3e6Z_2K_NzdvGuOb2HqbDw_V9Lgj4BfHm9mG1sv6SNJHyveVS0kjp4ZcsJqSk2XnPHoKZSIkFWXPbsYtns-8mEiZFr85JVi5K9PYJAeaG7OltZ-k8/s1600/Zorin-OS-15-Default-Desktop.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="768" data-original-width="1368" height="359" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeHha8RuVsAL_Q0IJDlkquuxZNYU3e6Z_2K_NzdvGuOb2HqbDw_V9Lgj4BfHm9mG1sv6SNJHyveVS0kjp4ZcsJqSk2XnPHoKZSIkFWXPbsYtns-8mEiZFr85JVi5K9PYJAeaG7OltZ-k8/s640/Zorin-OS-15-Default-Desktop.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">ZorinOS default Desktop</td></tr>
</tbody></table>
<div>
<br /></div>
<div>
The desktop is apparently a heavily customized (but down to simplicity) Gnome desktop. That way I could apply the same background locks and password-less logins as before. I was in love!</div>
<div>
<br /></div>
<div>
Once I checked that I could fulfill all requirements I installed it on a slow dual core machine. The installation was fast and the machine was given a new life.</div>
<div>
<br /></div>
<div>
Within 48 hours I demoed it and started installing it on ageing laptops. The computers teacher at the middle school was thrilled by the speed and the educational applications as well as the ease of use. </div>
<div>
All that is left is gauge the acceptance of students and rush off to install more than 30 ageing machines. At this point if I was to recommend to someone a Linux desktop it would be either <a href="https://zorinos.com/download/#core" target="_blank">Zorin Core </a>or<a href="https://zorinos.com/download/#lite" target="_blank"> Zorin Lite</a> depending on the hardware at hand</div>
<h3>
Copyrights, thanks and disclaimers</h3>
<div>
This is the time to thank the Zorin team for a beautiful distribution, their permission to use their logos and graphics as well as the<a href="https://zoringroup.com/forum/viewforum.php?f=3" target="_blank"> Zorin Support Community</a> for their quick responses.</div>
<div>
<br /></div>
<div>
Finally from <a href="https://zorinos.com/" target="_blank">Zorin's </a>own web site:<br />
<br /></div>
<span style="font-family: "times" , "times new roman" , serif;">The "Z" logomark and the "ZORIN" name are trademarks of Zorin Technology Group Ltd.The "ZORIN" and "ZORIN OS" logotypes are Copyright © 2014 - 2020 Zorin Technology Group Ltd. All Rights Reserved.Zorin Technology Group Ltd. permits the use of Zorin OS branding and the above brand assets for non-commercial use only. Usage of these term(s) and/or associated image(s)/logo(s) does not and should not suggest affiliation, endorsement or sponsorship by Zorin Technology Group Ltd. or any of its subsidiaries. Zorin Technology Group Ltd., at its sole discretion, reserves the right to cancel, modify, change, add or remove its policies at any time without notice.</span><br />
<div>
<span style="font-size: x-small;"><br /></span></div>
<div>
<br /></div>
Unknownnoreply@blogger.com10tag:blogger.com,1999:blog-3256541113612906467.post-18421594973986541252019-12-25T12:10:00.001+02:002020-01-02T14:43:12.967+02:00Volunteering in school IT - A retrospectiveThe purpose for a PC in a school is to be a teaching tool and not a hurdle.<br />
This is a retrospective of the most interesting volunteer work I have ever done (and still do). I live in a small town (~9000 residents), governed by a Local Council. As it happens the Local Council's finances are in dire straits (which I will not go into at all) and at the 3 schools within its jurisdiction (in two of them my children study), 2 primary schools and one middle school, the PCs in the classes have fallen to disarray. <i>TL;DR No such thing this time. Read on</i><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiATDMR6t50SklK0EskEw1a2jGur73mbZ_1Gb6TVy8_aBgcA9hqmA33IS7ojiqRyzLfz4HGnB5K12TSpew-swnOPT5usJTfNK0bK29hulU7yPHlKqUddPLEAveZK1XK3_kd-TFEsTCbs5A/s1600/hands-people-friends-communication-45842.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="512" data-original-width="640" height="512" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiATDMR6t50SklK0EskEw1a2jGur73mbZ_1Gb6TVy8_aBgcA9hqmA33IS7ojiqRyzLfz4HGnB5K12TSpew-swnOPT5usJTfNK0bK29hulU7yPHlKqUddPLEAveZK1XK3_kd-TFEsTCbs5A/s640/hands-people-friends-communication-45842.jpg" width="640" /></a></div>
<br />
<h3>
How it all begun</h3>
Somewhere around June 2019 one of the council members mentioned that he is trying to devise a plan to upgrade the school's computers and network infrastructures. Long story short I found myself willingly involved in that project spearheading change on the field while said council member spearheads change in administrative levels on the education board. I will spare you the long night hours upgrading OSs, the mistakes and the triumphs. I will share with you however what I have learned since, as far as project management and support goes, as well as how it has changed me, probably for life.<br />
<h3>
Culture Shock</h3>
<div>
Imagine any person in our field, coming from the ever demanding and fast pacing private sector who just enters, albeit volunteering, into the public, slow paced public sector. It is a culture shock. One cannot understand why things move slowly, why time is not pressing and sometimes why one is not being understood. On the other hand the people in the public sector meeting such a person do not understand what is the rush... The wheels of bureaucracy are slow. Why rush? </div>
<div>
<br /></div>
<div>
One has to press the "client" for requirements (what to install beyond OS and some office suite), how things are connected in the class, what is the firewall configuration (is there a firewall at all? What is a firewall? ) and should data be backed up, only to have answers painfully trickle in.</div>
<div>
<br /></div>
<div>
Fast forward 3 weeks later after the requirements are closed, the school is ready, including training videos, upgrades, dust cleanup, passwords and firewalls. Three volunteers from the private sector rushed in to bring it all up and running just before the new school year opened. </div>
<div>
<br /></div>
<div>
It was time for the public sector to be in a culture shock. 110 PCs, 3 weeks of after hours work, intensive support for the first week of school opening. They said we have lots of energy. I say we are used to do things in an orderly and quick way.</div>
<h3>
Lessons learned</h3>
<div>
Some of these lessons were known to me from experiences past but had to be re-iterated in the right context. So in no definite order here goes:</div>
<div>
<ul>
<li>We are a technical authority but also volunteers. Nobody owes us anything. This is their place of work. They know better. We ask what hey need and we suggest the best possible solutions, including building computer labs on Linux instead of aging Windows.</li>
<li>When it comes to any procedural vs technical matter (for example, firewall or content filtering), insist, be firm and compromise on what works best but also achieves the purpose.</li>
<li>The client is always right. But the client does not dictate how to execute the requests. This is up to us.</li>
<li>Don't promise what you cannot achieve</li>
</ul>
</div>
<div>
<br /></div>
Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-3256541113612906467.post-10695454079463708802019-10-15T15:56:00.001+03:002019-10-15T15:56:28.583+03:00Evaluating NDepend on current codebase Part 2In <a href="https://www.albertobarnoy.blog/2019/10/evaluating-ndepend-on-current-code-base.html" target="_blank">Part 1</a> we saw a first approach to <a href="https://www.ndepend.com/" target="_blank">NDepend </a>starting off with analyzing a project of 2 assemblies and focusing on the smaller assembly. In this part we will focus on the main executable and the gems <a href="https://www.ndepend.com/" target="_blank">NDepend </a>discovered in it <i>TL; DR Memory leak detected...</i><br />
<i><br /></i>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoN6WOpQgZ6AmEgxQ6IWow7T89YXz1xTccejuSaCpJDQNHyJ2M_vRGKRLDhcqJKO5m_u9tpdBinhkTgvfWbARDxI98rI740DQkqDi3lNRLJtx4wVpbfcqZqDYFHRmFhevBRsStVvg834A/s1600/daan-mooij-91LGCVN5SAI-unsplash.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="900" data-original-width="1600" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoN6WOpQgZ6AmEgxQ6IWow7T89YXz1xTccejuSaCpJDQNHyJ2M_vRGKRLDhcqJKO5m_u9tpdBinhkTgvfWbARDxI98rI740DQkqDi3lNRLJtx4wVpbfcqZqDYFHRmFhevBRsStVvg834A/s640/daan-mooij-91LGCVN5SAI-unsplash.jpg" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><span style="background-color: white; font-family: inherit;"><span style="color: #111111; font-size: 14px; white-space: nowrap;">Photo by </span><a href="https://unsplash.com/@daanmooij?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText" style="box-sizing: border-box; color: #767676; font-size: 14px; text-align: start; text-decoration-skip-ink: auto; transition: color 0.1s ease-in-out 0s, opacity 0.1s ease-in-out 0s; white-space: nowrap;">Daan Mooij</a><span style="color: #111111; font-size: 14px; white-space: nowrap;"> on </span><a href="https://unsplash.com/s/photos/leak?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText" style="box-sizing: border-box; color: #767676; font-size: 14px; text-align: start; text-decoration-skip-ink: auto; transition: color 0.1s ease-in-out 0s, opacity 0.1s ease-in-out 0s; white-space: nowrap;">Unsplash</a></span></td></tr>
</tbody></table>
<h2>
Enter 3 years old WPF project - Main executable</h2>
<div>
Going back to the dashboard I see the "usual" long types or methods errors, some immutability warnings, which I would have set as errors and 400 violations of "Avoid namespaces mutually dependent" some with debt time of 4 days. "Oh come on.. what 4 days. How hard can it be..."</div>
<div>
<br /></div>
<div>
Drilling down into the code (a wpf application) I realize that there is a single class that is injected in the constructor of every view model and I hardly see any services in the system save for calls to the DAL assembly.</div>
<div>
<br /></div>
<div>
Without drilling down into the class I changed it's namespace and made the necessary, albeit sisyphic, changes to all the classes. While at it I noticed that some view models where creating instances of view models for dialog boxes, panes and popups and injected the Container class to them as well. </div>
<div>
<br /></div>
<div>
Once the change was completed, I run NDepend on the result and I had 800 violations of the namespace rule plus some API breaks. Oh my...</div>
<h2>
A lesson learned: Always drill down before making such change</h2>
<div>
The injected class, let's call it <i>Container</i>, has 2 properties pertaining to 2 classes, Let's call them Singletons and Factories. </div>
<div>
<br /></div>
<div>
A first look reveals nothing suspicious; <i>Singletons </i>holds services and <i>Factories </i>creates view models when needed. Sounds reasonable right? Wrong... To quote myself:</div>
<blockquote class="tr_bq">
there is a single class that is injected in the constructor of every view model </blockquote>
In fact, every time the <i>Factories</i> class creates a class it injects in its constructor... you guessed it, the <i>Container </i>class. Moreover, elements in the <i>Singleton </i>class created view models via the <i>Factories</i> and these view models in turn require use of these same (or other) singletons. In fact, some view models also serve as service classes and there is more than one way to create a view model; By factory or by directly initializing via constructor. Here is a diagram of the dependencies between these classes.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXWwKlhg7HxBZU_Ey0lCx5bWsq6n9GSeI4ubT3-zSP8pY8kSlcLTOz4Jpd-G7821Mp_Q7V5-hbRjTiq5HqHaWXgPVBSBoXpCLjfdH8C4xtf8Ksz0Nx9GMU_bmXTs7A8cdpf_XhHDmRXek/s1600/Cyclic+dependency.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="362" data-original-width="621" height="372" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXWwKlhg7HxBZU_Ey0lCx5bWsq6n9GSeI4ubT3-zSP8pY8kSlcLTOz4Jpd-G7821Mp_Q7V5-hbRjTiq5HqHaWXgPVBSBoXpCLjfdH8C4xtf8Ksz0Nx9GMU_bmXTs7A8cdpf_XhHDmRXek/s640/Cyclic+dependency.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">There really aren't enough lines to describe this</td></tr>
</tbody></table>
<br />
When there is a "God" obejct in any system it almost always ends up looking like this. Sometime weird performance issues are detected in the system and people tend to use GC.Collect to deal with them and blame some 3rd party black box or may some obscure Microsoft bug, not that this isn't known to happen. However when some GC.Collect calls seem to solve the problem that means that there is a memory leak and a misbehaving object ruining loose.<br />
<h2>
Going forward with the D in S.O.L.I.D</h2>
<div>
A lot of time will be spent fixing this one obviously, mainly by introducing a proper dependency injector and IOC container. And in every step of the way this code as well as any new code in the development team will have to be analyzed by NDepend to catch problems on time. The build engine integration of NDepend should be of great value to catch code smells as they are committed. </div>
<div>
<br /></div>
<div>
Apart from the features portrayed in these posts NDepend is feature rich, including code coverage files (which I have yet to test), trends, metrics and graphs to show you your project analysis from any view and angle possible. I am hooked. How do you perform your static code analysis? Leave a note in the comments below.</div>
<div>
<br /></div>
Unknownnoreply@blogger.com3tag:blogger.com,1999:blog-3256541113612906467.post-40748093637163912552019-10-15T15:56:00.000+03:002019-10-15T17:54:53.153+03:00Evaluating NDepend on current code base Part 1A while ago I was asked by one of <a href="https://www.ndepend.com/" target="_blank">NDepend's</a> founders to evaluate any .NET code base I wanted with <a href="https://www.ndepend.com/" target="_blank">NDepend</a> and write a blog post about it. It turns out I came up with a two-part post. <i>TL; DR Oh boy....</i><br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIWyx5xQPw5twYum0d7Sy_Ez-1llNMyIC88izGXQvbjT729wtjh6PX3KTTnwn6R5a1lygKWyaMTuU8xUcgvKPnT_5YsfjJOJxnqZvvRw_pSAmi9prJn-3htr3pQuu8J4TJjWILQ6GDejc/s1600/banner-4056457_1920.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="391" data-original-width="1600" height="155" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIWyx5xQPw5twYum0d7Sy_Ez-1llNMyIC88izGXQvbjT729wtjh6PX3KTTnwn6R5a1lygKWyaMTuU8xUcgvKPnT_5YsfjJOJxnqZvvRw_pSAmi9prJn-3htr3pQuu8J4TJjWILQ6GDejc/s640/banner-4056457_1920.jpg" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Photo by geralt on Picabay</td></tr>
</tbody></table>
<i><br /></i>
<br />
<h2>
Enter 3 years old WPF project</h2>
<div>
Without revealing the nature of the specific project I would just say it is a feature rich client, with UI elements customized to the customer's needs. It is written using MVVM, some third party grids and communicates with an SQL Server database via a classic DAL class library. All and all the project is comprised of one executable and one DAL assembly.</div>
<div>
<br /></div>
<div>
So off I went and added the necessary assemblies to a new NDepend project and let the analysis run. Given the size of the project it was pretty swift and started off with a a dashboard (or at least this is the view I chose to start from).<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgavdhOPLVOQcSwxEOPLPo9iv2A949cxOvo-sACbO2g7cAja2yv4IVjAa1UaCVra5bBT2jewFdM38U-0JFcIjcAb5FIZMoYM3FEKDMvdF5zitaLnIzp1L2iX6pOFY8tdoXo41q-Rs12w3A/s1600/NDependDashboard.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="867" data-original-width="1600" height="345" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgavdhOPLVOQcSwxEOPLPo9iv2A949cxOvo-sACbO2g7cAja2yv4IVjAa1UaCVra5bBT2jewFdM38U-0JFcIjcAb5FIZMoYM3FEKDMvdF5zitaLnIzp1L2iX6pOFY8tdoXo41q-Rs12w3A/s640/NDependDashboard.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">NDepend desktop Dashboard</td></tr>
</tbody></table>
<br />
At the same time a very nifty HTML based dashboard popped up in my browser<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWWYdZRteQ6tcLqhKTnCbOvov-sfLAq-wBzVmAmBiazZlcDCZyfRMJPiVewts4rZWsJ2X4fJ0Bgj5F594HXKzyVdZTkERxjit6ZnR4EgZdUnA9gtANxb9huvSjILCSV6tiXQVnlbWSMno/s1600/NDependHTML.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="815" data-original-width="1600" height="324" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWWYdZRteQ6tcLqhKTnCbOvov-sfLAq-wBzVmAmBiazZlcDCZyfRMJPiVewts4rZWsJ2X4fJ0Bgj5F594HXKzyVdZTkERxjit6ZnR4EgZdUnA9gtANxb9huvSjILCSV6tiXQVnlbWSMno/s640/NDependHTML.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">NDepend HTML Dashboard</td></tr>
</tbody></table>
<br />
<br /></div>
<div>
The dashboard (as expected from its name) gives one a very good 10000 feet overview of the state of the code base. The first thing that drew my attention on the HTML dashboard was the Abstractness vs Instability graph... Although the Treemap Metric View looks mostly clean (green) the Abstractness vs Instability tells a different story...<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibaCDs0gwWCwJpSNrUzeyWw7dFXpsWAVhJgFjUO-vb1DsMOaqTkOjxo4sfDPnei28q2FaS6ugAU9OmnwJsRi8yA2t1XIQNr0pawFr4hEwt0qXQg1iTL-5d-s5_ny8Emsp1qY8bzBaIPWo/s1600/NDepend+AbstractVsInstability.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="965" data-original-width="1108" height="556" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibaCDs0gwWCwJpSNrUzeyWw7dFXpsWAVhJgFjUO-vb1DsMOaqTkOjxo4sfDPnei28q2FaS6ugAU9OmnwJsRi8yA2t1XIQNr0pawFr4hEwt0qXQg1iTL-5d-s5_ny8Emsp1qY8bzBaIPWo/s640/NDepend+AbstractVsInstability.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">NDepend Abstractness vs. Instability</td></tr>
</tbody></table>
<br />
In order to get accustomed to the tool I examined the DAL assembly first. I took a deep breath and set out to see what rules where broken. A little bit of drill down brought me to 14 types and 4 methods in the DAL violating some rule... How hard can that be?</div>
<div>
<br /></div>
<h2>
The elusive "Avoid namespaces mutually dependent"</h2>
<div>
I am not a native English speaker. I do, however, consider myself pretty fluent in the English language and this one I had to run through my head a bit. After reading about it in NDepend's docs, which thoroughly explain how to investigate the issue and acted as per the docs, I got the gist of it. There is a circular dependency between namespaces. One that is not direct or easy to find.<br />
<br />
How come the tool finds a possible circular reference between two namespaces and I do not see it in code unless I am using the tools provided by NDepend? Instead of dismissing the error I took out the good old pen and paper and started writing down the dependencies, inheritances and implementations between two offending namespaces (out of 14 violations). This was more for ducking it out to myself than lack of documentation. When I was done writing down it hit me... Spaghetti code one step away from adding the meatballs. Here is a partial diagram<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjY0vy5b8hpLaXiwEGiF5XVg3In_nfdCXTJhdQmP8x0-d3Wl5M3kW21ozThm2-lndOm9c7sVz7tkQlscwblba_7HF-K4pUA32HDZ9erpcLFFf1Ou6B7mRQeiSH-oLQ1wVnhHuk8O6HGISg/s1600/NameSpaceSpaghetti.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="442" data-original-width="720" height="392" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjY0vy5b8hpLaXiwEGiF5XVg3In_nfdCXTJhdQmP8x0-d3Wl5M3kW21ozThm2-lndOm9c7sVz7tkQlscwblba_7HF-K4pUA32HDZ9erpcLFFf1Ou6B7mRQeiSH-oLQ1wVnhHuk8O6HGISg/s640/NameSpaceSpaghetti.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Spaghetti...</td></tr>
</tbody></table>
<br />
<br />
In one of the cases the solution was pretty simple... Just change the namespace in one interface and the code is untangled. In the DAL assembly however lies the hint for the mess to come. Not all 14 violations where so easy to solve.<br />
<h2>
More code smells</h2>
If you take a close look at the dashboard image there are some more problems there. Some of them denote long types, long methods or long names. Pretty easy to solve. Some of them are warnings that the U.I should neither use DB types nor the DAL directly. I agree on the former. I can argue the latter. And I think that the makers of NDepend where right to make this a warning and not an error.<br />
<br />
Ideally the U.I layer would communicate with a service which communicates with the database. Then again ideally none of us likes to inherit other coders code smells; We like to make our own mess...<br />
<h2>
Some unwanted dependencies</h2>
</div>
<div>
One more thing that I checked out was the overall types dependency graph. I discovered that the DAL has direct access to other domain's APIs as well as direct access to message queues. This may not be a broken rule on the static code analysis but it is bad architecture.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhM0cBECHMZi9a3rFS5gTQzV6Odw2SnJmcNBRQq-xh6-oxaDlzsiQsa0ywiq2aHxVHNtB-i5CgA0qhIS0cqB8RyWH9G95AOO6C1Qv8W2M1REoax9b6VAILcLKopEv9bSbZjd7qoxw9_PQ8/s1600/Dependencies.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="431" data-original-width="691" height="398" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhM0cBECHMZi9a3rFS5gTQzV6Odw2SnJmcNBRQq-xh6-oxaDlzsiQsa0ywiq2aHxVHNtB-i5CgA0qhIS0cqB8RyWH9G95AOO6C1Qv8W2M1REoax9b6VAILcLKopEv9bSbZjd7qoxw9_PQ8/s640/Dependencies.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">This definitely not good architecture...</td></tr>
</tbody></table>
<br /></div>
<div>
<br /></div>
<h2>
Exit DAL part of 3 years old WPF project</h2>
<div>
"Well..." I thought to myself, "this wasn't so bad. Maybe I will be lucky and the 400 offending types in the actual executable are easy to fix like the first one I checked". Was I right or wrong? On to<a href="https://www.albertobarnoy.blog/2019/10/evaluating-ndepend-on-current-codebase.html" target="_blank"> Part 2</a>.</div>
Unknownnoreply@blogger.com3tag:blogger.com,1999:blog-3256541113612906467.post-85318032399015686662019-03-30T13:36:00.000+03:002019-03-30T13:36:19.113+03:00Tests code coverage in Visual Studio Code with C# and .Net CoreWhile writing tests for you code goes without saying, there is much to be said about code coverage of tests. How much of your code is actually covered by these tens of tests you just wrote? If you work in a TDD approach most probably you don't have such "mundane" questions. Of course you code is 100% covered. You did make sure every test failed before you added that line in your code to make it pass... and that conditional statement... or did you? While purists would argue there is no chance of no coverage I beg to differ. Let alone if you write your tests after the code is written... After such and such years and experience in the industry when we are nearing deadlines some things are thrown out the window. They shouldn't but they are. <i>TL;DR tools help with coverage. In this case <a href="https://marketplace.visualstudio.com/items?itemName=formulahendry.dotnet-test-explorer" target="_blank">.Net Core Test Explorer</a> with <a href="https://github.com/tonerdo/coverlet" target="_blank">coverlet </a>and <a href="https://marketplace.visualstudio.com/items?itemName=ryanluker.vscode-coverage-gutters" target="_blank">Coverage Gutters</a>.</i><br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqjFCDNwW-BQBLUcwjAwOfrt3XW6v213QltH58AkwU6Sf0tqj7jR3xDu8T4YSBpmK84CW9iI212yKN0HKMhziSTHVJp-Evu1mDTqS4e2EkjvrxgsEnqHuHJmsBBfmsY55_h0-uC1YewOA/s1600/action-plan-brainstorming-complex-212286.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1067" data-original-width="1600" height="425" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqjFCDNwW-BQBLUcwjAwOfrt3XW6v213QltH58AkwU6Sf0tqj7jR3xDu8T4YSBpmK84CW9iI212yKN0HKMhziSTHVJp-Evu1mDTqS4e2EkjvrxgsEnqHuHJmsBBfmsY55_h0-uC1YewOA/s640/action-plan-brainstorming-complex-212286.jpg" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Photo by <a href="https://www.pexels.com/@startup-stock-photos?utm_content=attributionCopyText&utm_medium=referral&utm_source=pexels" style="background-color: #e8e8e8; box-sizing: border-box; font-family: -apple-system, BlinkMacSystemFont, "segoe ui", roboto, oxygen, cantarell, "helvetica neue", ubuntu, sans-serif; font-size: 16px; margin-bottom: 0px; margin-top: 0px; text-decoration-line: none;">Startup Stock Photos</a><span style="background-color: #e8e8e8; color: #333333; font-family: , "blinkmacsystemfont" , "segoe ui" , "roboto" , "oxygen" , "cantarell" , "helvetica neue" , "ubuntu" , sans-serif; font-size: 16px;"> from </span><a href="https://www.pexels.com/photo/man-wearing-black-and-white-stripe-shirt-looking-at-white-printer-papers-on-the-wall-212286/?utm_content=attributionCopyText&utm_medium=referral&utm_source=pexels" style="background-color: #e8e8e8; box-sizing: border-box; font-family: -apple-system, BlinkMacSystemFont, "segoe ui", roboto, oxygen, cantarell, "helvetica neue", ubuntu, sans-serif; font-size: 16px; margin-bottom: 0px; margin-top: 0px; text-decoration-line: none;">Pexels</a></td></tr>
</tbody></table>
<h3>
Coverlet to the rescue</h3>
<div>
As I <a href="https://www.albertobarnoy.blog/2019/03/visual-studio-code-setup-i-use-for-c.html" target="_blank">blogged </a>a while ago I have made myself a warm and cozy development environment for Visual Studio Code. One thing that popped to mind was tests code coverage. How can I see the coverage of my tests before they reach the CI pipeline? After a surprising brief search online I discovered a dotnet core CLI tool called <i><a href="https://github.com/tonerdo/coverlet" target="_blank">coverlet</a></i>. One can use this tool to create a coverage file and feed that file to a coverage reporter or even in some of the CI tools out there. The tool mainly produces common formats for code coverage reporters. All one needs to do is install the coverlet tool and install a Nuget package to one's test project. Fortunately the tool's Github page has detailed installation and usage information.</div>
<h3>
.Net Core Test Explorer</h3>
<div>
So far so good. One can produce a textual representation of the coverage by running a command line tool. We are however developers and as such inherently lazy. I want the coverage to be updated every time I run my updated tests via the very very neat <i><a href="https://marketplace.visualstudio.com/items?itemName=formulahendry.dotnet-test-explorer" target="_blank">.Net Core Test Explorer</a></i> extension for Visual Studio Code.</div>
<div>
<br /></div>
<div>
This extension discovers, runs all tests or single tests for debug and... test... via Code Lens as well as provide feedback on whether a single test has passed failed or is being skipped. One of its very useful features is the ability to feed the dotnet core test runner with arguments. Since we have coverlet installed we can now instruct the test runner to create the coverage (i.e. call coverlet), control the coverage file format and output location.</div>
<div>
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXnJXdd27XmuFUZ6sHdt65apvSBcErfd2gnHErN8izD4bXdyj-OnKCWOE6Fb909ue-icBCdAU3o3UerQ6MeHGyd6q0DOpocNPVI1cW5SupSS4HiV5ozv13kfRnCNd3S9VDx4YoHNIRfOs/s1600/.NetCoreTestExplorer.PNG" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img alt="Part of the .Net Core Test Explore settings" border="0" data-original-height="171" data-original-width="595" height="182" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXnJXdd27XmuFUZ6sHdt65apvSBcErfd2gnHErN8izD4bXdyj-OnKCWOE6Fb909ue-icBCdAU3o3UerQ6MeHGyd6q0DOpocNPVI1cW5SupSS4HiV5ozv13kfRnCNd3S9VDx4YoHNIRfOs/s640/.NetCoreTestExplorer.PNG" title="Part of the .Net Core Test Explore settings" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Part of the .Net Core Test Explore settings</td></tr>
</tbody></table>
<h3>
Coverage Gutters</h3>
<div>
This handy language agnostic extension will take coverage files in lcov format and paint the gutter next to the covered code in green orange or red at the hit of a keystroke. One side effect here is that that once the gutter is overlayed with the coverage one cannot set or remove breakpoints. There is, however, a workaround to this. Show the coverage inline... which actually is way better.</div>
<div>
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1lCsDzbksUgoh3u-gPygD4XQ5SqY46LWXpT-_hdoFLxYu-XGwwAaJDC4o05-KC5GQVe7MLVq_cgUnHp01NFx__4u53jWBXqwMwsNR99AKcCh0CyNSl0sdOjhfYI9t9hal1MbhMK7vCPA/s1600/CoverageGutters.PNG" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="129" data-original-width="327" height="157" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1lCsDzbksUgoh3u-gPygD4XQ5SqY46LWXpT-_hdoFLxYu-XGwwAaJDC4o05-KC5GQVe7MLVq_cgUnHp01NFx__4u53jWBXqwMwsNR99AKcCh0CyNSl0sdOjhfYI9t9hal1MbhMK7vCPA/s400/CoverageGutters.PNG" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Part of the Coverage Gutters settings</td></tr>
</tbody></table>
<div>
<br /></div>
<div>
The reason why this is handy is because in conditional statements where more than one condition is tested, it actually shows the condition missed by the test. Green color is for covered, orange for partially covered and red for not covered at all.</div>
<div>
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNVznj5SkNoUuHctyKQejYWzbzFq10b6j9BvsonWe9mVVW7eyZmUP38u7YP9s2azUqYLL4Q3BU7Gs9xLTWZ_lwl9eKe7YpvREycudaOC3DRYPEV_cEK7bej8D4Fr5y0YPZRrnjYkF-DsE/s1600/CoverageExample.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img alt="Coverage Gutters example" border="0" data-original-height="554" data-original-width="918" height="385" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNVznj5SkNoUuHctyKQejYWzbzFq10b6j9BvsonWe9mVVW7eyZmUP38u7YP9s2azUqYLL4Q3BU7Gs9xLTWZ_lwl9eKe7YpvREycudaOC3DRYPEV_cEK7bej8D4Fr5y0YPZRrnjYkF-DsE/s640/CoverageExample.png" title="Coverage Gutters example" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Coverage Gutters example</td></tr>
</tbody></table>
<div>
<br /></div>
<div>
One caveat with this extension is that on Windows the "turn off coverage" keyboard shortcut does not work and cannot be set to the proposed combination. I opened in issue in Github and let the developer know. Unfortunately apart from setting a different keyboard shortcut there isn't anything else to do. I set mine to <i>ctrl+shift+backspace</i>.</div>
<div>
<br /></div>
<div>
I whipped up some code to demonstrate how these three extensions work together to help with coverage. You can find the code <a href="https://github.com/AlbertoBN/CoverageGuttersAndCoverletExample" target="_blank">here</a>.<br />
<br />
Let me know in the comments below if you have found any more useful extensions for vscode! </div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div>
<br /></div>
Unknownnoreply@blogger.com19tag:blogger.com,1999:blog-3256541113612906467.post-91666310623438467032019-03-25T18:44:00.000+02:002019-03-30T13:34:48.819+03:00Visual Studio Code setup I use for C# developmentVisual Studio Code has been around a while. However most of the extensions or blog posts out there relate mainly to extensions that facilitate development in JavaScript environments such as Angular, React or NodeJs (to name a few) and even Rust! The IDE is getting great reviews as being fast to load and very responsive as opposed to its bloated and heavy bigger brother, Visual Studio.<i> TL;DR I switched from Visual Studio for good</i><br />
<br />
Having worked on Visual Studio since version 4.2 I was used to it being heavy to load and at times even slow to respond. After experiencing VS Code with a little bit of NodeJs development I decided to try and make it my daily driver for .Net Core and C# development. I sought to find extensions to ease my day in the cubicle and see how comfortable will I be with it. I would give it a month on various tasks and workloads.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiY537h3xYCt_GN6AZZXauorSGm7EuD8O1wk5PfOTaHT4EfaPZpRLPMCg1tlc2sAsOHI4XnQ1zqxj4hHM9qLWi_AB8sYtDkbaSQ405VNsUholaZXcLNjU5bZ_ZNktkthCFk5FdaAO8c4lo/s1600/Screenshot+from+2019-03-25+17-56-41.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img alt="VSCode showing off extensions" border="0" data-original-height="744" data-original-width="1600" height="297" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiY537h3xYCt_GN6AZZXauorSGm7EuD8O1wk5PfOTaHT4EfaPZpRLPMCg1tlc2sAsOHI4XnQ1zqxj4hHM9qLWi_AB8sYtDkbaSQ405VNsUholaZXcLNjU5bZ_ZNktkthCFk5FdaAO8c4lo/s640/Screenshot+from+2019-03-25+17-56-41.png" title="VSCode showing off extensions" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">VSCode showing off extensions</td></tr>
</tbody></table>
<div class="separator" style="clear: both; text-align: center;">
</div>
The month became two months and then 3 months and here I am with a list of very handy (in my opinion) extensions for vscode. Some of them useful for all programming languages and some for C#.<br />
<br />
<h3>
C# and .NET Centric (in no particular order)</h3>
<div>
<ul>
<li><a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode.csharp" target="_blank">Omni Sharp</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=formulahendry.dotnet-test-explorer" target="_blank">.Net Core Test Explorer</a></li>
<li><a href="https://github.com/jchannon/csharpextensions" target="_blank">C# Extensions</a> - Unfortunately project discontinued</li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=josephwoodward.vscodeilviewer" target="_blank">C# IL Viewer</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=jorgeserrano.vscode-csharp-snippets" target="_blank">C# Snippets for Visual Studio Code</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=k--kato.docomment" target="_blank">C# XML Documentation Comments</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=doggy8088.netcore-snippets" target="_blank">Essential ASP.NET Core Snippets</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=tintoy.msbuild-project-tools" target="_blank">MSBuild project tools</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=jmrog.vscode-nuget-package-manager" target="_blank">Nuget Package Manager</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=craigthomas.supersharp" target="_blank">Super Sharp (C# extensions)</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=fernandoescolar.vscode-solution-explorer" target="_blank">vscode-solution-explorer</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=quicktype.quicktype" target="_blank">Paste JSON as code</a> - This extension supports also Go, TypeScript, C++ and more</li>
</ul>
<h3>
Language Agnostic</h3>
</div>
<div>
<ul>
<li><a href="https://marketplace.visualstudio.com/items?itemName=alefragnani.Bookmarks" target="_blank">Bookmarks</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=CoenraadS.bracket-pair-colorizer-2" target="_blank">Bracket pair colorizer</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker" target="_blank">Code Spell Checker</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=salbert.copy-text" target="_blank">Copy Text</a></li>
<li>(Test) <a href="https://marketplace.visualstudio.com/items?itemName=ryanluker.vscode-coverage-gutters" target="_blank">Coverage Gutters</a> - fairs very well with .Net Test Explorer</li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=heaths.vscode-guid" target="_blank">Insert GUID</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=christian-kohler.path-intellisense" target="_blank">Path Intellisense</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=johnpapa.vscode-peacock" target="_blank">Peacock</a> - colorize your window, depicted above</li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=Gruntfuggly.todo-tree" target="_blank">TODO Tree</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=pflannery.vscode-versionlens" target="_blank">Version Lense</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=Shan.code-settings-sync" target="_blank">Settings Sync</a> - To sync all these goodies between different machines</li>
</ul>
<div>
After all these plugins vscode still comes up fast and feels lightweight.</div>
</div>
<div>
If you have any comments or suggestions for cool plugins let me know in the comments!</div>
Unknownnoreply@blogger.com13tag:blogger.com,1999:blog-3256541113612906467.post-64579202206194780772018-12-12T07:15:00.000+02:002018-12-12T07:15:02.531+02:00Using custom health checks with Asp.Net Core 2.2 I almost burst with cries of joy when I saw the release of .Net Core 2.2 with the much needed built in and standardized health checks. The preview was great and with each version until the release new blog posts emerged eager to show to the world the new wonder. But as I do like my frameworks fully baked and released I waited patiently for the real deal.<br />
<i>TL;DR Implement your own service from IHealthCheck and inject it with whatever you want. It just works!</i><br />
<h3>
Reading the instructions...</h3>
<div>
The best article I found for the new healthcheck API was <a href="https://blogs.msdn.microsoft.com/webdev/2018/08/22/asp-net-core-2-2-0-preview1-healthcheck/" target="_blank">this one</a> based on preview code and the best code samples where of course the <a href="https://github.com/aspnet/Diagnostics/tree/release/2.2/samples/HealthChecksSample" target="_blank">official samples</a>. However by looking at them something was missing. So I went on a quest to achieve what suited my needs. And my needs are simple. I need to be able to inject some testing code to my custom health check module.</div>
<div>
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjWqFMeP0HmaPT61gOCCeTzHw_k2foyqLJecC2WKAWbHAMlHefhqM94NiGRumQM82pd_f958Y6fMKIUGHHa3_0WY_y2g2y6arHB9mYZOZxTTrKnaqlu2XKM_OSh96ajl4TTAtZei71o7s/s1600/pexels-photo-48604.jpeg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="408" data-original-width="640" height="408" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjWqFMeP0HmaPT61gOCCeTzHw_k2foyqLJecC2WKAWbHAMlHefhqM94NiGRumQM82pd_f958Y6fMKIUGHHa3_0WY_y2g2y6arHB9mYZOZxTTrKnaqlu2XKM_OSh96ajl4TTAtZei71o7s/s640/pexels-photo-48604.jpeg" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Healthcheck for your .Net Core2.2 Services</td></tr>
</tbody></table>
<h3>
On to the code</h3>
<div>
After I practiced a little bit with the concept of tags I just added a health checking service to the standard DI container as such</div>
<div>
<script src="https://gist.github.com/AlbertoBN/1540721a86220324539f408490eb4974.js"></script></div>
<div>
Oddly enough it was as simple as that. It worked right out of the box. And you can still use tags and different kinds of routing paths for liveliness and readiness checks. This way the actual health check and all the code that comes with it, database checks, broker connection checks, (put you check here) is decoupled from the actual <i>IHealthCheck </i>interface implementation. This way you can break your individual external resources checks on different classes, DI them to the interface implementation and keep your concerns separated and your code clean and concise. </div>
<br />
<br />
And of course for your coding pleasure you can download the code from <a href="https://github.com/AlbertoBN/Core2.2HealthCheckDI" target="_blank">here</a> and navigate to "http://localhost:5000/health". Press F5 a few times and the call will return sometimes "Healthy" and some times "Unhealthy"<br />
<br />
Enjoy!
Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-3256541113612906467.post-73069605382151241362018-12-05T23:45:00.000+02:002018-12-17T15:41:35.768+02:00Running an Asp.Net Core 2.* Web API as a Windows Service At my current workplace there is a healthy hunger for new technologies and a pragmatic view of the software industry in our corner of the planet. As a Microsoft driven shop, previous reservations of moving to different ecosystems and operating systems have melted away with the arrival and wide adoption of .Net Core. After all the language is the same. The developers need "only" to catch up on their containers. When I joined a month ago as a tech lead, little did I know that putting my money where my mouth is would mean having to deal with outdated Microsoft documentation or even S.O answers to questions such as "How do I run an Asp.Net Core app as a windows service without IIS".<br />
<i>TL;DR add a reference to the NuGet package <a href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.hosting.windowsservices?view=aspnetcore-2.1" target="_blank">Microsoft.Aspnetcore.Hosting.Windowsservices</a>, publish and register your executable as a service.</i><br />
<h3>
A Prophecy?</h3>
<div>
Almost a year ago I wrote a blog post about porting <a href="https://www.albertobarnoy.blog/2017/12/how-to-port-net-framework-project-to.html" target="_blank">full framework projects to core</a>. Ever since I have written my share of .Net Core, Python and Bash script code, all happily deployed mostly on a Kubernetes cluster and if not as such then to a Cloudformation on AWS over Linux images. Life was good and scripts where flowing on the wires of communications and then life being life I had to look for a new place to work. To make a long story short, I get to lead a group of developers on how to port <a href="http://topshelf-project.com/" target="_blank">TopShelf </a>based services to .Net Core and have them run as windows services (containers are down the road, until then windows services it is), as well as redefine the system's architecture and apply it little by little on a mission critical production system.</div>
<div>
<br /></div>
<div>
One of the ports is a WCF service turning REST over .Net Core. Nevertheless it still has to run as a service. The port was fairly easy, the code works like a charm. I had my <a href="https://swagger.io/" target="_blank">Swagger</a> setup and my client stubs ready with <a href="https://github.com/RSuter/NSwag" target="_blank">NSwag</a> and it was time to deploy.</div>
<h3>
Eeny, meeny, miny, shift delete...</h3>
<div style="text-align: left;">
Go ahead and type "How to run ASP.Net Core as a service" in your favorite browser. Most likely the first results page will include these links</div>
<div style="text-align: left;">
<ol>
<li><a href="https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/windows-service?view=aspnetcore-2.2" target="_blank">A Microsoft article</a>. This should be the ultimate guide right? Wrong!</li>
<li><a href="https://dzone.com/articles/running-aspnet-core-application-as-windows-service" target="_blank">A DZone post</a>. Informative but... no.</li>
<li><a href="https://gunnarpeipman.com/aspnet/aspnet-core-windows-service/" target="_blank">This blog post</a>. Nope</li>
<li><a href="https://www.c-sharpcorner.com/article/host-an-asp-net-core-application-as-a-windows-service/" target="_blank">This blog post</a>. How about... no.</li>
<li>A plethora of Stack Overflow answers.</li>
</ol>
All the above revolve more or less around the same answer in different versions of Asp.Net Core 2, ranging from preview to 2.2. The gist of it is: Add a platform RID (such as win7-x64) in your project file, add some attributes denoting if the deployment mode is <a href="https://docs.microsoft.com/en-us/dotnet/core/deploying/" target="_blank">framework dependent or self contained</a> (self contained is a good idea with some caveats... read through carefully), compile, publish and use the <a href="https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/sc-create" target="_blank">sc create command </a>to register your service.<br />
<br /></div>
<div style="text-align: left;">
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYgtF0AyEezFSM9DULPTfl5I0wHTIFWZ8xO-NbJIH_qrtV-Fb-7i64ge1sPwTyZ5jCiUzT3_AM8SoR-UGmPu0hMdPgqjNgjzsvtT1nVX7Uo2uBfb6ZAtsrJVT8tIfeKf4KyHsWtTZ6Rzw/s1600/pexels-photo-257736.jpeg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img alt="" border="0" data-original-height="425" data-original-width="640" height="424" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYgtF0AyEezFSM9DULPTfl5I0wHTIFWZ8xO-NbJIH_qrtV-Fb-7i64ge1sPwTyZ5jCiUzT3_AM8SoR-UGmPu0hMdPgqjNgjzsvtT1nVX7Uo2uBfb6ZAtsrJVT8tIfeKf4KyHsWtTZ6Rzw/s640/pexels-photo-257736.jpeg" title="Me trying to wire up (or conjure) the correct parameter combinations" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Me trying to wire up (or conjure) the correct parameter combinations</td></tr>
</tbody></table>
<div>
<h3>
Read the manual they said</h3>
</div>
<div>
After following the steps described in each post carefully results varied. I had a file named <i>apphost.exe </i>which was supposed to be the bootstraper for the service DLL but threw an error all the time. And then I didn't or the self contained deployment went awry with some modern DLL hell over .Net Core 2.1 vs 2.1.6 update. </div>
<br 4="" a="" and="" at="" blood="" change="" coffee="" comments="" day="" do="" file="" full="" half="" have="" i="" in="" is="" list="" mess="" my="" namely="" not="" number="" of="" on="" one="" point="" programs.cs="" project="" replaced="" s="" spent="" suggestions="" that="" the="" this="" to="" tutorials="" visual="" was="" with="" work="" />
One of them (namely number 4 in the list) suggested to change the <i>netcoreapp2.1 </i>moniker to <i>net461 </i>in order to produce an executable that could be run as a service, which is quite the opposite of going with .Net Core in the first place. All other posts suggested that by following their instructions an executable file (yes .exe) will be produced. That sounded (or rather read) very odd to me. .Net Core does not produce executable files.
<br />
<br />
<div style="text-align: left;">
I decided to cleanup my code but leave the additions for running as a service as well as the </div>
<i><a href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.hosting.windowsservices?view=aspnetcore-2.1" target="_blank">Microsoft.Aspnetcore.Hosting.Windowsservices</a> </i>package , delete the extra properties in my project file, build, publish and see what is produced... And there it was, like an uncut diamond fresh out of a volcano... A .exe file produced out of a .Net Core project. I opened the command line and after a few seconds there it was. An ASP.Net Core, lean, mean Kestrel based, Windows service. <b>Success!</b><br />
<br />
<h3>
Lessons (re)learned</h3>
<div>
In the jolly days of MFC I used to be skeptic of complicated solutions in Microsoft's web sites and documentation mainly because experience had taught me that they usually did not really work. Not even in the examples attached to them (I wonder in whose environments they did work though). This incident threw me back 20 years. Now I am back to being skeptic about the solutions provided in these docs. At least this time around I had the experience to think out of the box.</div>
<div>
<br />
<div>
Finally, lest I forget, <a href="https://github.com/AlbertoBN/WebApiWinService" target="_blank">the link to a working solution</a>. Happy Coding!</div>
</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-3256541113612906467.post-46537551172834823362018-03-05T10:18:00.002+02:002018-04-11T12:10:38.745+03:00Adjust the message to the audienceA couple of weeks ago had my first public speaking chance. Two 12 minute sessions TED style, in front of an audience between 20-70 years old and non technical. Each sitting had 100 people. The session was about crypto/virtual currencies, real money and everything between them. 12 minutes, non technical, make the message count. Go! <i>TL;DR It was a success and K.I.S.S</i><br />
<h3>
Version 1</h3>
<div>
The first version, presented to the other lecturers of the evening for feedback, was rejected by the second slide. The words Bitcoin Mining were present in the slide. Shot down in flames? Yes. Discouraged? No. Slightly depressed. Yes.</div>
<h3>
Version 2</h3>
<div>
Imagine... A world without bank accounts.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdPDVtMsq7U0nIN3xtXmsduQn_0tFGQNIVhXlmajvJ1A7VN-8Oz4OngazlI5DxsDH5BnXjQHrtK2KAQIZZzYGkZqCvyCLQzaRN4Y5VUWOaLI9s34ck8lbHLQmZ9hkXqXgUR0WAgkZAyMg/s1600/pexels-photo-355952.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="444" data-original-width="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdPDVtMsq7U0nIN3xtXmsduQn_0tFGQNIVhXlmajvJ1A7VN-8Oz4OngazlI5DxsDH5BnXjQHrtK2KAQIZZzYGkZqCvyCLQzaRN4Y5VUWOaLI9s34ck8lbHLQmZ9hkXqXgUR0WAgkZAyMg/s1600/pexels-photo-355952.jpeg" /></a></div>
<div>
<br /></div>
<div>
Yes this is more or less how it started. as a story... with the song <a href="https://youtu.be/VOgFZfRVaww" target="_blank">Imagine</a> playing in my head. I took my super technical slide deck and turn it into a story. How did I do it? Well I was given a tip. Tell a story. </div>
<div>
<br /></div>
<div>
<i>Disclaimer: The "tips" here work for me. They are part of my experience. I suggest searching the internet for more tips and strategies and find out what works for you.</i></div>
<h3>
The blog post that was never published </h3>
<div>
What am I having fun doing, except coding, to express myself? Blog! </div>
<div>
So I wrote the whole session as a blog post, as such:</div>
<div>
<ul>
<li>Made a note of the main concepts I wanted to convey as headers</li>
<li>I wrote the contents of each header and had the flow as I would flow a blog post</li>
<li>I compared the outcome to the existing slides, erased all slides but the last one. It was as I wanted it to be from the beginning.</li>
<li>I added each header and its contents as notes in empty slides.</li>
<li>I made the slides. </li>
</ul>
<h3>
Practice makes... well different every time</h3>
<div>
I started practicing and taking time to see if I am making less than the 12 allotted minutes. Why less? Because while telling a story some new details may creep in. So here I am on my 10 minute comfort zone when I realized... Every time I go through the same slides, what runs through my brain is the same ideas but what comes out of my mouth is completely different. And this is the moment I knew that I am on the right track for the specific task and audience.</div>
<div>
<br /></div>
<div>
And so I realized that the key to a successful session is to know how to adjust your slide deck and message to your audience and the occasion this audience has gathered for.</div>
<h3>
Run it for feedback.. and breath</h3>
</div>
<div>
I practiced, run it for feedback...Success!!! I got thumbs up from all the lecturers...</div>
<div>
Now you might (or not) ask how it went? Well... You will have to wait for the video but *spoilers*... It was a great success! In the mean time...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLanlusZxd40s7r0ou9homXhXiNL_Y01k824OKcyYdrMgjzRO8tm0FV2E_mTytC5S8mAQT60hgQMg7EZ6irMbs5AJkWy0HNRP7AD1_k6rLEdrekE3qAg14qt5egHybQ7tJc5J6anw2RtI/s1600/WhatsApp+Image+2018-02-17+at+20.28.01.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="800" data-original-width="1599" height="319" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLanlusZxd40s7r0ou9homXhXiNL_Y01k824OKcyYdrMgjzRO8tm0FV2E_mTytC5S8mAQT60hgQMg7EZ6irMbs5AJkWy0HNRP7AD1_k6rLEdrekE3qAg14qt5egHybQ7tJc5J6anw2RtI/s640/WhatsApp+Image+2018-02-17+at+20.28.01.jpeg" width="640" /></a></div>
<br />
Update<br />
Here is a video with subtitles of that speech<br />
<br />
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/xtB9gUxV9Q4/0.jpg" frameborder="0" height="315" src="https://www.youtube.com/embed/xtB9gUxV9Q4?feature=player_embedded" width="560"></iframe></div>
Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-3256541113612906467.post-91649982325269778972018-03-03T11:42:00.003+02:002018-03-05T12:13:04.068+02:00Binding yourself to high level design by details - irrevocablyLittle over half a year ago I was present in an unprecedented blunder by a team leader. I saw how the fervor to succeed made for a design mishap and how the same fervor made for a Mr. Know It All team leader. <i>TL;DR detailed designs are for devs, not VPs or CTOs</i><br />
<h3>
How to not design like a galley master and not be shackled like a rowing slave</h3>
<span style="font-weight: normal;">When one is asked to make the design document of a new development, one must be very very careful how flows are put on paper. These documents are binding and every word or terminology in them can and will haunt one for a long time. In order to try to minimize a possible mess here are some rules of thumb, gathered from my own experience</span>
<br />
<h4>
Detailed documents glide up like migrating birds</h4>
<span style="font-size: small; font-weight: 400;">High level design documents may and will end up to the higher ranks of the corporate hierarchy. Be vague when describing functional parts. Do not put highly detailed implementation details in a high level design, otherwise once the details are stated and a VP of anything has seen it stated then everything is bounded to it and surround it. Changing that code will be next to impossible for a long time. Document your high level design but keep the fine details of implementation out of it. By all means however address all fine details of requirements.</span><br />
<h4>
State your terms of surrender... clearly</h4>
Agree on terminology. For example one can break things to fragments or chunks. Use either or. Always remember that although no one is perfect at naming flows, classes, modules or methods things do tend to stick. Using two names for the same thing will make a mess. Choose one term and stick to it.<br />
<h4>
Be the master of your diagram</h4>
Highly detailed UML diagrams are hard to read. Prove your mastery at design by capturing the essence of a flow in as few lines of drawing as possible. Highly detailed diagrams on high level designs make for poor mastery and bind you irrevocably. There is merit in vagueness. It keeps you flexible to architect your code as you like while keeping you inline with your high level design.<br />
<h4>
Consult your team</h4>
<div>
In case you are required to perform the fallacy of putting implementation details in a high level design, do consult your team. You do not own the absolute truth. You do not know it all. You are human. Ask for your teams ideas. They are there not only to code a product but to have fun and participate.</div>
<h4>
Consult the internet</h4>
<div>
If you made it to team leader and you don't have a steady stream of tech blogs or publications to read on some spare or dedicated time then go and do it. It is inconceivable to not do so at this stage of your career. I am not saying to be like me, coding at home and having a blog. I am saying, stay updated and on top of your game. Not every solution or post may fit you, at least not today, maybe not ever, but ideas and solutions will come easily if you do keep up with tech rather than not. </div>
Unknownnoreply@blogger.com3tag:blogger.com,1999:blog-3256541113612906467.post-39170244046109955692018-01-18T18:08:00.000+02:002018-01-18T18:08:05.750+02:00Public speaking - baby stepsSometime last year I decided that I too have something to say to the world. This is how this blog was born. I really feel it is time to take the next step and try my luck on public speaking. <i>TL;DR this is not long hang in there. </i><br />
<h3>
Where to start</h3>
<div>
There isn't really a recipe or a user guide on that one. One can start on meetups, try one's luck on a conference out of the blue... Just take your pick. </div>
<div>
<br /></div>
<div>
I am personally starting in my town of residence, giving a 12 minute session on cryptographic and virtual currencies to a non technical audience. These are people I see every day on my way to the country club, school, gym etc. This is as up close and personal as I could start. </div>
<div>
<br /></div>
<div>
Consider this... 12 minutes on such a subject and skip the technical jargon. This is quite a challenge! But as one tiny, great fictional green alien once said.. </div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/BQ4yd2W50No/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/BQ4yd2W50No?feature=player_embedded" width="320"></iframe></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<h3 style="clear: both; text-align: justify;">
Where to go from there</h3>
<div>
After that 12 minute challenge I plan to speak on friendlier ground. At work towards colleagues on a technical subject. One hour with code and slides. From there a meetup and a conference.</div>
<div>
<br /></div>
<div>
Wish me luck!</div>
<div>
<br /></div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-3256541113612906467.post-57618761554189455282018-01-13T19:15:00.000+02:002018-01-13T19:26:46.953+02:00Applying an internal forums system in the company culture - thoughtsLong gone are the days where, as children, we used to tie a string to two boxes and shout messages at each other. Communication for some of us has changed from phones with a round dial to smartphones in a decade.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyOOS9hf2bDRIzGdSsqGX1oOkJlZUx_hV218BhwvJug4cBRzSp87wKF7E8VsVfoO_WeMKQ1u-XC0m8XC9aitI_96gWr4xWyR3b2y0xh5CJfZU21fvJ1vIvltYdpHdkBvVOnAu_HB4coeM/s1600/marketing-man-person-communication.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="426" data-original-width="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyOOS9hf2bDRIzGdSsqGX1oOkJlZUx_hV218BhwvJug4cBRzSp87wKF7E8VsVfoO_WeMKQ1u-XC0m8XC9aitI_96gWr4xWyR3b2y0xh5CJfZU21fvJ1vIvltYdpHdkBvVOnAu_HB4coeM/s1600/marketing-man-person-communication.jpg" /></a></div>
<br />
Having worked in several places with a mobile based solution for groups of teams and dev departments forum/chat system as well as a couple of places with an internal forum/social media system in place, I have seen more often than not that the adoption rate of such a system is diverse. Some like it, some not and some participate on a whim. And in some places it is obligatory.<br />
<br />
However what happens when you find yourself accustomed to such a system and arrive at a place where there was none, and one is being applied. How does an organization make the shift from coffee machine pow wows to an internal forum/social/chat board. <i>TL;DR Success of such a forum depends on... oh quite a few factors</i><br />
<h3>
It is not the medium, it is the content</h3>
<div>
This is not a post on the different solutions out there. I am sure that a quick search on your favorite engine will produce quite a few results. Neither do I disdain from mobile (as in id by phone number) based group chat solutions. They serve their purpose but do not fit a company wide approach. </div>
<div>
<br /></div>
<div>
What sort of content does a company expect to be presented and discussed upon in such a forum? The answer is "it depends". It depends on the company culture and philosophy, it depends on the ultimate purpose of management, it depends on the content makers.<br />
<h3>
Content makers</h3>
</div>
<div>
Content makers are the people in a company who enjoy sharing articles, opinions or even blog. It is useful to know who might these people be and involve them early in the process. These are the people who will create an initial hype, but also keep the fire burning. Down the road more employees will be involved. More but not all. Some may even mute the system or never log in. Again depending on the company and the company culture, this may or may not be OK. Regardless it will never be a 100% involvement. We may be social animals but some are less than others. </div>
<div>
<br /></div>
<div>
A word to content makers: Do not overdo it. Less in high quality is more than a lot in low quality. </div>
<h3>
Content</h3>
<div>
Encourage content makers, the ones you new about before hand and the ones emerging down the road. Make focused channels on topics of general interest. Set boundaries, monitor and enforce them. Delete and discourage low quality content. Forbid politics, strike out ethnic and religious remarks (a company may be many things but by no means is it a democracy) and make sure the language is clean. Allow for healthy jokes and banter. Make public announcements in the system as well as by email. Make people own the content they post. And give it time.<br />
<br />
Sometimes a contest may be announced to make people involved. This won't last much. Coffee machine pow wows discussing content from the forum, however, will.<br />
<br />
And with that in mind I am off to pour content in such a system. ;) </div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
Unknownnoreply@blogger.com3tag:blogger.com,1999:blog-3256541113612906467.post-21713832046273863092017-12-31T15:33:00.001+02:002018-01-04T17:59:41.855+02:00How to port a .NET framework project to .NET Core including tests - A GuideSo you want to port your project to .Net Core and don't know how? Are you reluctant to let go of your traditional .Net Framework targeting but want to have a taste of the new .Net buzz? Is the information on the subject incomplete or too confusing (yes it usually is). Well you have come to the right place. <i>TL;DR This is guide. It will hopefully save you time. Rejoice.</i><br />
<h3>
A tale of two frameworks (well actually 3) </h3>
I will make this one short and sweet and let this article tell the tale. I recommend to read this article before you continue: <a href="https://msdn.microsoft.com/en-us/magazine/mt842506.aspx" target="_blank">.NET Standard - Demystifying .NET Core and .NET Standard</a>.<br />
<h3>
To port or not to port</h3>
<div>
It depends</div>
<div>
<ul>
<li>If this is your production code and there is no prospect to run it in a platform other than windows then maybe not. </li>
<li>If it is a huge complicated project then maybe not</li>
<li>If it is your open source baby maybe yes</li>
<li>If it is a new project and you see the benefit of it being cross platform maybe yes</li>
</ul>
<div>
The considerations are many and it is up to you to decide. In any case here is what you need to do.</div>
</div>
<h3>
API Portability</h3>
<div>
First of all start with this handy tool: <a href="https://marketplace.visualstudio.com/items?itemName=ConnieYau.NETPortabilityAnalyzer" target="_blank">.NET Portability Analyzer</a>. It will tell you which API is portable and which is not, to what extent and percentage and what is the alternate API to use. Solutions to less than 100% portability will be briefly discussed further below.<br />
<br />
If the solution is too big then it may be wise to check the portability on a project by project basis. At the end of each analysis an .xlsx file is produced with two sheets and the results.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuFUSOg5uBM-pmvPnzzQsSolZxWn_FzJZrr5uBOo-BNA_jFtLwaNVTP_BcLT63coVuDtQcaxbfUCY03nJoN0IbRIpudEHPljib38d8LkgUXpC5AFLabZtpyXa1a10xPw1QSKaI_K9Zpi4/s1600/API+Portability.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="382" data-original-width="836" height="291" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuFUSOg5uBM-pmvPnzzQsSolZxWn_FzJZrr5uBOo-BNA_jFtLwaNVTP_BcLT63coVuDtQcaxbfUCY03nJoN0IbRIpudEHPljib38d8LkgUXpC5AFLabZtpyXa1a10xPw1QSKaI_K9Zpi4/s640/API+Portability.png" width="640" /></a></div>
<br />
<put example="" here=""></put>
The upper part of picture shows the first sheet of an API portability analysis. Interesting enough a project originally built for .Net framework is 60% portable. The lower part shows which APIs are supported in each .NET flavor if at all. The analyzer works for both VS 2015 and VS 2017.</div>
<h3>
Multitargeting or just port</h3>
<div>
You may multi-target your project instead of just port it and do the porting little by little on a development branch. One one hand this way you will have more control over the process. On the the hand you may have to use too many preprocessor definitions, depending on the functionality of your application. This is beyond the scope of this post but well within the scope of your analysis on the cost of porting your code.</div>
<h4>
Multitargeting and tooling</h4>
<div>
There is none. After you multi-target your project file in the project properties under Application you will notice that the target framework is disabled</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggvEaq2Cu7z2G7Rs2FYqn51_lN6xhJ1f5OEmQIX5AKFN97eSb7OL6CTqGsIZtDXWRXAq2W3Qf5tdKuBxwS1jpnCTR1_1o8jFBmOA5vD4cqZ-hooyvQBx7o3tXB3YPeCj-z-6g4NF76-t8/s1600/Capture.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="59" data-original-width="316" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggvEaq2Cu7z2G7Rs2FYqn51_lN6xhJ1f5OEmQIX5AKFN97eSb7OL6CTqGsIZtDXWRXAq2W3Qf5tdKuBxwS1jpnCTR1_1o8jFBmOA5vD4cqZ-hooyvQBx7o3tXB3YPeCj-z-6g4NF76-t8/s1600/Capture.PNG" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
This means that on each compilation all targets will be compiled. This also means that you are actually supporting at the same time your legacy and new code as well. It does not mean however that all is smooth. While multi-targeting you may need to use preprocessor definitions to wrap code relevant to your targets. <example here=""></example></div>
<h3 style="clear: both; text-align: justify;">
How to setup your project file</h3>
<div class="separator" style="clear: both; text-align: justify;">
In contrast to the old .csproj file with .Net Core you need not define each and every code file in the project file. The IDE scans the directories and files adjacent to the project file and adds them to the project. </div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
A typical .Net Core project file would start off as such</div>
<div class="separator" style="clear: both; text-align: justify;">
<script src="https://gist.github.com/AlbertoBN/8b8cc1c054767de08509dc46991a3d3c.js"></script></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Whereas a multitarget project will look as such</div>
<div class="separator" style="clear: both; text-align: justify;">
<script src="https://gist.github.com/AlbertoBN/71b1337e0c630e82e6a63df61ac73ea1.js"></script></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
The .Net Core project has only one <i>TargetFramework</i> whereas the multitargeted has <i>TargetFrameworks </i>in plural. The project depicted above supports Core 2.0 and framework 4.6.1. Notice that each framework defines, in subsequent property groups, dependency assemblies versions. These are updated and added by Visual Studio as you add references along the lifetime of your project. In existing projects update packages via NuGet and let the IDE do its magic.</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
And that's it. From here on it is a matter of choosing the correct preprocessor definitions while you code. A very good article by Microsoft describes all that in more detail (and for some reason search engines rank it lower than some blogs) <a href="https://docs.microsoft.com/en-us/dotnet/core/tutorials/libraries" target="_blank">Developing Libraries with Cross Platform Tools</a></div>
<h3 style="clear: both; text-align: justify;">
Handling tests and solutions files</h3>
<div class="separator" style="clear: both; text-align: justify;">
Once you have your project file setup, open it and fix any compilation errors and make sure it compiles for all targets. Once that is done save the new solution file created automatically for you by the IDE. You will need it in order for the ported test project to reference your codebase. </div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Next create a project file for your tests and put it in, like the regular project file, adjacent to the code files and directories of the tests. This should look like as such</div>
<div class="separator" style="clear: both; text-align: justify;">
<script src="https://gist.github.com/AlbertoBN/bcfd9b1ab4103c238417ae52ef764c4b.js"></script></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
It is not however created manually. The <i>dotnet</i> cli will do the hard work for us as described in this article <a href="https://docs.microsoft.com/en-us/dotnet/core/testing/unit-testing-with-mstest" target="_blank">Unit testing C# with MSTest and .NET Core</a>. The article assumes you have a solution file. I used MSTest but you can use a number of unit testing frameworks as depicted on the navigation tree on the left hand side of the article. </div>
<h3 style="clear: both; text-align: justify;">
Final advice</h3>
<div class="separator" style="clear: both; text-align: justify;">
It is advisable to give a different name to your project files while porting. This way you will not be confused if you have to open your project with the old project files for some reason. Also please notice that .Net Core produces a .dll file and not a .exe file. It is runable by using the <i>dotnet</i> cli.</div>
<h3 style="clear: both; text-align: justify;">
Credit</h3>
<div>
The incentive to venture into porting a .Net Framework project into .Net Core came to me after an Alt.Net meetup where I saw a small project for mutation testing. The project uses Roselyn to alter the code under test. If the test still passes then it actually does not test something meaningful. If the test fails upon code mutation then the test is considered correct and robust. The project is called <a href="https://github.com/nirroz/SentinelSharp" target="_blank">SentinelSharp</a> and is developed by Nir Rozen. </div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-3256541113612906467.post-12358223690346987342017-12-25T10:21:00.001+02:002017-12-26T10:14:30.377+02:00It's been a hard year's... coding - Happy Holidays 2017!I have found myself lately learning all sorts of new things. I am mostly using this very known video courses web site. Every course is between 5-10 hours broken down to sections and clips. And this is when my mind goes blank <i>TL;DR sometimes you need to take a break.</i><br />
<i><br /></i>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6gRvAhHSgdNGCE-oAaHI4Fymz4K1VNId-mR9YKYt-coEDJq31IGgOlRkvcuI-0THsCVKtJwzMMxZag3-sJi-19PQQRUarxxEBFIgDHip_ByWDMrg0-ZTNK99R17UiJRplAmI3Gatc5zw/s1600/pexels-photo-712320.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="423" data-original-width="640" height="420" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6gRvAhHSgdNGCE-oAaHI4Fymz4K1VNId-mR9YKYt-coEDJq31IGgOlRkvcuI-0THsCVKtJwzMMxZag3-sJi-19PQQRUarxxEBFIgDHip_ByWDMrg0-ZTNK99R17UiJRplAmI3Gatc5zw/s640/pexels-photo-712320.jpeg" width="640" /></a></div>
<i><br /></i>
<br />
<h3>
Take your brain to.. golf</h3>
<div>
Regardless on whether you are coding, reading a technical book or taking an online course at some point or another you may find yourself being stuck on he same lines of code, or paragraph in a book, or rewinding the video of that course. This is it; your brain has had enough. You need to "F5" your brain cells. And this you do by either getting up and taking and stroll around the cubicles or get out in the open air and have your eyes look towards the horizon.. or.. whatever makes your brain disconnect for a while from the task at hand.<br />
<br />
So towards the new year and in the midst of the holiday season and the time resolutions are being made through the best intentions of being kept, make one for your self... Learn when to take a break and take your brain off the every day/hour focus. Take a ten minute break on the hour, take a day break in the month, take a holiday... Think and retrospect... Live long, prosper and be strong.<br />
<br />
And in that spirit.. this is me... taking a break from it all in hazy shades of winter ;)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijd1XGThy4tJ6pct-jTvgrJFnxorMHwc8EUrBSYF3PUKZqmHVQfPESWULLZsAoz3J5S2ddVa3bKAalRQ_R2ylTELUcnUKCguZkHiBuOVZmOMvZJuhL67VPRm1WZCL645lX95QwI6z8kiQ/s1600/IMG_20171223_144332.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1600" data-original-width="1200" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijd1XGThy4tJ6pct-jTvgrJFnxorMHwc8EUrBSYF3PUKZqmHVQfPESWULLZsAoz3J5S2ddVa3bKAalRQ_R2ylTELUcnUKCguZkHiBuOVZmOMvZJuhL67VPRm1WZCL645lX95QwI6z8kiQ/s640/IMG_20171223_144332.jpg" width="480" /></a></div>
<br />
<br /></div>
<div>
Have a very Merry Christmas/Belated Hanukkah and a Happy New Year! </div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-3256541113612906467.post-74047657109545967912017-12-11T13:03:00.000+02:002017-12-26T10:12:16.645+02:00On job hunts and recruitersJob hunting for a software developer is a full time job. One polishes and hones one's skills and CV, scours the placement advertising sites and goes out to the world to seek one's next challenge. Ever since the late '90s of the previous century some things have changed and some have not when it comes to looking for a new job. <i>TL;DR tech recruiters have changed</i>.<br />
<h3>
Online presence and you</h3>
<div>
Towards the end of the last century all we had was CVs and not so polished web sites to send our CVs to. Placement companies did their best to make their sites shiny and down the road they even had job posts online with an appropriate submit button to post your CV for a position. In time they also made agents for you to set your job preferences and have the agent send you a notification when a relevant search came up with results.</div>
<div>
<br /></div>
<div>
And then somewhere in the second decade of the new century something changed. Your online presence became much more important, not only when looking for a job.Your professional profile on <a href="https://www.linkedin.com/in/albertobarnoy/" target="_blank">LinkedIn</a> became significant. Not only as an online CV but also on what you comment or even post. Your picture on that profile became important. Should you have a professional picture or a casual one? It all came down to what you want to communicate to any one interested in you. Some recruiters or potential employers would look into your public profile. Some of them would be so bold as to look in your Facebook profile as well (this is why you should have your privacy settings well considered on Facebook by the way).</div>
<div>
<br /></div>
<div>
Fast forward on the years and LinkedIn headhunting became a thing. And some recruiters became "sourcers" (as opposed to sorcerers ;) ), which if I understand correctly aim to scour social media in general and hunt for candidates for that exclusive position they have to offer. There are also mobile applications where you have to create a profile similar to LinkedIn so that recruiters can approach you. Such applications are popping up like mushrooms. They promise to be the next best thing in job placement. </div>
<div>
<br /></div>
<div>
At the end of the day though it all comes down to you. Are your skills properly set and defined (both in your CV and online presence), do you participate in open source projects, do you have a public <a href="https://github.com/AlbertoBN" target="_blank">GitHub</a> repository, do you have a <a href="http://www.albertobarnoy.blog/" target="_blank">blog</a>, do you update your open source projects, blog or repositories often enough? These forms of online presence can get you a long way towards finding a job. A lot more than a mere landing page with your CV pasted on it. Some recruiters or employers will like the fact that you code outside working hours. Some will not. It is up to you to choose which employer is good for you. Today's developers have to have a stronger online presence beyond a professional profile in order to get a job. It is not only about honing your skills and having fun. It is more than that; like it or not you are responsible for the marketing of the product of <b>you </b>(and if you are a freelancer this is twice as important).<b> </b></div>
<div>
<b><br /></b></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8bVzMCOlZZxIiwpEp06BSpKFDQfhe5XQTrV24wGBKTzMxp-sYsyKiWtKY8RjIPJ_hVc3fjA8IoDxdOTGWipSt6K3-ASfNxsQfaDEfFiYKOUJiz9WP6PlYiN42Kz6HaVqg_zV9_8Yyiyw/s1600/pexels-photo-684314.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="452" data-original-width="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8bVzMCOlZZxIiwpEp06BSpKFDQfhe5XQTrV24wGBKTzMxp-sYsyKiWtKY8RjIPJ_hVc3fjA8IoDxdOTGWipSt6K3-ASfNxsQfaDEfFiYKOUJiz9WP6PlYiN42Kz6HaVqg_zV9_8Yyiyw/s1600/pexels-photo-684314.jpeg" /></a></div>
<div>
<b><br /></b></div>
<h3>
Recruiters and you </h3>
<div>
Recruiters are not tech people. They know nothing about multithreading or servers. ASP.NET or ES6. They mostly get a list of buzzwords and ask you over the phone (or scan your CV) for them. Few are those who make the effort to understand which buzzwords are client or server related, which technologies mean server or web and I can't blame those who don't. But in the end of the day they are but people like you and me. Be communicative, be nice. They are trying to get you a job. Work with them and not against them. And be communicative. Did I mentioned be communicative? Be it then. </div>
<div>
<br /></div>
<div>
Never do a no show in interviews without proper notice well in advance. You may be late for an interview due to reasons beyond your control but an un-notified no show reflects bad on you and the recruiter. Your marketing representative cannot market the product of you if you do not show up on the "shelf" promptly or at all. Your rep looses credibility and so do you.</div>
<div>
<br /></div>
<div>
Be polite to potential employers on the phone. No matter how they sound over the phone or what they say, go with the flow. You can and have to give feedback about them to the recruiter but never ever to a potential employer. Doing so will burn you bridges. Both with the employer and the recruiter.</div>
<div>
<br /></div>
<div>
Be culture aware. If this a relocation job or you have relocated and seek for a job in a country not your own be aware of the cultural differences in recruiting. This will get you a long way. And what is acceptable back home may very well be bad form elsewhere.<br />
<br /></div>
<div>
</div>
<div>
Be clear of your intentions and the positions you seek. If you have met (mostly over the phone) recruiters that you connect better with, add them to your professional contacts in the platform of your choice. They are keepers. You will want to work with them again and again.</div>
<h3>
Conclusion</h3>
<div>
If you are a frequent reader of this blog you know I don't usually do conclusions, but I feel the need to do one in this case. So to conclude when job hunting:</div>
<div>
<ul>
<li>Have a solid online presence. This is built over time and not for job hunting only. If it is as such it shows.</li>
<li>Be communicative to recruiters.</li>
<li>Be polite to potential employers.</li>
<li>Be specific and precise on what you seek. </li>
</ul>
<div>
<br /></div>
</div>
<div>
<br /></div>
<div>
<br /></div>
Unknownnoreply@blogger.com17tag:blogger.com,1999:blog-3256541113612906467.post-69723227885952006222017-12-06T21:40:00.001+02:002017-12-06T21:40:08.530+02:00Distributed monolith - a microservices nightmare<div dir="ltr">
"... and then the interviewer <i>coined</i> an expression. I stared wide eyed as it hit me... microservices or not the monolith looms behind every feature... and it is a distributed monolith" <i>TL</i><i>;DR </i><i>not what y</i><i>ou think read on.</i></div>
<div dir="ltr">
</div>
<h3>
From monolith to microservices to monolith</h3>
What is it that fascinates developers all over the world with microservices? Some say it is the separation of concerns into tiny services focused on one task. Some say it is the scaling capabilities the architecture provides. Others like the fact that there is no single point of failure. Or is there? I came across <a href="https://www.microservices.com/talks/dont-build-a-distributed-monolith/">this video and article</a> by Ben Christensen about the perils of a miscoservice architecture to become a distributed monolith. And then it hit me. It is not only what is described in the article as signs and perils of a distributed monolith.<br />
<div dir="ltr">
<br /></div>
<div dir="ltr">
Consider a set of microservices "perfectly" orchestrated. They each pass around different DTOs, even if duplicate ones, that can evolve in separate paths over time, 3rd party vendor services are hidden behind some microservice of your own providing a facade. There is sufficient code reuse but also purposeful code duplication to prevent coupling and everything is ticking like a Swiss clock.</div>
<div dir="ltr">
<br /></div>
<div dir="ltr">
Consider however the following premise; When one service fails the whole system collapses. Your services are not fault tolerant enough. This also constitutes a distributed monolith.</div>
<div dir="ltr">
<br /></div>
<div dir="ltr">
I can almost hear your thoughts saying "impossible, we check for faults, we are fault tolerant, this guy is grasping at straws". I can, almost also, see you running first thing in the morning and checking if that service you built on your last sprint is fault tolerant and won't take the whole system down with it when it fails. If it does you are not decoupled enough. In fact you are a monolith. I would add this argument to the article as well.</div>
<div dir="ltr">
<br /></div>
<div dir="ltr">
So how are your microservices faring? </div>
<div dir="ltr">
<br /></div>
<div dir="ltr">
<br /></div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-3256541113612906467.post-2855833921897143892017-11-30T18:23:00.003+02:002017-11-30T18:23:57.789+02:00.NET Core - a quick observation.NET Core is:<br />
<br />
<ul>
<li>A substantial rewrite of .NET in the making</li>
<li>A better .NET</li>
<li>A multi-platform .NET</li>
<li>A way to leverage an amazing language like C# over Linux and IoT (based on Linux)</li>
</ul>
.NET Core is not:<br />
<br />
<ul>
<li>A one stop shop - yet </li>
<li>Only for web</li>
<li>Only for cloud development</li>
</ul>
Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-3256541113612906467.post-55673650790795928482017-11-26T19:08:00.000+02:002019-09-23T16:26:41.301+03:00Evolving code and adding new technologies - Part 4In this part we will focus more on the process of changing a system architecture and the design at hand than on code. After trying different approaches in an effort to not change the architecture entirely, with no success, there is only one thing to do. Change the architecture entirely. <i>TL;DR Brace yourselves, major changes are coming. And they are good!</i><br />
<br />
For a recap here is <a href="http://www.albertobarnoy.blog/2017/11/evolving-code-and-adding-new.html" target="_blank">Part 1</a>, <a href="http://www.albertobarnoy.blog/2017/11/evolving-code-and-adding-new_13.html" target="_blank">Part 2</a>, <a href="http://www.albertobarnoy.blog/2017/11/evolving-code-and-adding-new_22.html" target="_blank">Part 3</a> and <a href="https://www.albertobarnoy.blog/2017/11/evolving-code-and-adding-new_23.html" target="_blank">Part 5</a><br />
<h3>
What this change is not</h3>
<div>
The system at hand is an on premise system. It does not run in the cloud. I dare say that it does not even run on the same network as the customer's other services. It is an island with a closed network with no access to the world outside including the client's kitchen. These things exist to the extent that remote debugging is not possible, not even plugging a USB key after installation (if there is a USB port on the machine). I plan to address debugging such systems in a post after the series is over so stay tuned ;)</div>
<h3>
About the process of changing a system's architecture</h3>
<div>
Suppose that after long months of trying to fix the system, you reach the conclusion that there is no real option than to break the monolith into separate services. Not necessarily micro-services, and I have nothing against them, but Rome was not built in one day and re-architecting a monolith will be not be done in one go either.<br />
<br />
You must remember that every time you want to make radical changes to a piece of software, you have to involve the stake holders. And they come in two flavors. Those who understand the problem and see the need for change and those who understand the problem but do not want to accept the fact that for the past few months they poured money down the drain and you produced no definitive results as far as they are concerned.<br />
<br />
In fact you are asking them to trust you and pour more money down the drain, the way they see it. You have to convince them that what you suggest is the only way. By the way if you suggested that, before the hopeless effort to fix the system and they didn't hear you now is not the time to remind them. Always remember (sadly enough) that the higher the managerial level, the more ego gets on the way and the less self responsibility is exhibited. In fact as the one suggesting the change, you have great opportunities before you, which come with great responsibility as well.<br />
<h3>
Changes in architecture</h3>
<div>
Observe the diagram below. On the left is where we are and on the right where we want to get to.</div>
<div>
<br /></div>
<div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_b2zzbWB0hZ4BDMwxMov0ES8JkdZp0FnHi3UdoqCMV7o3fslkACUo_pkfsWvZi8e9iWd8kKvVnHzlnRnPsZs4oa7TJg_HLD5dUGqZjVZ8XQmdQnINzd4YebeLt6HdfC2AWzT8hkX2H5E/s1600/InitialArchitecture-CodeEvolve+%25281%2529.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="482" data-original-width="632" height="488" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_b2zzbWB0hZ4BDMwxMov0ES8JkdZp0FnHi3UdoqCMV7o3fslkACUo_pkfsWvZi8e9iWd8kKvVnHzlnRnPsZs4oa7TJg_HLD5dUGqZjVZ8XQmdQnINzd4YebeLt6HdfC2AWzT8hkX2H5E/s640/InitialArchitecture-CodeEvolve+%25281%2529.png" width="640" /></a></div>
<br />
From a monolithic application holding display and processing logic mixed together we want to separate our processing blocks into separate processes. We want to separate the concerns of those building blocks and we also want to clean their code; remove dead code for example, refactor and make code leaner.<br />
<br />
What we will also achieve is the ability to individually test each building block and even run it on a different machine in order to load balance the compute resources. After all as we have seen our system is growing. Messages are pouring into our system by the thousands or hundreds of thousands. We need solid infrastructure to cache messages and allow for the individual processes to deal with the them the best possible way. We also need a queuing mechanism and maybe even a messaging system. Now I know that there are a few 3rd party products out there for the job and you can choose to use anyone you like to accomplish the task at hand. For the purpose of this series I chose <a href="https://redis.io/" target="_blank">Redis</a>. In this case a one stop shop for all our needs.<br />
<br />
One other thing to remember is that all these changes in a real system will be made little by little so you can always have a working product for a demo or a client delivery. Change small parts and write unit tests, have QA check for regressions and conduct internal acceptance tests. Control the development and the rate of bugs and be proactive.<br />
<h3>
Data Flows</h3>
<div>
<div>
One other important aspect when refactoring a system is to map the flow of data and the different use cases to be moved to other processes. This would be an excellent time to group together relevant flows and APIs and forego any circular dependencies and God Objects that most certainly have been formed throughout the lifetime of your product. It does not matter how you record these flows. It may be a spreadsheet, a document, a <a href="https://www.draw.io/">drawing</a> as long as you do it. The reasons to do this are:</div>
<div>
<ul>
<li>Create and agree on a common language with your team mates</li>
<li>Be able to measure progress by writing off the developed/refactored parts</li>
<li>Always know which changes are going to break things and for how long. Assess risks and plan your work accordingly.</li>
<li>Be able to communicate said progress to the system stakeholders and your peers in a concise way.</li>
</ul>
<h3>
Time Estimates</h3>
</div>
</div>
</div>
</div>
<div>
I may not need to say that but plan for surprises and feature creeps while you are refactoring. Add buffers in your time estimates. If you want to put on a good show and make them lean and mean you may end up death-marching to failure or gaining the distrust of the stakeholders. Give sufficient, but not too large, buffers to make them feel comfortable, but make sure the buffers are not too comforable. In these time estimates you have to be prepared for change, unit tests, code reviews and life in general. It may sound impossible but remember, you are supposed to know the strengths and weaknesses of your team. </div>
<div>
<h3>
Working with Redis - A Prelude</h3>
<div>
As a prelude for the next part, from the Redis website:<br />
<br />
<div>
<span style="color: #999999; font-family: inherit;"><i>Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache and message broker. It supports data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs and geospatial indexes with radius queries. Redis has built-in replication, Lua scripting, LRU eviction, transactions and different levels of on-disk persistence, and provides high availability via Redis Sentinel and automatic partitioning with Redis Cluster.</i></span></div>
<div>
<span style="color: #999999; font-family: inherit;"><i><br /></i></span></div>
The natural environment for <a href="https://redis.io/" target="_blank">Redis</a> is anything but Windows OSs. It is however most certainly Linux. There is a port for Windows but my favorite setup on my own rig is a Linux virtual machine running Redis and Windows processes connecting to it. When I need to see the contents of Redis I am using <a href="https://redisdesktop.com/" target="_blank">Redis Desktop Manager</a> and lately <a href="https://www.fastoredis.com/" target="_blank">FastoRedis</a>.<br />
<br />
As for a library to use in code I am using the Nuget package <a href="https://github.com/StackExchange/StackExchange.Redis">StackExchange.Redis</a>. You can also clone it from GitHub if you wish to see the way it works from the inside. In the code of this post I will not be using this library in an abstraction, however for your product you should.</div>
</div>
<div>
<br /></div>
<div>
After these words of wisdom lets pretend we persuaded our stake holders and move on.</div>
<div>
<br /></div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-3256541113612906467.post-20438819026823983252017-11-23T16:06:00.004+02:002017-12-03T20:48:57.981+02:00Evolving code and adding new technologies - Part 5The implementation of the proposed architecture is at hand. We dive into the change and see how Redis (or any other message queue or pub/sub broker) makes our life easier. <i>TL;DR Time to make the change. Read it all!</i><br />
<br />
For a recap here is <a href="http://www.albertobarnoy.blog/2017/11/evolving-code-and-adding-new.html" target="_blank">Part 1</a>, <a href="http://www.albertobarnoy.blog/2017/11/evolving-code-and-adding-new_13.html" target="_blank">Part 2</a>, <a href="http://www.albertobarnoy.blog/2017/11/evolving-code-and-adding-new_22.html" target="_blank">Part 3</a> and <a href="http://www.albertobarnoy.blog/2017/11/evolving-code-and-adding-new_26.html">Part 4</a><br />
<h3>
Components of our example</h3>
<div>
<a href="https://github.com/AlbertoBN/CodeEvolve/tree/CodeEvolve_ConcurrentQueue">GitHub branch</a></div>
<div>
<br /></div>
<div>
<div>
<div>
Our monolithic example will be divided to three processes:</div>
<div>
<ol>
<li>Producer</li>
<li>Redis (3rd party broker)</li>
<li>Consuming Processor</li>
<li>Thin client</li>
</ol>
<div>
After we are done with the change, the server will look like this:</div>
</div>
<div>
<br /></div>
<div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgy8vAVtzYonfHLuFEpCAT3otp7mKZIgscjiDNqUUXest4agFJ72kKnDu7FfKg-VuAmfKTLDYbczc_OtEcOwKBB8JES1ux4ajAwm6VGiRgXAgauvBlqIAR_5yjFRjFDuA-xva0TBfxKqeU/s1600/CodeEvolve_NewAcrhitecture.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="432" data-original-width="712" height="388" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgy8vAVtzYonfHLuFEpCAT3otp7mKZIgscjiDNqUUXest4agFJ72kKnDu7FfKg-VuAmfKTLDYbczc_OtEcOwKBB8JES1ux4ajAwm6VGiRgXAgauvBlqIAR_5yjFRjFDuA-xva0TBfxKqeU/s640/CodeEvolve_NewAcrhitecture.png" width="640" /></a></div>
<br /></div>
</div>
<h3>
On to the code</h3>
<div>
The Dataflow library from the previous part will be removed in the consumer. Now that the processes are separated the consumer is super fast up until the actual processing which takes around 1 second.<br />
<br />
The different components will work directly with Redis which will in fact be the backbone of our pipeline.<br />
<br />
Ten producers are being used to send messages into 10 Redis lists. Each list has a key named {Producer_i} where i is the number of the producer. The consumer is aware that there are 10 producers by configuration file. In an actual system this would be communicated to the consumer via an API (be it REST, WCF, or Redis Pub/Sub).<br />
<br /></div>
<div>
And so the producer will now look as such:<br />
<br />
<div>
<script src="https://gist.github.com/AlbertoBN/8f6c3a3ab5fed3041e89290446419578.js"></script></div>
<br />
The messages are being pushed in a batch but not a transaction operation. The difference being that batch may be sent to the server at once but other command may come in between. In a transaction however isolation is guarantied, at the expense of speed of course. Since each producer is sending data to its own queue batch is good enough.<br />
<br />
The consumer will now look as such:<br />
<br />
<div>
<script src="https://gist.github.com/AlbertoBN/56fef98daa3ebeb658f772c9ac79061b.js"></script></div>
<br />
<br />
Data is read serially from all producer queues in batches of 100 at a time. it is then de-serialized (between 0-10 millies per value) and then grouped and sent to the client. Data is being left in the grouped ConcurrentDictionary for no more than a minute, whereupon it is marked for deletion and deleted at every cycle. In order to emphasize how fast the system works milliseconds are used to display the amount of messages entered at a certain millisecond in the system. The lag is practically non existent to acceptable.<br />
<h3>
What is next</h3>
</div>
</div>
<div>
We could stop the series here but there is one bit that still bothers me... The client is quite passive and has only one handler to deal with the messages produced by the consumer.. Bow can the client be made less coupled with the pub/sub message handler and more versatile to the messages it displays or even the way it receives and reads them? Well stay tuned..... After the holidays the final chapter of the series will answer just this question!</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-3256541113612906467.post-20149380994264774062017-11-22T10:11:00.000+02:002019-09-23T16:26:00.462+03:00Evolving code and adding new technologies - Part 3In this part of the series we will see how our code, after having evolved from a simple event call to a concurrent mess, will first and foremost get a bit into shape and then being throttled to produce best results. <i>TL;DR The light at the end of the tunnel is not oncoming traffic.</i><br />
<br />
More parts are here: <a href="http://www.albertobarnoy.blog/2017/11/evolving-code-and-adding-new.html" target="_blank">Part 1</a> and <a href="http://www.albertobarnoy.blog/2017/11/evolving-code-and-adding-new_13.html" target="_blank">Part 2</a>, <a href="http://www.albertobarnoy.blog/2017/11/evolving-code-and-adding-new_26.html" target="_blank">Part 4</a> and <a href="https://www.albertobarnoy.blog/2017/11/evolving-code-and-adding-new_23.html" target="_blank">Part 5</a><br />
<br />
Before we start I urge you to go read through the documentation. These are the links that hlped me write this post and learn how to use the Dataflow Library<br />
<h3>
<div style="font-size: medium; font-weight: 400;">
<ul>
<li><a href="https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/dataflow-task-parallel-library" target="_blank">Dataflow (Task Parallel Library)</a></li>
<li><a href="https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/walkthrough-creating-a-dataflow-pipeline" target="_blank">Walkthrough: Creating a Dataflow pipeline</a></li>
<li><a href="https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/walkthrough-using-dataflow-in-a-windows-forms-application" target="_blank">Walkthrough: Using Dataflow in a Windows Forms application</a></li>
<li><a href="https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/how-to-write-messages-to-and-read-messages-from-a-dataflow-block" target="_blank">How to: Write messages and read messages from a Dataflow block</a></li>
<li>Update: On Post and SendAsync <a href="https://stackoverflow.com/questions/13599305/tpl-dataflow-whats-the-functional-difference-between-post-and-sendasync" target="_blank">On Post and SendAsync in TPL Dataflow</a></li>
</ul>
</div>
</h3>
<h3>
Let the data flow</h3>
<div>
<a href="https://github.com/AlbertoBN/CodeEvolve/tree/CodeEvolve_DataFlow">GitHub branch</a><br />
<br />
This may be "old" tech for some or all of you but it was new to me when I decided to pop my head out of the "company" man role and into the consultancy role in my career. So lets evolve and enrich that old system with, you guessed it, the <a href="https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/dataflow-task-parallel-library" target="_blank">TPL Dataflow library</a>. Now mind you, in this blog post this is the first time I am using this library. I will explore, apply and benchmark it to the demo code. The change in the real system skipped this phase and was more radical. We will get there, however I feel that this is an important step to shape up and streamline an otherwise messy code.</div>
<h3>
Identifying the proper data flow block</h3>
<div>
After having read the documentation of the data flow library I decided to link a Batch source block to a buffer block and form a pipeline. This way I can free the producers from creating a list of 100 messages and then pushing it over to the consumer, gather 100 items from all consumers each time and pipeline them to the buffer block where messages will be dealt with one by one. Moreover I will put a block between the batch source block and the buffer block to group messages by time with a margin. This will go into the buffer block and the data consumer on the other side will have a primary message correlation to do as it sees fit. The flow will look as such:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYMKTEG4aok6PMYiih4-fINYr0TVWWNpOKL7HlOsx4yEvMhIiqvw5qihCKoKs-XgAloz8wdNMsSzBZg8qq5bdg4iKnzi5huQ2bzMSYa97TZoyG5-WtkZ7J3AHAGeRFnXL41iFjSftvFg8/s1600/CodeEvolve_Dataflow.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Our Dataflow pipeline" border="0" data-original-height="184" data-original-width="982" height="118" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYMKTEG4aok6PMYiih4-fINYr0TVWWNpOKL7HlOsx4yEvMhIiqvw5qihCKoKs-XgAloz8wdNMsSzBZg8qq5bdg4iKnzi5huQ2bzMSYa97TZoyG5-WtkZ7J3AHAGeRFnXL41iFjSftvFg8/s640/CodeEvolve_Dataflow.png" title="" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br /></div>
<div>
<br /></div>
<div>
Please notice that the data flow library has degrees of parallelism built in. We will be changing those, as well as the amount of producers and the rate messages are produced, in order to observe the behavior of the library. See we didn't get rid of concurrency woes. We just took a library that keeps them under wraps and makes the code above more of a syntactic sugar with, albeit useful, bells and whistles. Expect surprises!</div>
<h3>
On to the code </h3>
<div>
So on with the changes. Our DataMessage class will look like this:</div>
<div>
<br /></div>
<div>
<div>
<script src="https://gist.github.com/AlbertoBN/41409f5d5abc83da34644d2f3647e03b.js"></script></div>
<br /></div>
<div>
Notice the overridden <i>ToString </i>method. Not only will it make the code to print out the message data cleaner down the road, when you hover in the debugger over an instance of a class with this method overridden, what you will see is the output you composed inside your override. Be careful though, make the output too big or too complex and you may cause major performance degradation while debugging. Especially if this a collection of hundreds of messages you are inspecting.<br />
<br />
By the way in the matter of debugger views I strongly urge you to check out my colleague's <a href="http://moaid.codes/" target="_blank">Moaid Hathot</a> post on <a href="http://moaid.codes/post/VisualStudios-Debugger-Attributes" target="_blank">Custom Debugger views for Visual Studio</a> by using debugger attributes. In there you will also see the use of <a href="https://www.oz-code.com/" target="_blank">OzCode</a> which is also mentioned in my <a href="http://www.albertobarnoy.blog/p/tools-of-trade.html" target="_blank">Tools of the Trade page</a>. This was a huge eye opener for me. Thanks Moaid!</div>
<div>
<br /></div>
<div>
Before we get down to the specific implementation please notice there are 2 ways to use components of the Dataflow library:<br />
<ul>
<li>As a pipeline, where you link the different process block with each other and let them synchronize and pass data around or</li>
<li>Write the "go between" code on your own by using<i> DataflowBlock.Recieve</i> or <i>DataflowBlock.RecieveAsync</i> and do the synchronizing or <i>DataflowBlock.Post</i> or <i>DataflowBlock.SendAsync </i>to the next block on your own.</li>
</ul>
<div>
There really isn't a better option here. It is a matter of implementation, code architecture and specific needs. For example if different Dataflow blocks needed to exist in different components wrapped around with abstractions then most probably the later would be the case. For our example I chose a pipeline. I wanted 0 interaction with the complexity of concurrency... or didn't I?<br />
<br />
The code to produce and have data flow in the pipeline looks like this:<br />
<br />
<div>
<script src="https://gist.github.com/AlbertoBN/daf77ed690ea005a91937e2faf9ef017.js"></script></div>
<br />
I also added 3 configuration parameters in order to jungle with the throttling of the system in order to understand the behavior of the Dataflow library.<br />
<br />
<div>
<script src="https://gist.github.com/AlbertoBN/2031ddeb710bd44d7ff8db15bd0c9fd7.js"></script></div>
<br />
The first one defines the amount of producers, the second the amount of messages the <i>BatchBlock</i> will hold before pushing them down the pipeline and the third the maximum degree of parallelism for the <i>ActionBlock</i>. The later may also be used on the <i>TransformBlock. </i>I urge you to run the code and play with these values. The findings will be most interesting.<i> </i><br />
<h3>
Some Benchmarks</h3>
</div>
<div>
Playing with the settings produced some interesting results. The data is grouped by time. The larger the number of producers the worst the situation becomes. The delay observed in the previous parts of the series gets worse. Memory allocated is not released on time. On 10 producers increasing the number of max parallelism gives better results for a couple minutes and then enters a delay as well, all the while messages are numbered in millions. Some actual throttling can be sensed on the buffer of the batch block. Smaller number gives better results. Larger number the system goes downhill.</div>
<div>
<br /></div>
<div>
When having 1-2 producers, again the main throttling parameter is still the buffer size. Also notice the 100 milliseconds sleep on the producer code. Remove it and no matter what all the other values are things turn south fast. </div>
<h3>
Conclusion</h3>
<div>
Although the TPL Dataflow library is a very nice library, it is not built for large volumes of data. Especially not in pipeline mode. Data will flow and will flow well and the complexity will be visibly reduced from your code. It's overall performance is good as long as the amount of data and its rate are reasonable and do not amount to thousands within 60 seconds. Having 10 producers is also not bad as long as they don't overload the pipeline. On this specific case however the need is for thousands of messages per minute, hence the Dataflow library is not the best solution. By the way, in case you are wondering, it took me 1 day's work net time to implement, debug and benchmark the library. In case you are investing in a mock to see if it fits your needs 1 work day including conclusions is reasonable time for that. </div>
<h3>
</h3>
</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-3256541113612906467.post-27364027697361323012017-11-13T01:06:00.002+02:002019-09-23T16:25:02.658+03:00Evolving code and adding new technologies - Part 2In <a href="http://www.albertobarnoy.blog/2017/11/evolving-code-and-adding-new.html" target="_blank">Part 1</a> of this series we saw a basic, naive implementation of a monolithic desktop client that draws input from some input producer and displays data. Now imagine that this is your system. You built and deployed it a while ago and time went by. On a quiet morning while you sit on your desk sipping coffee and reading your favorite news outlet, your PO and hands you over the new requirements for the next version. <i>TL;DR it will get messy before it will get sweet</i><br />
<i><br /></i>
Parts 3-5 are here: <a href="http://www.albertobarnoy.blog/2017/11/evolving-code-and-adding-new_22.html" target="_blank">Part 3</a>, <a href="http://www.albertobarnoy.blog/2017/11/evolving-code-and-adding-new_26.html" target="_blank">Part 4</a> and <a href="https://www.albertobarnoy.blog/2017/11/evolving-code-and-adding-new_23.html" target="_blank">Part 5</a><br />
<h3>
Version 2</h3>
<div>
<a href="https://github.com/AlbertoBN/CodeEvolve/tree/CodeEvolve_ConcurrentQueue">GitHub branch</a><br />
<br />
According to the requirements now you have more than one producer. And they produce data faster. However your processing of data just got slower. You have to fetch some older data from the DB, do some correlations and then save data back to the DB. No matter what the processing is your data processing takes anywhere from 600ms to 1000ms. Yes you read right; 1 sec by the time data is correlated, stored in the database and displayed. Database optimization and more threads are out of the scope of this series and in the real life system this article is drawn from they were out of the scope of the deadline as well. </div>
<div>
<br /></div>
<div>
So you start typing and come up with an application which manages to do the processing and display the data in a timely fashion. Enter PO: The producers will not be creating one message every second anymore. The will be producing a list of DataMessages whenever they have the chance. So the producer goes from this:<br />
<br />
<script src="https://gist.github.com/AlbertoBN/6fad70d5d68a62dad1d89fefdc2f0589.js"></script></div>
<div>
<br /></div>
<div>
To this: <br />
<br />
<script src="https://gist.github.com/AlbertoBN/3c1db4e1be9da56c8a88266a8a974862.js"></script></div>
<br />
<div>
Notice what happened here. The producer creates a list of 100 messages, adds them to a collection and pushes them to the consumer. The processing time however has not changed. it still takes up to 1 second to process each message. The consumer now looks as such:<br />
<br /></div>
<div>
<script src="https://gist.github.com/AlbertoBN/e20d6dacaaa493424b1fc0506d0bc6de.js"></script></div>
<br />
<div>
And your application looks like this:</div>
<br />
<div>
<iframe allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/l792Qn9Ps-E?rel=0" width="560"></iframe> </div>
.
<br />
<div>
So as you can see the client is stuck. This is where you realize that you need to take drastic measures.<br />
<h3>
Synchronized collections to the rescue</h3>
</div>
<div>
As pompous as the heading is they do come to the rescue to some extent. No matter which type of collection you use or how you use it, the outcome is the same. The code has become more complex and harder to debug. Concurrency and threading tends to do that to systems. It complicates flows and creates unexpected race conditions.</div>
<div>
<br /></div>
<div>
What is important to understand at this point in the code is that not only did we render our client inoperable, we are also facing starvation on the producer side. If we had a requirement of "Group all messages produced on the same time with a margin of 500ms on either side of an anchor time", we would fail miserably to address it.Considering the above we can now calculate the possible starvation time of a producer.<br />
<br />
Any producer may have to wait this long to push data:<i> O((n-1)*100 elements)*1000ms*100ms for list filling. </i>So the last producer will wait for 9*100*1000*100 = 90000000 milliseconds or <b>25 hours</b>. Yes folks it was like that and worst. Times would not correlate and things became messier by the day.<br />
<br />
So how do we solve the starvation on the producer side? Well take a look at the following code:<br />
<br />
<div>
<script src="https://gist.github.com/AlbertoBN/4aa0d827e217cc3b5f41943e38269916.js"></script></div>
<br />
We are using a synchronized list to add messages and process them one by one.<br />
There can be a few variations to this code but all you will do is shave off a few milliseconds.</div>
<h3>
The complexity of concurrency</h3>
<div>
In the real system behind this post, in versions before things changed radically, there was a synchronized collection per producer. Did that help? It did a bit... it shaved starvation time on the producer side. It did little to none to improve the system on the processing time of the data. In fact improving processing time had to do with more concurrency being put to place which complicated things even more, not to mention the fact that debugging it was possible only via trace logs.<br />
<br />
I urge you to download and run the code for yourself and notice how while you print data of a specific minute your computer clock goes forward and you are still processing old data.<br />
<br />
While writing these lines I realized the code throws an OutOfMemory exception when adding items to a simple WinForms list box. The control is not built for such abuse and the original system used WPF. Since UI is not in the scope of this blog I will leave it at that. After all the final chapter will hold a surprise in that area. This explains the efforts to clean as many collections as possible in the code The effect of the delay however is apparent by the time the exception is thrown. In any case the code for this part is <a href="https://github.com/AlbertoBN/CodeEvolve/tree/CodeEvolve_ConcurrentQueue" target="_blank">here</a>.<br />
<br />
So how do you think the problem of the timing will be solved? Which technology will solve our problems until the next bottleneck? Stay tuned! </div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-3256541113612906467.post-20249102835731832792017-11-07T23:48:00.000+02:002019-09-23T16:23:32.103+03:00Evolving code and adding new technologies - Part 1This is a start of a series starting on some simple old fashion code and evolving such code to something more modern. I will not use buzzwords like <i>microservices</i> or <i>containers. </i>This is beyond the scope of this article. What I will try to show is how to approach the past and future decisions step by step by way of refactoring and introducing new technologies. <i>TL;DR There is none, read it all</i><br />
<h4>
Disclaimer</h4>
The idea for this series is taken from a real life "war story". I am however not the least bit inclined to disclose the source. Nor does any part of the code reflect the full and actual system, the idea for the post has stemmed from.<br />
<br />
Parts 2-5 are here: <a href="http://www.albertobarnoy.blog/2017/11/evolving-code-and-adding-new_13.html" target="_blank">Part 2</a>, <a href="http://www.albertobarnoy.blog/2017/11/evolving-code-and-adding-new_22.html" target="_blank">Part 3</a>, <a href="http://www.albertobarnoy.blog/2017/11/evolving-code-and-adding-new_26.html" target="_blank">Part 4</a> and <a href="https://www.albertobarnoy.blog/2017/11/evolving-code-and-adding-new_23.html" target="_blank">Part 5</a><br />
<h2>
Part 1 - Old School</h2>
<div>
The code for the old school code is pretty straight forward and resides on the master brunch of this <a href="https://github.com/AlbertoBN/CodeEvolve" target="_blank">GitHub repository</a>.</div>
<h3>
Initial architecture</h3>
<div>
The initial architecture of the system looks as such:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEib4DtV9H8HaFJRCgeor34FfmOjBWUBFbDz2JRPEZnTWHv4MhDh9otPd6EUfzzXhyP8-OobyHLO_t3jziQ4iRZAsJnhXGRetA5KXYdbUi3mMR0tLVmnqpL28KK-8LwpyOjLFHWwnSOXRmM/s1600/InitialArchitecture-CodeEvolve.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Monolithic application diagram" border="0" data-original-height="462" data-original-width="206" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEib4DtV9H8HaFJRCgeor34FfmOjBWUBFbDz2JRPEZnTWHv4MhDh9otPd6EUfzzXhyP8-OobyHLO_t3jziQ4iRZAsJnhXGRetA5KXYdbUi3mMR0tLVmnqpL28KK-8LwpyOjLFHWwnSOXRmM/s400/InitialArchitecture-CodeEvolve.png" title="" width="177" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Consider an application with two major threads; One thread reads data from some input, does some pre-processing of the data read and then calls an event on the other thread, incidentally a UI thread, to read the data. It does so on a message by message basis. The receiving thread upon reading each message does some more processing on the context of the event, synchronously. Meaning the calling thread of the event is stuck until the called thread is done.</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
If the volume of messages is not too big (say 100 per minute) then this architecture will work pretty well. Things will get messy when the volumeof inputs increases, the processing on the called thread gets slower and more cumbersome or more calling threads are added to handle different inputs yet ride on the same event message.</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
When volumes grow then this architecture is not good enough. The drawing will stay the same but something else will need to change. Something inside the code. The synchronous event based paradigm will have to change. Some would argue that instead of using invoke the <a href="https://docs.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/asynchronous-programming-model-apm" target="_blank">APM</a> method should be used. I would however skip this step in order to advance faster to the preferred solution.</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
So until the next part I leave it to you to think what could be the next step to handle larger volumes of data (without APM or TPL for now).</div>
<div>
<br /></div>
<div>
<br /></div>
Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-3256541113612906467.post-60708651954606767622017-10-27T22:40:00.000+03:002017-10-28T09:50:52.584+03:00Code Review Boards - How to stay professional I have recently come across the concept of a code review board. At first it was an awkward moment; My change set was out there for all the world to see and comment. I admit I was stressed about it and with good reason. What I will do in this post is put the record straight, as far as I am concerned, on the good, the bad and the ugly of public/social code reviews. And since in the near future my code will be standing there naked for all to see on some public repository, this should make for a very good exercise on what to expect and what to reject when it comes to review boards.<i> TL;DR Code reviews are good. Review boards meh...</i><br>
<br>
<h3>
Past (nearly) perfect</h3>
<div>
At some point during my searching for topics to write I recalled some articles I wrote back in the day on <a href="http://www.codeproject.com/" target="_blank">CodeProject</a>. And I also do remember that, unless your article was pure garbage, review of the article and comments where polite, leveled and cool headed. Social media was not that proliferated and people did not openly enjoy putting others in a defensive position on a whim. Oh and by the way one can find links for those articles in this static <a href="http://www.albertobarnoy.blog/p/previous-articles.html" target="_blank">page</a> in this blog.</div>
<h3>
The Good</h3>
<div>
The good thing about having people crowd-review your code is that you get everyone's perspective on what you wrote, be it for the design of your code, potential bugs, or best practices. In a perfect world you can have a professional discussion about it and solve problems, decide on a course of action on technical debts or develop a philosophical discussion.<br>
<br>
<h3>
The Bad</h3>
<div>
The bad thing about review boards (especially when they are group wide), are the email "noise" they produce. Every single comment will be, most definitely, sent by email to every member in the group at any time of the day... or night.</div>
<div>
<br></div>
<h3>
The Ugly</h3>
<div>
Although code reviews are good and between professionals are even better, there is always that person with the annoying comments. The person who has something to say no matter what. Who doesn't like your naming scheme. Who thinks that <span style="font-family: Courier New, Courier, monospace;">if(A && B)</span><span style="font-family: inherit;">is not clear enough (to this person's opinion) then the elements around the </span><span style="font-family: Courier New, Courier, monospace;">&&</span><span style="font-family: inherit;"> have to be switched.</span><span style="font-family: Courier New, Courier, monospace;"> </span><span style="font-family: inherit;">The petty one. Be polite but precise and assertive to your answers to that person. Be constructive when commenting that person's code. Be professional. Hopefully that person will get off your back. Hopefully but not probably. </span></div>
<div>
<span style="font-family: inherit;"><br></span></div>
<div>
<span style="font-family: inherit;">Having said all that, in the link below is the base repository on which quite a few post will be based upon. And it has a bug!!! Can you spot it without running the code (review it)? Can you spot it after reading the code, running but not debugging? Leave a comment below and let me know!</span></div>
<br>
<a href="https://github.com/AlbertoBN/ProducerConsumer" target="_blank">Producer/Consumer Repo</a> </div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-3256541113612906467.post-28477417587369382192017-09-30T21:35:00.002+03:002017-11-14T13:35:43.202+02:00How to approach a new technologySomeone asked me to write a post about how I approach new technologies. There isn't really one way to do that and what works for me may not work for someone else. Having said all that let's explore the different options standing before any developer who wants to explore a new technology. <i>TL;DR Put time in your calendar and go for it.</i><br />
<h3>
<b style="background-color: white; color: #222222; font-family: sans-serif; font-size: 13.3px;"><a href="https://en.wikipedia.org/wiki/Heraclitus" target="_blank">Τα πάντα ρει, μηδέποτε κατά τ' αυτό μένειν - Everything flows, nothing remains the same - Heraclitus</a></b></h3>
We are living in a world where you see a new framework or a new language pop all the time. It was less than a year ago that Angular took the web by storm and went head to head with its predecessor AngularJS and React and then VueJS popped it's head to say Hi.<br />
Who would have thought Python would become the go to language for cyber security, or that Go would become the next hot thing.<br />
So let's stop beating around the bush and get to it.<br />
<h3>
Go Online</h3>
When I started to plow my way through technology all we had was BBS message boards and noisy modulators/de-modulators (better known as MODEMs). Later on the first websites started showing up. And then online books, blogs and finally... online courses. I will not go into the different sites and their quality. Ask your colleagues, friends and your favorite search engine. The important thing is to find not only a site with the content you seek but also for the format used to present the content to you, be to your liking. When it comes to how content is presented results will vary.<br />
<div>
<h3>
Find the time</h3>
</div>
<div>
If you are like me, you have to balance work, children, house chores etc. So how do I find the time for it? Well I won't be the one to tell you how to arrange your day. However you have commuting, lunch break and the evening. Figure it out. It is your time. It is your career. What I can tell you though is this;<b> put it in your calendar</b>. Make a recurring event in your calendar. If you are using Google calendar then you have a feature called "Goals", it helped me a lot.<br />
<h3>
Language vs Framework</h3>
Sometimes we hear about some new framework written in some shine language we know nothing about. So what do we do first? Learn the language or the framework? As a friend of mine once said (while scribbling design patterns on some hard surface, bless you Ran wherever your are...), a language's syntax and intricacies is cheap technical knowledge. So you might as well first learn that by writing the classic "Hello world" program and be done with it. Once you feel comfortable with the language itself then you can charge at the framework that drew your attention.<br />
<h3>
Do or Do not, there is no excuse.</h3>
<div>
The best way to pass a message isn't this you say? Disagree I would. </div>
<div>
Seriously though... There is no excuse. Every time you dismiss your calendar event and procrastinate, you are in fact finding excuses for yourself.</div>
<h3>
Don't try to learn every language 100% in one go</h3>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyDebuDbhC9rUQYJnhA-WQ_0gmepBPFYueldizeKmpRlLN_BhCOKZYAHQ3vlyzPaTH6h4QViMrqEJrLoT4zFSAaK1B7-LzVyDZPbHGhf8eSIZCP_aIlcHhxskZX-xcwgEKqfDTh26TZM4/s1600/WhatsApp+Image+2017-09-30+at+21.31.07.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Learning a new technology is like climbing an endless mountain" border="0" data-original-height="676" data-original-width="700" height="309" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyDebuDbhC9rUQYJnhA-WQ_0gmepBPFYueldizeKmpRlLN_BhCOKZYAHQ3vlyzPaTH6h4QViMrqEJrLoT4zFSAaK1B7-LzVyDZPbHGhf8eSIZCP_aIlcHhxskZX-xcwgEKqfDTh26TZM4/s320/WhatsApp+Image+2017-09-30+at+21.31.07.jpeg" title="" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Self explanatory right? Learn the things you need now, get the gist of a language or framework if it is for your own knowledge. The rest will come.</div>
<div>
<br /></div>
<div>
And finally...<b>Have fun learning!</b></div>
<br />
<br />
<br />
<br /></div>
Unknownnoreply@blogger.com6