<?xml version='1.0' encoding='UTF-8'?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-4273255328290947077</atom:id><lastBuildDate>Thu, 19 Mar 2026 16:26:37 +0000</lastBuildDate><category>patterns</category><category>agile</category><category>.net</category><category>test</category><category>tdd</category><category>go</category><category>security</category><category>bdd</category><category>teams</category><category>TBT</category><category>tap</category><category>toolbox</category><category>di</category><category>microsoft</category><category>relocating</category><category>collections</category><category>diagnostics</category><category>http</category><category>military</category><category>news</category><category>open source</category><category>performance</category><category>task</category><category>ux</category><category>fake</category><category>leadership</category><category>azure</category><category>interviews</category><category>rest</category><category>statistics</category><category>abuse</category><category>estimation</category><category>sql</category><category>OKR</category><category>ericsson</category><category>google</category><category>nuget</category><category>technical debt</category><category>aws</category><category>mail</category><category>php</category><category>tfs</category><category>twitter</category><title>Being Cellfish</title><description>Stuff I wished I&#39;ve found in some blog (and sometimes did).</description><link>http://blog.cellfish.se/</link><managingEditor>noreply@blogger.com (cellfish)</managingEditor><generator>Blogger</generator><openSearch:totalResults>195</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4273255328290947077.post-6769548601913685089</guid><pubDate>Thu, 24 Jul 2025 13:24:00 +0000</pubDate><atom:updated>2025-07-24T07:24:00.128-06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">OKR</category><title>OKR Mistake #9</title><description>&lt;p&gt;&amp;nbsp;A while back I went over &lt;a href=&quot;https://blog.cellfish.se/2023/03/okr-mistakes-and-how-to-avoid-them.html&quot;&gt;8 mistakes&lt;/a&gt; I&#39;ve seen in organizations using OKRs. I realized I missed one important one so here it is.&lt;span&gt;&lt;/span&gt;&lt;/p&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;p&gt;&lt;/p&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;Mistake #9 - Don&#39;t cover the basics&lt;/h3&gt;&lt;p&gt;In the previous article I mentioned that a good process is to have some generic high level goals that remain the same with some adjustments every year. And this is related to this mistake. Consider a situation where you want to increase sales and for the sake of this argument, let us assume you have a single KR; &lt;i&gt;increase number of sold items by 100%&lt;/i&gt;. It is plausible that this could be achieved by dumping the price of the product. Maybe we can double the number of items by cutting the prize in half.&lt;/p&gt;&lt;p&gt;The problem here is that if the team have the freedom to make any decisions as long as they meet their KRs, dropping the prize could happen. As a result the actual profit might go down or we could even end up in a situation where every item is sold at a loss. Since this is probably not want we want, we need to fix this.&lt;/p&gt;&lt;p&gt;Naturally this could be fixed with various constraints in the organization, but since we&#39;re talking about OKRs the way to fix this is to add another KR to balance the scale and set some rules. We could for example add another KR: &lt;i&gt;average profit per item sold should be at least $10.&lt;/i&gt;&lt;/p&gt;&lt;p&gt;I&#39;ll admit that in this simple example, putting a constraint on the profit doesn&#39;t feel like a KR at first glance, but there are actually two important things this KR allows the team to do: First, this allows the team to have tiered prizing. The more you buy the cheaper each item is. And the team can make these decisions themselves since they know the goal. Second, this allows the team to explore other options. Can they improve production to lower the cost to create the item and hence be able to lower the prize while maintaining the same profit.&lt;/p&gt;&lt;p&gt;In this simple example it might feel like an overkill and you could also argue that the team is not going to be malicious in order to meet the KRs set. While the latter is true, in a less obvious scenario a team might make an optimization for one KR that has an undesired side effect if the basics are not covered. And the team might not do this out of malice, but rather ignorance or just in dedication to succeed with the KRs set.&lt;/p&gt;&lt;p&gt;So in conclusion, since you tend to get what you measure, spend a few minutes thinking about how your KRs could be gamed and add a few more KRs to balance the scale and avoid KR gaming.&lt;/p&gt;</description><link>http://blog.cellfish.se/2025/07/okr-mistake-9.html</link><author>noreply@blogger.com (cellfish)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4273255328290947077.post-3536389640364509200</guid><pubDate>Thu, 15 May 2025 11:15:00 +0000</pubDate><atom:updated>2025-05-15T05:15:00.325-06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">leadership</category><category domain="http://www.blogger.com/atom/ns#">military</category><category domain="http://www.blogger.com/atom/ns#">teams</category><title>Mandatory manager training - Sabotage an organization</title><description>&lt;p&gt;It&#39;s been almost 10 years since I found this gem from &lt;a href=&quot;https://en.wikipedia.org/wiki/Office_of_Strategic_Services&quot;&gt;the OSS&lt;/a&gt; (CIA predecessor). Recently when talking to some colleagues I realized that the sabotage field manual would make for an excellent manager training.&lt;span&gt;&lt;/span&gt;&lt;/p&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;The &lt;i&gt;gem &lt;/i&gt;I&#39;m talking about is the &lt;a href=&quot;https://www.cia.gov/static/5c875f3ec660e092cf893f60b4a288df/SimpleSabotage.pdf&quot;&gt;simple sabotage manual&lt;/a&gt;, and specifically the 11th section starting on page 28 covering how to sabotage organizations and production. Section 11b even talks specifically about things a manager can do and hence serves as great examples of what &lt;b&gt;&lt;i&gt;not&lt;/i&gt;&lt;/b&gt; to do.&lt;/p&gt;</description><link>http://blog.cellfish.se/2025/05/mandatory-manager-training-sabotage.html</link><author>noreply@blogger.com (cellfish)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4273255328290947077.post-7299316411068775066</guid><pubDate>Thu, 30 Jan 2025 20:30:00 +0000</pubDate><atom:updated>2025-01-30T13:30:00.234-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">ux</category><title>Why not have users jump around in a form?</title><description>&lt;p&gt;Starting to collect documents to do my tax return this year I came across a terrible user experience.&lt;/p&gt;&lt;span&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;/span&gt;&lt;p&gt;When you live in the US, but have assets (such as a bank account) in another country you need to fill in a form to declare how much money you have there. It used to be a paper form but now there is an online form to fill in.&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJ6AUxXWMrYSXoZaeH69Cfe31mC3aVMzycbxl6ewuiUF0PRw3xC2yMWmdj1btyE5RBA0qf-HmQt8ZmOIOpVTdLojXVVYh-44F4NM8XIfd9KUeGw-OyO6AwZ8-WZheQfCdDLwn112TZkziM83lPaAfeKbNa-HYOy2Hq7Er2lSlcbDKVkBf_vckQCoG2GJM/s987/StateBeforeCountry.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;175&quot; data-original-width=&quot;987&quot; height=&quot;114&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJ6AUxXWMrYSXoZaeH69Cfe31mC3aVMzycbxl6ewuiUF0PRw3xC2yMWmdj1btyE5RBA0qf-HmQt8ZmOIOpVTdLojXVVYh-44F4NM8XIfd9KUeGw-OyO6AwZ8-WZheQfCdDLwn112TZkziM83lPaAfeKbNa-HYOy2Hq7Er2lSlcbDKVkBf_vckQCoG2GJM/w640-h114/StateBeforeCountry.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;This form has a great &lt;i&gt;&quot;feature&quot;&lt;/i&gt;... When you fill in the form from top to bottom and you want to enter the state for your address, the drop down is empty... But there is a helpful comment letting you know that you first need to skip down two fields and select the country. Once the country is selected you can select the state. Note that the US of A that is selected for line/field 13 is there because I selected it before taking the screenshot. Initially no country is selected and hence no state can be selected...&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I&#39;m pretty sure the ordering is just whatever order the paper form (that is still available as a PDF version) have the fields in this order. And for some reason the electronic form was not changed to be logical but to mimic the paper form. A great example of how UI should not be a reflection of the implementation behind the scenes.&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;</description><link>http://blog.cellfish.se/2025/01/why-not-have-users-jump-around-in-form.html</link><author>noreply@blogger.com (cellfish)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJ6AUxXWMrYSXoZaeH69Cfe31mC3aVMzycbxl6ewuiUF0PRw3xC2yMWmdj1btyE5RBA0qf-HmQt8ZmOIOpVTdLojXVVYh-44F4NM8XIfd9KUeGw-OyO6AwZ8-WZheQfCdDLwn112TZkziM83lPaAfeKbNa-HYOy2Hq7Er2lSlcbDKVkBf_vckQCoG2GJM/s72-w640-h114-c/StateBeforeCountry.png" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4273255328290947077.post-111923838736334016</guid><pubDate>Thu, 05 Sep 2024 15:05:00 +0000</pubDate><atom:updated>2024-09-05T21:52:53.348-06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">abuse</category><category domain="http://www.blogger.com/atom/ns#">ux</category><title>You never know what the users mean</title><description>&lt;p&gt;A couple of days ag Elon Musk tweeted (it&#39;s still called that, right?) about how their recommendation algorithm easily can get things wrong since they don&#39;t know &lt;i&gt;why&lt;/i&gt; you are sharing content with friends. This is a great example of a problem I have to deal with on a regular basis.&lt;/p&gt;&lt;span&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;/span&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhttgAJ9cq_LDVFIIi4QJUbfWw-Km2vRhUNh5ARlIxsf2cL_epIhPdIl-wobJ7jcHBswjwz3KeHytYFcTRIu6mCn-UxrVD62bs45RORlG5rBmvjFpV09Nc1VQ0UkGmBFZ7Fx-0tV3EVleuaF3g117V_BwpdKo4m0FhJX_K-LZk4DaR4AvLcgX1f2ijXsM/s593/elon-tweet.png&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img alt=&quot;The 𝕏 algorithm assumes that if you interact with content, you want to see more of that content.   One of the strongest signals is if you forward 𝕏 posts to friends, it assumes you like that content a lot, because it takes effort to forward.  Unfortunately, if the actual reason you forwarded the content to friends was because you were outraged by it, we are currently not smart enough to realize that.&quot; border=&quot;0&quot; data-original-height=&quot;295&quot; data-original-width=&quot;593&quot; height=&quot;199&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhttgAJ9cq_LDVFIIi4QJUbfWw-Km2vRhUNh5ARlIxsf2cL_epIhPdIl-wobJ7jcHBswjwz3KeHytYFcTRIu6mCn-UxrVD62bs45RORlG5rBmvjFpV09Nc1VQ0UkGmBFZ7Fx-0tV3EVleuaF3g117V_BwpdKo4m0FhJX_K-LZk4DaR4AvLcgX1f2ijXsM/w400-h199/elon-tweet.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;a href=&quot;https://x.com/elonmusk/status/1830440852411326782?t=7_KDgkmSFK2S-WFlesGrOQ&quot; target=&quot;_blank&quot;&gt;This is the tweet in question&lt;/a&gt; (screen shot to the right in case it get&#39;s deleted). It highlights a very common problem when it comes to both abuse prevention and streamlining content for users - you cannot be sure about why users take certain actions.&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Let&#39;s look at a two examples from &quot;my world&quot;. If a user deletes an email without reading it - what does that mean? Does it mean that the user don&#39;t want to see similar content? Or does it mean that they could triage the email based on the subject and decided they don&#39;t need to read this message (but is still interested in other messaged from the same sender)? Technically we cannot know...&lt;/p&gt;&lt;p&gt;What about somebody who is reporting an email as spam? Does that mean that they think all emails from that sender is spam? Or only that one email? Or are they using an email client with the options &quot;junk&quot; and &quot;trash&quot; where one means &quot;delete&quot; and the other &quot;spam&quot;? We can probably figure out if the last option is happening - but we still don&#39;t know if the action was intentional.&lt;/p&gt;&lt;p&gt;You might think that you can just ask the users for more information about their intentions. Sadly I think that rarely works with real users. I remember when I wanted to report a fake account on twitter and because I was not the victim directly affected it took me several attempts to reach a state where I could actually report the account. At that point I would have clicked anything just to proceed so the reasons I provided had less value. Generally I think users hate clicking through wizards so they probably just give up and your system do not get feedback on how it is performing.&lt;/p&gt;&lt;p&gt;At the end of the day, maybe it is acceptable to be &lt;i&gt;mostly right&lt;/i&gt;. But even if you keep the majority happy, the user experience for the minority where your system do the wrong thing can be pretty bad. And if you don&#39;t recognize the fact that users will do unexpected things you&#39;ll likely end up making a lot of users disappointed.&lt;/p&gt;</description><link>http://blog.cellfish.se/2024/09/you-never-know-what-users-mean.html</link><author>noreply@blogger.com (cellfish)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhttgAJ9cq_LDVFIIi4QJUbfWw-Km2vRhUNh5ARlIxsf2cL_epIhPdIl-wobJ7jcHBswjwz3KeHytYFcTRIu6mCn-UxrVD62bs45RORlG5rBmvjFpV09Nc1VQ0UkGmBFZ7Fx-0tV3EVleuaF3g117V_BwpdKo4m0FhJX_K-LZk4DaR4AvLcgX1f2ijXsM/s72-w400-h199-c/elon-tweet.png" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4273255328290947077.post-1195986576208370850</guid><pubDate>Tue, 07 May 2024 04:22:00 +0000</pubDate><atom:updated>2024-05-06T22:22:00.128-06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">go</category><category domain="http://www.blogger.com/atom/ns#">security</category><title>Yet another reason to love Go: math/rand/v2</title><description>&lt;p&gt;With the recent explanation of how &lt;span style=&quot;font-family: courier;&quot;&gt;math/rand&lt;/span&gt; evolved into &lt;span style=&quot;font-family: courier;&quot;&gt;math/rand/v2&lt;/span&gt; I got reminded why I &lt;a href=&quot;https://blog.cellfish.se/2016/04/go-for-c-developers-introduction.html&quot;&gt;first fell in love with Go&lt;/a&gt;. Design decisions are not always made to match what every body else is doing, but rather what is the better decision. By some definition of &lt;i&gt;better&lt;/i&gt; that I happen to agree with.&lt;span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;While the &lt;a href=&quot;https://go.dev/blog/randv2&quot;&gt;blog post on &lt;span style=&quot;font-family: courier;&quot;&gt;math/rand/v2&lt;/span&gt;&lt;/a&gt;&amp;nbsp;goes into interesting details around different pseudo random algorithms, exciting optimizations, and how to generally update a widely used library (like the standard library) with new versions are all interesting it is really three other things that make me even more excited.&lt;p&gt;&lt;/p&gt;&lt;p&gt;One of the first things that I appreciate is the openness in recognizing that the original &lt;span style=&quot;font-family: courier;&quot;&gt;math/rand&lt;/span&gt; library has several bad design decisions in it. And this is a tone in the whole article. Very appreciated and directly related to the next two things I&#39;m excited about.&lt;/p&gt;&lt;p&gt;It might seem like a small thing but the fact that &lt;a href=&quot;https://pkg.go.dev/math/rand/v2&quot;&gt;the new library&lt;/a&gt; recognizes that different pseudo random algorithms needs to be seeded in different ways, just like different crypto algorithms need to be seeded (with a key and other parameters) in different ways.&lt;/p&gt;&lt;p&gt;But the final thing is really the best; the removal of the &lt;span style=&quot;font-family: courier;&quot;&gt;Read&lt;/span&gt; method from any &lt;span style=&quot;font-family: courier;&quot;&gt;math/rand/v2&lt;/span&gt; types since this introduces a risk of accidently using the weaker randomness in &lt;span style=&quot;font-family: courier;&quot;&gt;math/rand&lt;/span&gt; vs the cryptographically secure &lt;span style=&quot;font-family: courier;&quot;&gt;crypto/rand&lt;/span&gt; package. In my opinion this shows and amazing attention to detail and is definitely in the spirit of Go - prevent developers from accidently making mistakes.&lt;/p&gt;</description><link>http://blog.cellfish.se/2024/05/yet-another-reason-to-love-go-mathrandv2.html</link><author>noreply@blogger.com (cellfish)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4273255328290947077.post-1663394758581971957</guid><pubDate>Thu, 11 May 2023 17:05:00 +0000</pubDate><atom:updated>2023-05-11T11:05:00.139-06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">go</category><title>Go for C# developers: defer is not IDisposable</title><description>&lt;p&gt;When using an &lt;span style=&quot;font-family: courier;&quot;&gt;IDisposable&lt;/span&gt; object in C# you have some pretty clear expectations on when that object is disposed. While the same thing is technically true with &lt;span style=&quot;font-family: courier;&quot;&gt;defer&lt;/span&gt; in Go, I&#39;ve seen a lot of people misunderstand when exactly the deferred method is called.&lt;span&gt;&lt;/span&gt;&lt;/p&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;In C# we expect the &lt;span style=&quot;font-family: courier;&quot;&gt;Dispose&lt;/span&gt; method to pretty much be called when the disposable object goes out of scope. Unless you use a &lt;span style=&quot;font-family: courier;&quot;&gt;using&lt;/span&gt; statement you technically don&#39;t have a guarantee, but there is always a chance that your object gets disposed pretty soon after it goes out of scope due to the garbage collector.&lt;/p&gt;&lt;p&gt;In Go however when you use the &lt;span style=&quot;font-family: courier;&quot;&gt;defer&lt;/span&gt; to mimic disposing of an object, the deferred method is not executed until the &lt;i&gt;method &lt;/i&gt;returns. This is an important difference. You are actually guaranteed it will &lt;i&gt;not&lt;/i&gt;&amp;nbsp;be executed until the &lt;i&gt;method &lt;/i&gt;returns.&lt;/p&gt;&lt;p&gt;I have seen this cause confusion and problems when people use &lt;span style=&quot;font-family: courier;&quot;&gt;defer&lt;/span&gt; inside a loop since all cleanup functionality is postponed until after the method where the loop resides returns. And the way to fix it is to create a new function that actually returns for each iteration in the loop. &lt;a href=&quot;https://go.dev/play/p/jWHCi2VxUBf&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;Here is an example&lt;/a&gt; showing both the &quot;wrong&quot; and &quot;right&quot; way to have a deferred method execute for each iteration in a loop.&lt;/p&gt;</description><link>http://blog.cellfish.se/2023/05/go-for-c-developers-defer-is-not.html</link><author>noreply@blogger.com (cellfish)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4273255328290947077.post-6586691489670160813</guid><pubDate>Thu, 27 Apr 2023 10:27:00 +0000</pubDate><atom:updated>2023-04-27T04:27:00.139-06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">abuse</category><title>Rant over a sloppy scammer</title><description>&lt;p&gt;Occasionally I come across some really good scam attempts. But most of the time I&#39;m surprised at how bad scams are presented. Let&#39;s look at a recent scam I received.&lt;/p&gt;&lt;span&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;/span&gt;&lt;p&gt;This was one of the typical &lt;i&gt;refund scams&lt;/i&gt;&amp;nbsp;where they send you a receipt for something hoping that you&#39;ll call back for a refund. If you&#39;re interested in knowing what those calls sound like (and see somebody have some fun with the scammer) - &lt;a href=&quot;https://youtu.be/rnwkX9fmZG0&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt; is one of many videos of that.&lt;/p&gt;&lt;p&gt;So the scam email I received was such a lazy attempt. First of all the sender was just a random gmail address (no attempt spoofing a realistic sender) and the subject was just the work &quot;order&quot; with a few random numbers. There was no message in the body and only an attached file that had a random characters and number for a name.&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiDorDKxqHTDlI723LjnMKFcfBIoEG6csu6U0iqpkeAgVHXASreu9kWmDzk_5ZgxWnlmyg6nsqDaS23c9B49w2HfrosBau7jLKefl9M4CFRZ56RM071MYc24jT6TA56HPE4nxnzIlnaZJslCyg4k400UZGEIocYk6PU7oUrrYX1Dkt3FfGO0fq-ovI/s1232/Scam.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1232&quot; data-original-width=&quot;1030&quot; height=&quot;499&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiDorDKxqHTDlI723LjnMKFcfBIoEG6csu6U0iqpkeAgVHXASreu9kWmDzk_5ZgxWnlmyg6nsqDaS23c9B49w2HfrosBau7jLKefl9M4CFRZ56RM071MYc24jT6TA56HPE4nxnzIlnaZJslCyg4k400UZGEIocYk6PU7oUrrYX1Dkt3FfGO0fq-ovI/w418-h499/Scam.png&quot; width=&quot;418&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;Let&#39;s take a look at that attachment. From the top note a few things:&lt;/div&gt;&lt;div&gt;&lt;ul style=&quot;text-align: left;&quot;&gt;&lt;li&gt;The order number overflows to the edge of the page - Professional!&lt;/li&gt;&lt;li&gt;&quot;Thurs&quot; is definitely one way to abbreviate &lt;i&gt;Thursday&lt;/i&gt;, but I would have expected just &quot;Thu&quot; given that the payment date is abbreviated &quot;Fri&quot;. Maybe a small thing - but it caught my eye.&lt;/li&gt;&lt;li&gt;So the thing I &quot;purchased&quot; was $310.99 including tax - yet Paypal added tax. I guess that&#39;s another reason to call an demand a refund.&lt;/li&gt;&lt;li&gt;And the tax (12.58%) of $310.99 is not $38.99 - It&#39;s $39.12.&lt;/li&gt;&lt;li&gt;They definitely want me to make sure I know I can call them and cancel since they mention it three times!&lt;/li&gt;&lt;li&gt;Capitalization is wrong (using upper case i in the middle of a sentence and starting another with lower case c.&lt;/li&gt;&lt;li&gt;What does it even mean that the &lt;i&gt;amount is done through&lt;/i&gt;&amp;nbsp;Amazon but &lt;i&gt;purchasing done through&lt;/i&gt;&amp;nbsp;PayPal?&lt;/li&gt;&lt;li&gt;A cherry on the top I think is that what if I don&#39;t remember this but go check what this &lt;i&gt;Norton 360 deluxe&lt;/i&gt;&amp;nbsp;is? Maybe it&#39;s something I want. I guess I&#39;ll now definitely call for a refund since the actual prize is $109.99.&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFU_YIcrB1Ess4Ka5cS7rjbAUvoCZE0dXo_SJSfSLPQMvnu2zDGS-TuBnK3L1gt1hrdzJniqao2vzlUbQVCCVFpznvQwQJKuzmszstltmcFbTB7JPEdtCl44NBZv9uu_fLE9VJQp7QTLKgUEOn7UKlNooBalTLL4FfCO5VafZAO0nyIWVYDxAtFr7y/s341/norton_prize.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;341&quot; data-original-width=&quot;253&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFU_YIcrB1Ess4Ka5cS7rjbAUvoCZE0dXo_SJSfSLPQMvnu2zDGS-TuBnK3L1gt1hrdzJniqao2vzlUbQVCCVFpznvQwQJKuzmszstltmcFbTB7JPEdtCl44NBZv9uu_fLE9VJQp7QTLKgUEOn7UKlNooBalTLL4FfCO5VafZAO0nyIWVYDxAtFr7y/s320/norton_prize.png&quot; width=&quot;237&quot; /&gt;&lt;/a&gt;&lt;/div&gt;I guess there is no point in wasting time paying attention to details when scams like this still fool people.&amp;nbsp;&lt;span style=&quot;font-family: &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, sans-serif; font-size: 16px;&quot;&gt;¯\_(ツ)_/¯&lt;/span&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description><link>http://blog.cellfish.se/2023/04/rant-over-sloppy-scammer.html</link><author>noreply@blogger.com (cellfish)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiDorDKxqHTDlI723LjnMKFcfBIoEG6csu6U0iqpkeAgVHXASreu9kWmDzk_5ZgxWnlmyg6nsqDaS23c9B49w2HfrosBau7jLKefl9M4CFRZ56RM071MYc24jT6TA56HPE4nxnzIlnaZJslCyg4k400UZGEIocYk6PU7oUrrYX1Dkt3FfGO0fq-ovI/s72-w418-h499-c/Scam.png" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4273255328290947077.post-5465867417078221346</guid><pubDate>Thu, 13 Apr 2023 10:13:00 +0000</pubDate><atom:updated>2023-04-13T04:13:00.210-06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">go</category><category domain="http://www.blogger.com/atom/ns#">patterns</category><category domain="http://www.blogger.com/atom/ns#">test</category><title>Testing a periodic worker</title><description>&lt;p&gt;I came across somebody that was asking about how to test their code. They had a function that would do certain work at short intervals and then some other work after a longer period of time. They provided a simplified version of the code and it looked something like &lt;a href=&quot;https://go.dev/play/p/g2ZUmIMrM6_g&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;this&lt;/a&gt;. They had coverage for the short period work (I guess functions &lt;span style=&quot;font-family: courier;&quot;&gt;foo&lt;/span&gt; and/or &lt;span style=&quot;font-family: courier;&quot;&gt;bar&lt;/span&gt; in the simplified example had some side effect they could test for.&lt;span&gt;&lt;/span&gt;&lt;/p&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;Interestingly enough they did know they could add more arguments to their main function to control the shorter period as well as using a function argument to capture the longer period worker. But two problems remained; they would rely on some (short) waiting in their tests and they also would prefer to know that some short period work always happened before the longer period work.&lt;p&gt;&lt;/p&gt;&lt;p&gt;If you accept some really short waiting times (and ignore the second requirement), then you can get away with pretty short waiting times. The problem with short waiting times is that you might end up with too short waiting times and get occasional failures just because something took a little longer than usual due to load on your machine (for example lots of other tests running in parallel). But if you do go down this route you probably end up with something like &lt;a href=&quot;https://go.dev/play/p/OCzXjlAvXvZ&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;this&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;But I think you can do much better... I think there is an easy way to also test how the shorter and longer period work interacts without any waits in a predictable way. The trick is to not add more parameters to the existing function but rather break out the periodic worker and test that one separately. If you do that you end up with something like &lt;a href=&quot;https://go.dev/play/p/-KrL5RolHHK&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;this&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Yes, that solution uses three different function arguments which might look scary, but since you get really fast and predictable testing I think it&#39;s worth it.&lt;/p&gt;</description><link>http://blog.cellfish.se/2023/04/testing-periodic-worker.html</link><author>noreply@blogger.com (cellfish)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4273255328290947077.post-5088766066059037945</guid><pubDate>Thu, 30 Mar 2023 09:30:00 +0000</pubDate><atom:updated>2023-03-30T03:30:00.232-06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">abuse</category><category domain="http://www.blogger.com/atom/ns#">patterns</category><category domain="http://www.blogger.com/atom/ns#">security</category><category domain="http://www.blogger.com/atom/ns#">ux</category><title>Using soft limits to prevent abuse with good user experience</title><description>&lt;p&gt;When you develop a service you will probably run into a situation where you want to put in some arbitrary large limit on something to prevent bad behaving clients from using too much of your resources. This can be a max length of the URI, max length of each request header, max size of a request and so on. What we tend to do is often to return some kind of error when this happens and expect the client to fix their request if it is legitimate. But what if it is a legitimate request - just something you didn&#39;t expect to be valid? Or what if there is a bug in the client, but the user have no way of fixing the client but rely heavily on your service? Do you really want to completely break your users in these cases?&lt;span&gt;&lt;/span&gt;&lt;/p&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;span&gt;&lt;/span&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;I have come across situations like this several times in my career and often the problem is solved short term by increasing the arbitrary limits. This however only works when clients are few and don&#39;t expect quick fixes and you can deploy a fix quickly. I have however found another way to deal with this problem.&lt;/p&gt;&lt;p&gt;Instead of completely blocking unexpectedly large request I have found it effective to process them differently than &lt;i&gt;&quot;normal&quot;&lt;/i&gt;&amp;nbsp;requests. The solution is to allow each client a small emergency quota. Any requests conforming to the limits expected do not need emergency quota. But when a request comes in that in some what exceeds the expected limits (typically on resources) I can check if that client have enough emergency quota to process the request. If not; I return an error informing the client they do not have quota to process the request since it exceeds some specified limit.&lt;/p&gt;&lt;p&gt;This way any users that only have an occasional extreme request will never notice what happened. But users that exceed limits a lot will only get a fraction of the requests processed but they will also (hopefully) get a clear error from their client. And whoever maintains the client can clearly see what the problem is.&lt;/p&gt;&lt;p&gt;But the biggest benefit is that I can protect my own service from extreme requests causing a denial of service since the quota check ensures I only process a small fraction of the dangerous requests. It is true I take a small risk this way that always needs to be weighted against the user experience. So this is not a pattern I use all the time, but rather a useful pattern in certain situations.&lt;/p&gt;</description><link>http://blog.cellfish.se/2023/03/using-soft-limits-to-prevent-abuse-with.html</link><author>noreply@blogger.com (cellfish)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4273255328290947077.post-6402334446077385669</guid><pubDate>Thu, 09 Mar 2023 13:00:00 +0000</pubDate><atom:updated>2025-07-21T21:05:42.561-06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">OKR</category><title>OKR mistakes and how to avoid them</title><description>&lt;p&gt;Using OKRs is popular at a lot of companies and has become a golden standard for a lot of companies. But just like how companies start their agile transformation because they heard it was good but without understanding what it is really about. I&#39;ve seen the same thing happen where OKRs are misunderstood.&lt;span&gt;&lt;/span&gt;&lt;/p&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;p&gt;&lt;/p&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;What is OKRs?&lt;/h3&gt;&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/OKR&quot; rel=&quot;nofollow&quot;&gt;OKR&lt;/a&gt; stands for &lt;i&gt;Objectives &lt;b&gt;and &lt;/b&gt;Key Results&lt;/i&gt;. An objective is a higher level goal and does not necessarily need to be easily measurable. Each objective can then have a number for Key Results (KR) to measure progress towards that higher level goal.&lt;/p&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;Mistake #1 - Treating OKR as a single thing&lt;/h3&gt;&lt;p&gt;The largest mistake I&#39;ve seen is when OKRs are treated as a single thing (Objective Key Results AKA Key Performance Indicators (KPI)) when it&#39;s really a combination of two things with a clear hierarchy. When every single KR have their own objective, you also tend to make mistake #2 and/or #4 below.&lt;/p&gt;&lt;p&gt;&lt;b&gt;Note&lt;/b&gt; that using KPIs instead of OKRs is not a bad if you know you are using KPIs. But if you are trying to use OKRs, using KPIs (without the objective) is a mistake.&lt;/p&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;Mistake #2 - Os and/or KRs are just tasks&lt;/h3&gt;&lt;p&gt;This typically happens in an organization where individual OKRs are used. Everybody need their own KRs so the easiest way to accomplish this is to just take something that needs to happen and call it an OKR (ex: &quot;&lt;i&gt;Implement the Foo component&lt;/i&gt;&quot;).&lt;/p&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;Mistake #3 - Objectives change every quarter&lt;/h3&gt;&lt;p&gt;If objectives change all the time it means priorities change all the time or the objective is too short term. And organization where this happens should look at if some of the objectives really are KRs and/or consider what is the longer term objective to achieve.&lt;/p&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;Mistake #4 - Os and/or KRs defines the how&lt;/h3&gt;&lt;p&gt;Since Os and KRs typically span over a longer period of time, if they define how something is expected to be implemented (or released) the team will be bound by an early decision on how to achieve a goal rather than letting the team make that decision when needed. By defining early how to do something you risk exploring the wrong solution or will have to spend time on changing OKRs.&lt;/p&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;Mistake #5 - KRs cannot be measured&lt;/h3&gt;&lt;p&gt;Not every detail of work needs to be measured but if you have a KR that cannot be measured (or can only be measured as a binary - either you are done or not done) it will be time consuming to follow up on the KR and see how it progresses. This can somewhat be mitigated by defining how a KR is measured upfront (ex: &quot;&lt;i&gt;If the KR is implement Foo, we call it 10% complete when design document is approved&lt;/i&gt;&quot;).&lt;/p&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;Mistake #6 - 70% success on each KR is the goal&lt;/h3&gt;&lt;p&gt;There is a recommendation that every team should aim high and hence 70% success on KRs is considered success. For some KRs this could make sense when you set an aggressive target like increase performance by 20%. But there is a risk that you end up with all your KRs being 70% done rather than actually reaching a certain goal. And if all your goals are ambitious and you never reach them the team will likely over time feel dissatisfied since they can never reach any goal set. Actually meeting 70% of the KRs and care less about lower priority KRs is probably much better for the organization both long and short term.&lt;/p&gt;&lt;p&gt;&lt;b&gt;Note &lt;/b&gt;that this mistake is particularly bad when combined with mistake #2 as nothing will be completed. The team just ends up with a lot of unfinished work.&lt;/p&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;Mistake #7 - every layer of the organization needs objectives&lt;/h3&gt;&lt;p&gt;Not everybody needs objectives. They make sense for large organizations and most teams. But a smaller team or individual can just consider the higher level Os and make their own KRs instead of spending time of breaking down a big O into a smaller. That just tends to be reusing a higher level KR as a lower level O. For example if a sales organization has an objective of being the market leader with their product and the KR is to achieve 50% market share. Then a smaller sales team that want to contribute by making 10 sales do not need their own objective in my option. And if you really want them to have their own objective I would suggest using the 50% market share as the small team objective.&lt;/p&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;Mistake #8 - No stack ranking of Os and KRs&lt;/h3&gt;&lt;p&gt;Just like any backlog your Os and KRs need to be stack ranked. This way teams and individuals can easily negotiate to help each other by looking at what KR their work contributes to. There is a mistake within the mistake to be made here. All KRs that belong to the most important O is not necessarily more important all KRs of the second most important O. The objective stack ranking serve as a guidance to the KR stack ranking since most KRs of a high priority O should be higher priority than most of the KRs of a lower priority objective.&lt;/p&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;Good OKR mind-set&lt;/h3&gt;&lt;p&gt;The O should explain why something needs to happen and the KR defines what needs to happen. The how it is achieved should be left to the teams to figure out.&lt;/p&gt;&lt;p&gt;You should also have a mix of long and short term Os and KRs. The longer term Os and KRs guide the organization at a high level and you then use shorter term Os and KRs to guide where you want the organization to focus short term. By long term I mean 1+ years and by shorter term I mean 1-2 quarters.&lt;/p&gt;&lt;p&gt;You should also think of Os as being defined top-down while KRs are defined bottom-up. I.e. stakeholders define the desired outcome with Os and the teams figure out how to best measure success with KRs. Stakeholders and teams then agree on the KRs.&lt;/p&gt;&lt;p&gt;It is also OK to change Os or KRs at any time if needed based on new information, but I think you have a good set of Os and KRs if changing Os or KRs only happens if there is a significant and unexpected change in organization priorities. If you expect KRs to change often, you have the wrong set of KRs.&lt;/p&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;Good OKR process&lt;/h3&gt;&lt;p&gt;I have come up with this process because I have seen it work well a couple of times.&amp;nbsp;&lt;/p&gt;&lt;p&gt;First of all you want an objective that essentially never would change (ex:&lt;i&gt; be the market leader in X&lt;/i&gt;). That objective also needs one or two KRs that represent yearly goals so it would be adjusted every year (ex: &lt;i&gt;we have 40% market share in X&lt;/i&gt;). Both of these are defined top-down in the organization.&lt;/p&gt;&lt;p&gt;If needed you might also have one or two objectives for the year (ex: &lt;i&gt;become market leader in Europe&lt;/i&gt;) that help guide the organization on where to focus. Finally for a quarter you can further guide the organization with an objective (ex: &lt;i&gt;become market leader in Germany&lt;/i&gt;).&lt;/p&gt;&lt;p&gt;I would have each team lead figure out what good team specific KRs would look like for each OKR cycle (ex: &lt;i&gt;make 10 sales in Berlin&lt;/i&gt;).&amp;nbsp;&lt;/p&gt;&lt;p&gt;Finally with all these Os and KRs in place it is up to the team to suggest what activities would contribute to the goals already set. But those activities are not Os or KRs - it is just a backlog for the team on how they plan to achieve the given KRs.&lt;/p&gt;&lt;p&gt;The KRs should be picked in such a way that they are easy to objectively measure and hence become easy to put on a dashboard. That way you can continuously follow up on where you are compared to the goal of each KR.&lt;/p&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;Every team is different&lt;/h3&gt;&lt;p&gt;The Os and KRs will likely look very different depending on what type of work the team is doing. And they are really just tools to guide the team (on a higher level) on what is important and how progress towards those goals look like.&lt;/p&gt;</description><link>http://blog.cellfish.se/2023/03/okr-mistakes-and-how-to-avoid-them.html</link><author>noreply@blogger.com (cellfish)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4273255328290947077.post-7601702237269398276</guid><pubDate>Thu, 08 Dec 2022 19:08:00 +0000</pubDate><atom:updated>2022-12-08T12:08:00.217-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">go</category><title>Go for C# developers: LINQ</title><description>&lt;p&gt;When I worked in C# I &lt;b style=&quot;font-style: italic;&quot;&gt;loved &lt;/b&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;LINQ&lt;/a&gt;. I also probably used it more than I should have. I have recently looked into some options to bring LINQ to a Go project so let me share some observations.&lt;/p&gt;&lt;p&gt;TL;DR: I don&#39;t think we&#39;ll see much use of LINQ in idiomatic Go. Nor should we desire it.&lt;/p&gt;&lt;span&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;/span&gt;&lt;p&gt;But before looking at options, what does LINQ bring to the table? In my opinion LINQ brings two good things to the table.&lt;/p&gt;&lt;p&gt;First it makes it very concise to filter and manipulate collections of data. It can possibly be argued that this conciseness makes programs harder to understand and I agree. Just like any program can be written in an easy or hard way to understand, the usage of LINQ sometimes makes it easier to write hard to understand code. This can however be mitigated by splitting up the LINQ statement into multiple statements.&lt;/p&gt;&lt;p&gt;Second and the most important reason I used LINQ is that it defers enumeration until it is needed. This makes it very easy to abstract fetching data in batches etc, and still do complex computations on the data. This benefit is obviously lost of you sort, or want distinct elements, but a lot of the time this deferred enumeration made my code both efficient and easy to understand.&lt;/p&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;&lt;a href=&quot;https://github.com/ahmetb/go-linq&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;ahmetb/go-linq&lt;/a&gt; - using reflection&lt;/h3&gt;&lt;p&gt;This is a package that predates generics in Go and correctly have identified that there is no easy way to implement LINQ using generics. The good news is that if you are looking for a package that let&#39;s you write LINQ just like in C# this is the package you are looking for. The bad news is performance. There is a lot of memory allocations and since it is using reflection you don&#39;t have compile time type safety.&lt;/p&gt;&lt;h4 style=&quot;text-align: left;&quot;&gt;ahmetb/go-linq&amp;nbsp;&lt;a href=&quot;https://github.com/ahmetb/go-linq/pull/112&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;pull request&lt;/a&gt; - adding generics&lt;/h4&gt;&lt;p&gt;The main reason why adding generics to this package is hard is because the generic types can only be on functions types, &lt;a href=&quot;https://go.googlesource.com/proposal/+/refs/heads/master/design/43651-type-parameters.md#No-parameterized-methods&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;&lt;i&gt;not &lt;/i&gt;on receiver methods&lt;/a&gt;. Hence something like &lt;span style=&quot;font-family: courier;&quot;&gt;Select&lt;/span&gt; becomes a little cumbersome to implement. This pull request works around that limitation by introducing a new intermediary type that holds all the types that are needed and hence increases the length of your LINQ statement. That intermediary step also becomes confusing I think.&lt;/p&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;&lt;a href=&quot;https://github.com/samber/lo&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;samber/lo&lt;/a&gt; - using generics&lt;/h3&gt;&lt;p&gt;This package is really a bunch of small helpers and does not claim to be a replacement for LINQ. This package will not allow you to make any &quot;method trains&quot; as each function will take the collection as an argument (i.e. receiver methods not used). These helpers also do not defer enumeration as they operate directly on slices and channels which means performance is just as good as if you manually do your processing. Since these helpers don&#39;t do anything other than hide a few for statements from you, the usage seems questionable to me, and definitely not idiomatic to Go where explicit implementations is preferred.&lt;/p&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;&lt;a href=&quot;https://github.com/szmcdull/glinq&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;szmcdull/glinq&lt;/a&gt; - copying IEnumerable&lt;/h3&gt;&lt;p&gt;This is an interesting approach where similar to samber/lo the constraints with generics is circumvented by only using functions rather than receiver methods. It introduces a copy implementation of &lt;span style=&quot;font-family: courier;&quot;&gt;IEnumerable&lt;/span&gt; from C# to defer enumeration. I think this implementation could have been much more idiomatic reusing the &lt;span style=&quot;font-family: courier;&quot;&gt;Iterable&lt;/span&gt; concept used in the internals of ahmetb/go-linq.&lt;/p&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;Conclusions&lt;/h3&gt;&lt;p&gt;Given the constraints in how generics are implemented in Go I don&#39;t expect to see anything like LINQ be used very much. And I have come to think that is a good thing. A long chain of function calls where each of them perform fairly simple tasks does not really make the code easier to understand. Even when using an approach where each part of the chain is independent (as in the last two examples above) the value of these generic methods is very limited compared to explicitly perform the desired actions.&lt;/p&gt;&lt;p&gt;Since LINQ really shines when it comes the the deferred enumeration of (partially) asynchronous steps, there already is a good solution for that in Go; channels. So the use of an interface like in the last example above is again not adding much value.&lt;/p&gt;&lt;p&gt;Another interesting observation is that maybe LINQ is a terribly idea in the first place. In &lt;i&gt;all&lt;/i&gt; languages. It is certainly nice to create a chain of actions (i.e. a data processing pipeline) and reuse that on different pieces of data, regardless of if the data is available all at once or not. And it might be helpful to have this data pipeline hide that fact. However, I don&#39;t think that means it is the most maintainable solution to achieve the same result. At the end of the day, maybe LINQ is best suitable to allow people familiar with databases to easily convert their SQL skills into another programming language, but I am no longer convinced LINQ is a good tool if you know the language well and want to do data processing.&lt;/p&gt;&lt;h4 style=&quot;text-align: left;&quot;&gt;Final thoughts&lt;/h4&gt;&lt;p&gt;Since this was not the outcome of my research into LINQ for Go and I&#39;m sure this opinion is not the most popular (especially among C# programmers), I&#39;d love to get examples (in Go and C#) where a LINQ statement is actually easier to understand than the alternative (explicit code). And remember shorter does not necessarily mean easier to understand!&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://go.dev/play/p/C1lO1M0sv7U&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;Here&lt;/a&gt; is an example I created that is border line better as LINQ. The use of &lt;span style=&quot;font-family: courier;&quot;&gt;Distinct&lt;/span&gt; and &lt;span style=&quot;font-family: courier;&quot;&gt;Sort&lt;/span&gt; is very short and clear, but the Go version is not much longer and follows the usual patterns for achieving the same thing. And even in a simple example like this, the non-LINQ version has the benefit of doing &lt;span style=&quot;font-family: courier;&quot;&gt;Select&lt;/span&gt; and &lt;span style=&quot;font-family: courier;&quot;&gt;Distinct&lt;/span&gt; in one place rather than separating them.&lt;/p&gt;</description><link>http://blog.cellfish.se/2022/12/go-for-c-developers-linq.html</link><author>noreply@blogger.com (cellfish)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4273255328290947077.post-6324918591444670349</guid><pubDate>Thu, 24 Nov 2022 16:00:00 +0000</pubDate><atom:updated>2022-11-24T09:00:00.219-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">go</category><title>Go for C# developers: Unicode strings</title><description>&lt;p&gt;&amp;nbsp;There are a few gotchas with strings in Go if they contain unicode characters.&lt;/p&gt;&lt;span&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;/span&gt;&lt;p&gt;For example, if you loop over a string using &lt;span style=&quot;font-family: courier;&quot;&gt;range&lt;/span&gt; to get all characters, you will actually only loop over the starting index for each character. Similarly the built in &lt;span style=&quot;font-family: courier;&quot;&gt;len&lt;/span&gt; function will return the number of bytes used in the string and not the number of visible characters.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://go.dev/play/p/xQJquwfSFfU&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;Here is an example&lt;/a&gt; showing how the index variable is &quot;jumping&quot; to each character in the string and how accessing each character in the string using that index is not working as expected.&lt;/p&gt;</description><link>http://blog.cellfish.se/2022/11/go-for-c-developers-unicode-strings.html</link><author>noreply@blogger.com (cellfish)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4273255328290947077.post-4749678092644778322</guid><pubDate>Thu, 08 Sep 2022 14:09:00 +0000</pubDate><atom:updated>2022-09-08T08:09:00.229-06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">go</category><title>Go for C# developers: Using keywords as identifiers</title><description>&lt;p&gt;It doesn&#39;t happen very often but sometimes there is a variable name that makes sense that happens to be a reserved word in the language. In C# when this happens you prefix it with &quot;@&quot; so you get &lt;span style=&quot;font-family: courier;&quot;&gt;&lt;b&gt;@new&lt;/b&gt;&lt;/span&gt; as a variable name. Not quite as clean with the prefix, but clear what is going on. Go takes a different approach.&lt;/p&gt;&lt;span&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;/span&gt;&lt;p&gt;It&#39;s a lesser known fact, but the number of &lt;a href=&quot;https://go.dev/ref/spec#Keywords&quot;&gt;reserved keywords&lt;/a&gt; in Go are actually not that many. Note how none of the built-in basic types or functions are actually reserved. Those are instead &lt;a href=&quot;https://go.dev/ref/spec#Predeclared_identifiers&quot;&gt;predeclared identifiers&lt;/a&gt;. The difference is that while reserved keywords can not be used as identifiers, all the predeclared identifiers can be used as identifiers. That is no different than when you declare a variable with a smaller scope when one is already used in the larger scope.&lt;/p&gt;&lt;p&gt;Reusing variable names in a smaller scope is mostly a bad idea since it is harder to spot bugs where you did not intend to actually use a smaller scope (&lt;a href=&quot;https://go.dev/play/p/ej-1gPzP1YH&quot;&gt;example&lt;/a&gt;), it is very nifty when reusing a name, but having a newly scoped variable makes the code more clear.&lt;/p&gt;&lt;p&gt;Redefining predeclared identifiers in a smaller scope suffers from the same problem of potentially causing confusion, but especially the ability to use variable names as &quot;new&quot; and &quot;copy&quot; without having to worry about prefixing them can certainly make the code more clear.&lt;/p&gt;&lt;p&gt;That being said, there is almost always alternatives that are guaranteed to avoid confusion and I would recommend looking to those first. For example &quot;n&quot; is a pretty good replacement for &quot;new&quot; and &quot;clone&quot; is a pretty good replacement for &quot;copy&quot;.&lt;/p&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;But...&lt;/h3&gt;&lt;div&gt;If you&#39;re still looking to redefined the predeclared identifiers you can have a lot of fun and not only use them as variable names but also types and function names (these are all identifiers). If your code needs to handle string lights, &lt;a href=&quot;https://go.dev/play/p/OruFlnuTeKY&quot;&gt;this is some terrible inspiration&lt;/a&gt; on how to do that.&lt;/div&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;What if I like prefixing like in C#?&lt;/h3&gt;&lt;div&gt;Well, the go specification does not let you prefix with &quot;@&quot;, but just like in C# you can use unicode in your identifiers so if you &lt;i&gt;really &lt;/i&gt;want to name a variable &lt;span style=&quot;font-family: courier;&quot;&gt;switch&lt;/span&gt;, I got &lt;a href=&quot;https://go.dev/play/p/H9NGayOciVW&quot;&gt;some options&lt;/a&gt; for you.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;Let me know what your colleagues think of your creative use of unicode and variable names!&lt;/i&gt;&lt;/div&gt;</description><link>http://blog.cellfish.se/2022/09/go-for-c-developers-using-keywords-as.html</link><author>noreply@blogger.com (cellfish)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4273255328290947077.post-5559334741303123378</guid><pubDate>Thu, 23 Jun 2022 18:03:00 +0000</pubDate><atom:updated>2022-06-23T12:03:44.769-06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">test</category><title>What is the purpose of a test name?</title><description>Since I&#39;m certainly a person who has been passionate about how tests are named, &lt;a href=&quot;https://blog.ploeh.dk/2022/06/13/some-thoughts-on-naming-tests/&quot;&gt;this article&lt;/a&gt; first made me a little upset since it &lt;i&gt;almost&lt;/i&gt;&amp;nbsp;suggested &lt;span style=&quot;font-family: courier;&quot;&gt;Test123&lt;/span&gt; to be a good name. But as I kept reading I started to question my own crusade regarding test names quite a bit.&lt;span&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;/span&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;At first I started to think about where my passion for test names came from. I started being passionate about test names a long time ago when I was working on a project where most tests were run after code was checked in. And the continuous integration server did not have a nice integration into the code base. Hence it was very costly to open up the IDE and search for a test name to look at the test code figure out what was wrong. Instead well names tests with good failure messages made it possible to quickly understand where the problem was and ask the right person to fix the problem.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Today we have better tools. And this scenario is very different than the scenario described in the article I read which is more about understanding failures as you are writing code. Similar to that author I also tend to use placeholder names while writing tests until I know what the test should really look like. And the final step for me is to give the test a name that signals intent so that future developers (including myself) know what the intent of the test was.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So in digesting that article I have come to realize that I should probably be less passionate about the naming of the tests and just continue to be passionate about what is tested and how failures are reported. Those two things are more important to me as I still consider tests to be the ultimate documentation of what I want to code to do. And as such, the name serves little more value than a summary of intent.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In the end this article also served as a good reminder to myself that in software engineering you should never stop learning.&lt;/div&gt;</description><link>http://blog.cellfish.se/2022/06/what-is-purpose-of-test-name.html</link><author>noreply@blogger.com (cellfish)</author><thr:total>2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4273255328290947077.post-4180509684242033044</guid><pubDate>Thu, 07 Apr 2022 13:04:00 +0000</pubDate><atom:updated>2022-04-07T07:04:00.177-06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">agile</category><category domain="http://www.blogger.com/atom/ns#">google</category><category domain="http://www.blogger.com/atom/ns#">microsoft</category><category domain="http://www.blogger.com/atom/ns#">teams</category><title>The social standup</title><description>&lt;p&gt;Reading about a &lt;a href=&quot;https://www.thoughtworks.com/radar/techniques?blipid=202203099&quot;&gt;new idea for remote standups&lt;/a&gt; in the &lt;a href=&quot;https://www.thoughtworks.com/radar&quot;&gt;Thoughtworks Tech Radar&lt;/a&gt; reminded me of a few similar experiences I&#39;ve had.&lt;/p&gt;&lt;span&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;/span&gt;&lt;p&gt;The idea described in the Tech Radar is that when the whole team is remote they lose out on ad-hoc opportunities for discussions. So rather than having a short standup everyday, the team blocks off much more time (up to an hour) so that there is plenty of time blocked off for discussions after the standup is completed. It is also pointed out that it doesn&#39;t have to be work related discussions but socialization is important too.&lt;/p&gt;&lt;p&gt;That part reminded me of the remotes standups my team started to have in the beginning of the COVID pandemic when everybody had to work form home. I don&#39;t think it was the work related exchange that was the most important but rather that we made a habit of joining early, exchange some jokes or stories and then hang out after the standup when possible. And I think this social aspect of our standups brought the team closer together.&lt;/p&gt;&lt;p&gt;I also remember back in the days when I worked on Xbox and we had a fairly large team doing standups together despite the fact that most of us didn&#39;t actually have work that affected each other directly. Hence everybody would spend most time in the standup listening to things most of us didn&#39;t care much about. A question was raised if we should split the standup into smaller standups so that we wouldn&#39;t waste everybody&#39;s time so much. Much to my surprise the team decided to &lt;i&gt;&lt;b&gt;not&lt;/b&gt;&lt;/i&gt; split the standup since we felt that the minutes of jokes and socialization as we gathered for the standup was worth so much for the team morale compared to the perceived loss of efficiency when everybody had to attend a slightly longer standup (because of how many people we were).&lt;/p&gt;&lt;p&gt;So while the social component in a remote standup really resonates with me - I think we should not forget that it can have a lot of value also in-person.&lt;/p&gt;</description><link>http://blog.cellfish.se/2022/04/the-social-standup.html</link><author>noreply@blogger.com (cellfish)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4273255328290947077.post-5131670523221805790</guid><pubDate>Thu, 24 Feb 2022 21:12:00 +0000</pubDate><atom:updated>2022-05-01T15:59:23.480-06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">ux</category><title>How to annoy your users featuring Volvo</title><description>&lt;p&gt;I&#39;ve owned a Volvo since 2017 and I would have hoped would have been fixed by a software update at this time, but no. So here are two things that annoy me pretty much every time I use the car. And then a third recent WTF moment.&lt;span&gt;&lt;/span&gt;&lt;/p&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;p&gt;&lt;/p&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;Driver specific keys and seat adjustments&lt;/h3&gt;&lt;p&gt;There are separate seat adjustments for myself and my wife. Basically I&#39;m taller than my wife and I want zero lumbar support while my wife want plenty of lumbar support. Our personal settings are programmed into separate buttons in the car. We also have our own personal keys that are paired with our respective seat settings.&lt;/p&gt;&lt;p&gt;So every time my wife has used the car and I open the car with my key the seat adjusts to my settings, right? No, maybe half the time the seat adjusts position and the rest of the time I need to push my button in the car. Then the seat adjusts position but not the lumbar support! In order to adjust the lumbar support I need to keep my personalized setting button pressed until the lumbar support adjusts.&lt;/p&gt;&lt;p&gt;How is this a thing? The lumbar support position is obviously programmed into the system but for some reason it does not adjust that automatically the same way the seat position does.&lt;/p&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;Always turn on music&lt;/h3&gt;&lt;p&gt;So if I listened to a podcast on my phone (connected to the car) in my last drive I probably wanna continue listening the next time I get into the car, right? But my phone is not connected when I open the door to the car so what does the car do? Obviously it turns on a random radio station.&lt;/p&gt;&lt;p&gt;So I figured, maybe I should turn off my podcast before turning off the car so it doe snot automatically turn on the radio. I&#39;ve tried turning my podcasts off several minutes before stopping and turning off the car. Still no success - my car really wants me to listen to the radio.&lt;/p&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;Service required means replace a fuse&lt;/h3&gt;&lt;p&gt;I recently, during cold weather, had some problems with the adjustable suspension on the car. And the next day there was a message from the car telling me I need to service the suspension of the car. Since the adjustable suspension was not working I got an appointment to get it fixed.&lt;/p&gt;&lt;p&gt;Turned out the fuse for the suspension needed to be replaced. I wish the car would tell me a fuse was broken (or indicate no power to the suspension system) rather than suggest I need to service the car.&lt;/p&gt;</description><link>http://blog.cellfish.se/2022/02/how-to-annoy-your-users-featuring-volvo.html</link><author>noreply@blogger.com (cellfish)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4273255328290947077.post-6573606680219625281</guid><pubDate>Thu, 10 Feb 2022 09:10:00 +0000</pubDate><atom:updated>2022-02-10T02:10:00.182-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">interviews</category><title>A coding interview that never happened</title><description>&lt;p&gt;I&#39;ve conducted hundreds of interviews that involve some kind of problem solving and most of them involved writing the solution in code. And most candidates make the same mistake so I figured it was time to share a simple strategy that seems to have worked for me over the years when I was the candidate.&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;The strategy is simple - &lt;i&gt;solve the problem and write the code the same way you would solve a problem outside an interview&lt;/i&gt;. What it means is; if the problem seems too large/complex and you don&#39;t know how to solve it, then you need to break the problem down in smaller parts. Similarly when you write your code you should not write a single large function with a solution but rather split the code up in a number of functions that make sense.&lt;p&gt;&lt;/p&gt;&lt;p&gt;Let me use an example to show you what I mean. I have never solved the &lt;a href=&quot;https://en.wikipedia.org/wiki/Tower_of_Hanoi&quot;&gt;Tower of Hanoi&lt;/a&gt; in any way and when I started thinking about this problem, at first I had no idea to how I would solve the problem. So I started thinking about the simple cases:&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;ol style=&quot;text-align: left;&quot;&gt;&lt;li&gt;If I only need to move one disk - I know how to do that.&lt;/li&gt;&lt;li&gt;If I only need to move two disks - I know how to do that since I can use the extra pin as temporary storage for the first disk until I get the second one in place.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;So the second statement made me think that the essence of the algorithm to solve Tower of Hanoi is to move N-1 disks to temporary storage since that will allow me to move N disks do the desired location.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In other words the essence of the algorithm is (pseudo code):&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;blockquote style=&quot;border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;&quot;&gt;&lt;blockquote style=&quot;border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;&quot;&gt;&lt;p&gt;&lt;/p&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;move(n, from, to) {&lt;/span&gt;&amp;nbsp;&lt;/div&gt;&lt;/blockquote&gt;&lt;/blockquote&gt;&lt;blockquote style=&quot;border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;&quot;&gt;&lt;blockquote style=&quot;border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;&quot;&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp;if&lt;/span&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp;(n &amp;lt;= 0) {&lt;/span&gt;&amp;nbsp;&lt;/div&gt;&lt;/blockquote&gt;&lt;/blockquote&gt;&lt;blockquote style=&quot;border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;&quot;&gt;&lt;blockquote style=&quot;border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;&quot;&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; return&lt;/span&gt;&amp;nbsp;&lt;/div&gt;&lt;/blockquote&gt;&lt;/blockquote&gt;&lt;blockquote style=&quot;border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;&quot;&gt;&lt;blockquote style=&quot;border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;&quot;&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp;}&lt;/span&gt;&amp;nbsp;&lt;/div&gt;&lt;/blockquote&gt;&lt;/blockquote&gt;&lt;blockquote style=&quot;border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;&quot;&gt;&lt;blockquote style=&quot;border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;&quot;&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp;move(n-1, from, temp)&lt;/span&gt;&amp;nbsp;&lt;/div&gt;&lt;/blockquote&gt;&lt;/blockquote&gt;&lt;blockquote style=&quot;border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;&quot;&gt;&lt;blockquote style=&quot;border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;&quot;&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp;move(1, from, to)&lt;/span&gt;&amp;nbsp;&lt;/div&gt;&lt;/blockquote&gt;&lt;/blockquote&gt;&lt;blockquote style=&quot;border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;&quot;&gt;&lt;blockquote style=&quot;border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;&quot;&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp;move(n-1, temp, to)&lt;/span&gt;&amp;nbsp;&amp;nbsp;&lt;/div&gt;&lt;/blockquote&gt;&lt;/blockquote&gt;&lt;blockquote style=&quot;border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;&quot;&gt;&lt;blockquote style=&quot;border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;&quot;&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;At this point I frankly have no idea if there is a corner case where this does not work, but trying the algorithm with three disks also works so let&#39;s give it a try...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In an interview setting I would now start implementing the main function and leave any helpers out. Those can be implemented if there is time as needed. When I sat down and actually implemented this I realized a stack would be good to have so I created one. A helper function to figure out the temporary pin would also be nice to have so I added one of those too. I was also very paranoid that my solution would violate the disk size rule so I added a check in my stack to make sure I never put a disk larger than the previous disk in any stack. I was honestly surprised when I could see my implementation working for any number of disks. I really expected there to be some corner case this simple algorithm would not handle. And the resulting code can be found here:&amp;nbsp;&lt;a href=&quot;https://go.dev/play/p/CLm-oPmyfi5&quot;&gt;https://go.dev/play/p/CLm-oPmyfi5&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Bottom line;&lt;/b&gt; breaking down the problem into smaller manageable chunks and solve each of those tends to always work. And breaking down your implementation by using helper functions tends to let you keep moving without getting stuck on implementation details.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I realize this advice may seem generic and not helpful, but still I&#39;ve seen so many candidates over the years that fail because they do not break the problem down and start simple. So this is still my best advice.&lt;/div&gt;&lt;p&gt;&lt;/p&gt;</description><link>http://blog.cellfish.se/2022/02/a-coding-interview-that-never-happened.html</link><author>noreply@blogger.com (cellfish)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4273255328290947077.post-8703467065646957308</guid><pubDate>Thu, 20 Jan 2022 15:01:00 +0000</pubDate><atom:updated>2022-01-20T08:01:00.218-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">relocating</category><title>Fire and the US insurance system</title><description>&lt;p&gt;It has been a long time since there was something interesting to write about in regards to relocating to the US. And it is a weird coincidence that once I started blogging again - something happened that makes me pick up this topic again. Since I lost a home in the &lt;a href=&quot;https://en.wikipedia.org/wiki/2021%E2%80%932022_Boulder_County_fires#Marshall_Fire&quot;&gt;Marshall Fire&lt;/a&gt; I&#39;m about to learn a lot about insurance companies in the US.&lt;/p&gt;&lt;span&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;/span&gt;&lt;p&gt;Compared to a lot of victims in the fire we were very lucky; we were never in any danger evacuating and since we recently moved into the house we still had a box of all valuables and important documents packed so we could quickly grab those and have not had to deal with replacing various documents.&lt;/p&gt;&lt;p&gt;I have also learned that people in this area are extremely willing to help people in need and I have learned quickly to accept any offers for help. Even small things like not having to cook a meal or a small gift card is helpful to everybody in a situation like this.&lt;/p&gt;&lt;p&gt;An alarming thing however is that there seems to be a disconnect between insurance companies and builders and the expectation is that the majority of home owners are under insured meaning insurance will not cover all the cost to rebuild homes. It will be interesting to see how this plays out and the effect on the community because of this.&lt;/p&gt;&lt;p&gt;So if you live in the US - call your insurance company and make sure you have coverage to rebuild a home - even with recent rapid increase in building costs!&lt;/p&gt;</description><link>http://blog.cellfish.se/2022/01/fire-and-us-insurance-system.html</link><author>noreply@blogger.com (cellfish)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4273255328290947077.post-6091121509700878773</guid><pubDate>Thu, 30 Dec 2021 19:30:00 +0000</pubDate><atom:updated>2021-12-30T12:30:00.235-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">google</category><category domain="http://www.blogger.com/atom/ns#">interviews</category><title>Yet another tale from an interview - 13 years later</title><description>&lt;p&gt;A little over 13 years ago I wrote something short about my Microsoft interview experience (&lt;a href=&quot;https://web.archive.org/web/20140408084007/http://blogs.msdn.com/b/cellfish/archive/2008/09/12/yet-another-tale-from-an-interview.aspx&quot;&gt;now only available in web archive&lt;/a&gt;). Back then the format was a shocker to a naive swede and now 13 years later and several interviews later I figured I&#39;ll write something about my experience going through the Google recruitment process.&lt;/p&gt;&lt;p&gt;Rather than me writing a long thing here you might as well read &lt;a href=&quot;http://steve-yegge.blogspot.com/2008/03/get-that-job-at-google.html&quot; target=&quot;_blank&quot;&gt;this&lt;/a&gt; which pretty much explains my experience in general.&lt;/p&gt;&lt;p&gt;If that blog post is too long here are the important things from my own experience.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;ul style=&quot;text-align: left;&quot;&gt;&lt;li&gt;&lt;b&gt;You don&#39;t get a &lt;i&gt;yes&lt;/i&gt; or a &lt;i&gt;no&lt;/i&gt;&lt;/b&gt; - you get a &lt;i&gt;yes&lt;/i&gt; or &lt;i&gt;not now&lt;/i&gt;. Failing a Google interview is not a big deal since there are several reasons a good candidate fails to prove them selves. Get your chin up and try again.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Be humble&lt;/b&gt; - if you are asked to implement Fibonacci with your 10+ years of experience just write the best damn Fibonacci the interviewer has ever seen with a smile on your face.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Prepare&lt;/b&gt; - the &lt;a href=&quot;http://www.crackingthecodinginterview.com/&quot; target=&quot;_blank&quot;&gt;cracking the coding interview book&lt;/a&gt; is actually a pretty good prep tool. I coded on paper one hour every night for weeks. And don&#39;t be over confident if you are asked a question from the book because those problems have more depth than the solutions shown in the book. If you are too lazy for that there is a rule of thumb I realized preparing; if you can solve something with a hash table or graph - you probably should. A lot of problems can be reduced into hash table or graph problems so learn how to identify and solve those.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Think differently&lt;/b&gt; - Google do things on a different scale than almost everybody else. This means that things that are important to other companies don&#39;t matter at Google. That is; if you can speed up things by preparing the data for a repeated operation - you probably should, even if it means using thousands of machines and/or huge amounts of memory.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;And most important; have fun. Even if I would not have gotten an offer I had a blast interviewing and would have tried again.&lt;/p&gt;</description><link>http://blog.cellfish.se/2021/12/yet-another-tale-from-interview-13.html</link><author>noreply@blogger.com (cellfish)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4273255328290947077.post-1339866656497878773</guid><pubDate>Wed, 22 Dec 2021 19:22:00 +0000</pubDate><atom:updated>2021-12-22T12:22:00.220-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">news</category><title>Still there?</title><description>&lt;p&gt;When I &lt;a href=&quot;/2016/12/a-new-schedule.html&quot;&gt;decided to not post regularly&lt;/a&gt;, it apparently resulted in &lt;i&gt;never&lt;/i&gt;. Well, I&#39;ve decided it&#39;s time to change that after five years of silence.&lt;/p&gt;</description><link>http://blog.cellfish.se/2021/12/still-there.html</link><author>noreply@blogger.com (cellfish)</author><thr:total>2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4273255328290947077.post-1135463065303690312</guid><pubDate>Thu, 22 Dec 2016 08:22:00 +0000</pubDate><atom:updated>2016-12-22T01:22:09.098-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">news</category><title>A new schedule</title><description>For a long time I&#39;ve made sure that there was something happening here on a regular basis. I&#39;ve decided &lt;i&gt;regular &lt;/i&gt;is no longer going to be the case.</description><link>http://blog.cellfish.se/2016/12/a-new-schedule.html</link><author>noreply@blogger.com (cellfish)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4273255328290947077.post-3000411618968077138</guid><pubDate>Thu, 15 Dec 2016 11:12:00 +0000</pubDate><atom:updated>2016-12-15T04:12:11.185-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">.net</category><category domain="http://www.blogger.com/atom/ns#">tap</category><title>All in on async/await</title><description>While I haven&#39;t been coding in C# for about a year now I couldn&#39;t resist reading &lt;a href=&quot;http://blog.stephencleary.com/2016/12/eliding-async-await.html&quot; rel=&quot;nofollow&quot;&gt;this recent article&lt;/a&gt;. A nice write-up where I only want to make two additions.&lt;br /&gt;
&lt;div&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
First I want to make certain you get what I think is the message in the article; if you are using async/await you should go all in as not doing so will have surprising result if you are not ready for them.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Second the author of the article mentions that the overhead of async/await is tiny. But if I remember correctly there are some compiler optimizations that make certain things having even less overhead such as returning completed tasks.&lt;/div&gt;
</description><link>http://blog.cellfish.se/2016/12/all-in-on-asyncawait.html</link><author>noreply@blogger.com (cellfish)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4273255328290947077.post-2776542693386741219</guid><pubDate>Thu, 08 Dec 2016 16:12:00 +0000</pubDate><atom:updated>2016-12-08T09:12:01.647-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">go</category><title>Go for C# developers: functions vs methods</title><description>I must admit that I often use the words &lt;i&gt;function&lt;/i&gt; and &lt;i&gt;method&lt;/i&gt; interchangeable. Probably because I was once taught that a method is a function that does not return anything. In the Go vocabulary however there is a clear difference and a nice method gotcha!&lt;div&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Another common mistake C# developers do is to talk about &lt;i&gt;class methods&lt;/i&gt; in Go. Go people hate this and politely let you know there are no classes in Go. So to all C# developers out there; what &quot;looks&quot; like a class method, that is a function that is defined as being attached to a specific type is in Go called a &lt;a href=&quot;https://golang.org/ref/spec#Method_declarations&quot; rel=&quot;nofollow&quot;&gt;method&lt;/a&gt;. Everything else is a &lt;a href=&quot;https://golang.org/ref/spec#Function_declarations&quot; rel=&quot;nofollow&quot;&gt;function&lt;/a&gt;.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
A really fun gotcha with methods in Go is that if you declare your receiver as being by-value then you can create setters that don&#39;t change the instance used to call the method. Here is a &lt;a href=&quot;https://play.golang.org/p/uQPXElFw4u&quot; rel=&quot;nofollow&quot;&gt;snippet to demonstrate that&lt;/a&gt;. Cut-n-pasting method receiver definitions can definitely lead to bugs if you do not consider your definitions carefully.&lt;/div&gt;
</description><link>http://blog.cellfish.se/2016/12/go-for-c-developers-functions-vs-methods.html</link><author>noreply@blogger.com (cellfish)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4273255328290947077.post-6151389842006888648</guid><pubDate>Thu, 01 Dec 2016 09:12:00 +0000</pubDate><atom:updated>2016-12-01T02:12:01.516-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">relocating</category><category domain="http://www.blogger.com/atom/ns#">TBT</category><title>Relocation, relocation, relocation</title><description>Looking back at &lt;a href=&quot;https://blogs.msdn.microsoft.com/cellfish/2009/3/&quot; rel=&quot;nofollow&quot;&gt;March 2009&lt;/a&gt; there is not much stuff that I still find interesting.&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;To be honest the relocation stuff is the only stuff that still feels relevant because &lt;a href=&quot;https://blogs.msdn.microsoft.com/cellfish/2009/03/19/the-amazing-auto-woman/&quot; rel=&quot;nofollow&quot;&gt;buying a car is still a pain&lt;/a&gt;, &lt;a href=&quot;https://blogs.msdn.microsoft.com/cellfish/2009/03/11/getting-a-drivers-license-in-the-us/&quot; rel=&quot;nofollow&quot;&gt;getting a driver&#39;s license is a joke&lt;/a&gt; and &lt;a href=&quot;https://blogs.msdn.microsoft.com/cellfish/2009/03/03/mobile-phone-costs-in-the-us/&quot; rel=&quot;nofollow&quot;&gt;cell phone plans are still expensive&lt;/a&gt; compared to Sweden. Apart from that &lt;a href=&quot;https://blogs.msdn.microsoft.com/cellfish/2009/03/23/code-stewardship/&quot; rel=&quot;nofollow&quot;&gt;code stewardshi&lt;/a&gt;p is probably the only post still worth reading.</description><link>http://blog.cellfish.se/2016/12/relocation-relocation-relocation.html</link><author>noreply@blogger.com (cellfish)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4273255328290947077.post-7453967124754889870</guid><pubDate>Thu, 24 Nov 2016 08:11:00 +0000</pubDate><atom:updated>2016-11-24T01:11:00.157-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">agile</category><title>Scrum is like riding a bike with training wheels.</title><description>Over the years I&#39;ve grown to dislike Scrum, mostly because I&#39;ve seen it abused and misunderstood. And an approach that makes it easy to screw up is not a good approach in my opinion.&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;And before you put me in the Scrum-haters bucket let me be clear: I think Scrum is a great way to boot-strap a team that wants to be agile. But I do not believe it is &lt;i&gt;the &lt;/i&gt;best method out there to get there. All approaches considered without any constraints.&lt;br /&gt;
&lt;br /&gt;
The reason is that Scrum lets you focus on the practice of Scrum without having to think too much about why Scrum tells you to do certain things. This is awesome if you want to get from the dark ages of waterfall into the wonderland of agile, but if you don&#39;t get the fact that you need to learn and evolve, then you haven&#39;t achieved much I think.&lt;br /&gt;
&lt;br /&gt;
It&#39;s like learning to ride a bicycle with training wheels. Every parent I know will tell you that you can have your kid ride around with training wheels for months (or years) without any real progress until you actually take the time and take those training wheels away, give your &lt;strike&gt;team&lt;/strike&gt; kid proper help (coaching) and within hours they can ride the bike properly. Without training wheels.&lt;br /&gt;
&lt;br /&gt;
Scrum is like riding a bike with training wheels. You wont hurt your self, you will definitely get to your destination, but it wont be pretty and it is definitely not riding a bicycle. You need to take those training wheels off and as you do so you need both the will to learn and proper help to get you there.&lt;br /&gt;
&lt;br /&gt;
What triggered me to write this post was this &lt;a href=&quot;http://ronjeffries.com/articles/016-09ff/defense/&quot; rel=&quot;nofollow&quot;&gt;Dark-Scrum&lt;/a&gt; post which is an excellent read. Because it helps you to see when those training wheels needs to come off...</description><link>http://blog.cellfish.se/2016/11/scrum-is-like-riding-bike-with-training.html</link><author>noreply@blogger.com (cellfish)</author><thr:total>2</thr:total></item></channel></rss>