tag:blogger.com,1999:blog-64386667385614042962024-03-27T13:28:39.531+01:00devCrowdLet's do IT empathicallyJanek Fellienhttp://www.blogger.com/profile/11037083301535227855noreply@blogger.comBlogger43125tag:blogger.com,1999:blog-6438666738561404296.post-77660401902232248652024-03-27T10:39:00.009+01:002024-03-27T10:39:55.642+01:00Conditional Values in Azure Pipelines<p><img alt="An artificial pipeline in a wood with a valve and dividers" class="bg tc ue c" height="467" src="https://miro.medium.com/v2/resize:fit:764/0*DiNA5hrVxP3oxYF1" width="700" /> <br /></p><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="abe9">In
some cases, you may want to change the value of an Azure Pipeline
variable depending on the environment data. When I was looking for a way
to do this, I couldn’t find many examples, so I’ll describe my solution
here, maybe it will help you too.</p><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="eadb">Normally, a condition is prepared as follows.</p><pre class="wo wp wq wr ws wt wu wv bo ww ba bj"><span class="wx vm pd wu b bf wy wz l xa xb" data-selectable-paragraph="" id="5683"><blockquote> <span class="hljs-attr">variables:</span><br /> <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">AZ_IS_MAIN_DEPLOYMENT</span><br /> <span class="hljs-attr">value:</span> <span class="hljs-string">$[eq(variables['Build.SourceBranch'],</span> <span class="hljs-string">'refs/heads/main'</span><span class="hljs-string">)]</span></blockquote><span class="hljs-string"></span></span></pre><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="7bbf">Here, the Variable <code class="hy aiu aiv aiw wu b">AZ_IS_MAIN_DEPLOYMENT</code> gets a <code class="hy aiu aiv aiw wu b">true</code> or <code class="hy aiu aiv aiw wu b">false</code>, depending on the branch. In later steps you use the variable to control tasks, steps and so on by set the <code class="hy aiu aiv aiw wu b">condition</code>value. But in my underlying use case, I needed a condition where the value of my variable gets an <code class="hy aiu aiv aiw wu b">production</code> or <code class="hy aiu aiv aiw wu b">dev</code> value (Btw, it was for the deployment slot of a Static Web App 😉)</p><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="0f63">My solution is to set a variable value by use the key word <code class="hy aiu aiv aiw wu b">if</code> in a kind of attribute on top of the variable value.</p><pre class="wo wp wq wr ws wt wu wv bo ww ba bj"><span class="wx vm pd wu b bf wy wz l xa xb" data-selectable-paragraph="" id="d3af"><span class="hljs-attr"></span><blockquote><span class="hljs-attr">variables:</span><br /> <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">AZ_DEPLOYMENT_ENV_NAME</span><br /> <span class="hljs-string">${{</span> <span class="hljs-string">if</span> <span class="hljs-string">eq(variables['Build.SourceBranch'],</span> <span class="hljs-string">'refs/heads/main'</span><span class="hljs-string">)</span> <span class="hljs-string">}}:</span><br /> <span class="hljs-attr">value:</span> <span class="hljs-string">production</span><br /> <span class="hljs-string">${{</span> <span class="hljs-string">else</span> <span class="hljs-string">}}:</span><br /> <span class="hljs-attr">value:</span> <span class="hljs-string">dev</span></blockquote><span class="hljs-string"></span></span></pre><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="8b68">Very important is the indentation of <code class="hy aiu aiv aiw wu b">value</code> here. It will not work, if it’s not set.</p><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="3804">I’ve not tested a <code class="hy aiu aiv aiw wu b">else if</code> condition yet. Feel free to do so and let me know if it works.</p>Janek Fellienhttp://www.blogger.com/profile/11037083301535227855noreply@blogger.comtag:blogger.com,1999:blog-6438666738561404296.post-32391829388750426172024-03-27T10:38:00.003+01:002024-03-27T10:38:30.321+01:00Role Assignment with Azure Resource SDK<p><img alt="" class="bg tc ue c" height="467" role="presentation" src="https://miro.medium.com/v2/resize:fit:764/1*MMHXHnp0ZQo4HRXYd_JOcw.png" width="700" /> <br /></p><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="62da">I love <a class="af la" href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/overview?tabs=bicep" rel="noopener ugc nofollow" target="_blank">bicep</a>. I really love <a class="af la" href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/overview?tabs=bicep" rel="noopener ugc nofollow" target="_blank">bicep</a>. I love it to deploy resources in the Azure Cloud. It’s simple to read and also simple to manage. <a class="af la" href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/overview?tabs=bicep" rel="noopener ugc nofollow" target="_blank">Bicep </a>takes
the JavaScript-JSON-styled files and transforms it into ARM templates,
which is needed to get things up and running in the Cloud. It works fine
for almost all cases. But sometimes it’s necessary to switch to another
way for deployment.</p><h3 class="vl vm pd be vn vo vp vq vr vs vt vu vv vw vx vy vz wa wb wc wd we wf wg wh wi bj" data-selectable-paragraph="" id="d698" style="text-align: left;"><a class="af la" href="https://learn.microsoft.com/en-us/dotnet/api/overview/azure/resourcemanager.resources-readme?view=azure-dotnet" rel="noopener ugc nofollow" target="_blank">Azure Resource SDK</a></h3><p class="pw-post-body-paragraph uf ug pd uh b ui wj uk ul um wk uo up uq wl us ut uu wm uw ux uy wn va vb vc jm bj" data-selectable-paragraph="" id="1f6c">Actually as a developer, if you want to deploy infrastructure into the Azure Cloud, you can go different ways. There is <a class="af la" href="https://www.pulumi.com/b/?utm_campaign=Competitive-IaC&utm_term=pulumi&utm_medium=cpc&utm_source=google&hsa_grp=164192522628&hsa_cam=20775470768&hsa_mt=e&hsa_net=adwords&hsa_ver=3&hsa_acc=1926559913&hsa_ad=680872926398&hsa_src=g&hsa_tgt=kwd-1177947170384&hsa_kw=pulumi&gad_source=1&gclid=EAIaIQobChMIudG5ypqFhQMVsGdBAh2J1ACZEAAYASAAEgKSKfD_BwE" rel="noopener ugc nofollow" target="_blank">Pulumi</a>. <a class="af la" href="https://www.terraform.io/" rel="noopener ugc nofollow" target="_blank">Terraform</a>, <a class="af la" href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/overview" rel="noopener ugc nofollow" target="_blank">ARM templates</a> or bicep and more IaC solutions. In case of Azure, you can go the <a class="af la" href="https://learn.microsoft.com/en-us/dotnet/api/overview/azure/resourcemanager.resources-readme?view=azure-dotnet" rel="noopener ugc nofollow" target="_blank">SDK </a>way too. This <a class="af la" href="https://learn.microsoft.com/en-us/dotnet/api/overview/azure/resourcemanager.resources-readme?view=azure-dotnet" rel="noopener ugc nofollow" target="_blank">SDK </a>sits on top of the public <a class="af la" href="https://learn.microsoft.com/en-us/rest/api/resources/" rel="noopener ugc nofollow" target="_blank">REST API of Azure Resource Management</a>.
The last version I used is a result of a long hard way, when I look
into the old documentation. In the beginning of the SDK, Microsoft tried
to design all the resources in a Domain specific language, which is
cool to read and use, but the target system is too dynamic, so the SDK
became senseless after a while.</p><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="71df">Now
it is completely redesigned, and actually the behavior is close to the
bicep style, which I love. (Did I mentioned it already? 😄)</p><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="6c36">Okay, the intention of this post is not to describe how the SDK works.</p><h3 class="vl vm pd be vn vo vp vq vr vs vt vu vv vw vx vy vz wa wb wc wd we wf wg wh wi bj" data-selectable-paragraph="" id="23ae" style="text-align: left;">Role Assignment</h3><p class="pw-post-body-paragraph uf ug pd uh b ui wj uk ul um wk uo up uq wl us ut uu wm uw ux uy wn va vb vc jm bj" data-selectable-paragraph="" id="c2fd">Many
times, when you want to deploy an infrastructure, you want to set up
rights for the resource who works together. For example, a Web App wants
to get data from a database, so the Web App needs the right for it. You
might ask, isn't it not solved by using a connection string. Well, in
the good old time it was the way, but for a way better security it’s not
anymore. Now we work with managed identities. Which means, described in
a very simple way: any resource is a kind of user and gets rights to do
things, or not.</p><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="ac88">Microsoft did not the best job in this topic. I mean, when I set up a role for a resource with bicep, it looks like:</p><pre class="wo wp wq wr ws wt wu wv bo ww ba bj"><span class="wx vm pd wu b bf wy wz l xa xb" data-selectable-paragraph="" id="d9b0"><blockquote>param storageAccountName string<br />param principalId string<br />param roleId string<br /><br /><span class="hljs-keyword">var</span> roleAssignmentName = <span class="hljs-title.function">guid</span>(<span class="hljs-title.function">subscription</span>().<span class="hljs-property">subscriptionId</span>, storageAccountName, roleId, principalId)<br /><br />resource storageAccount <span class="hljs-string">'Microsoft.Storage/storageAccounts@2022-09-01'</span> existing = {<br /> <span class="hljs-attr">name</span>: storageAccountName<br />}<br /><br />resource blobRoleAssignment <span class="hljs-string">'Microsoft.Authorization/roleAssignments@2022-04-01'</span> = {<br /> <span class="hljs-attr">name</span>: roleAssignmentName<br /> <span class="hljs-attr">scope</span>: storageAccount<br /> <span class="hljs-attr">properties</span>: {<br /> <span class="hljs-attr">roleDefinitionId</span>: <span class="hljs-title.function">subscriptionResourceId</span>(<span class="hljs-string">'Microsoft.Authorization/roleDefinitions'</span>, roleId)<br /> <span class="hljs-attr">principalId</span>: principalId<br /> <span class="hljs-attr">principalType</span>: <span class="hljs-string">'ServicePrincipal'</span><br /> }<br />}</blockquote></span></pre><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="9ea9">Here I set up a role for a resource, referenced by its <code class="hy aiu aiv aiw wu b">principalId</code>, to allow access to a storage account. The resource <code class="hy aiu aiv aiw wu b">blobRoleAssignment</code> needs a role definition ID, which is somehow organized by the subscription. That’s why I have to transform the <code class="hy aiu aiv aiw wu b">roleId</code> into a <code class="hy aiu aiv aiw wu b">roleDefinitionId</code>. Nobody knows why it is so, because the <code class="hy aiu aiv aiw wu b">roleId</code> is a unique ID all over the Azure Cloud. Why I have to transform it then? 🤷♂️</p><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="3fb7">Now
I want to do the same but different thing by using the Azure SDK. Here I
assign the role “KeyVault Secret Reader” to a KeyVault</p><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="1473">Step 1: Get role definition</p><pre class="wo wp wq wr ws wt wu wv bo ww ba bj"><span class="wx vm pd wu b bf wy wz l xa xb" data-selectable-paragraph="" id="f873"><blockquote><span class="hljs-keyword">using</span> Azure;<br /><span class="hljs-keyword">using</span> Azure.ResourceManager;<br /><span class="hljs-keyword">using</span> Azure.ResourceManager.Authorization;<br /><span class="hljs-keyword">using</span> Azure.ResourceManager.Authorization.Models;<br /><span class="hljs-keyword">using</span> Azure.ResourceManager.KeyVault;<br /><br />...<br /><br />ResourceIdentifier kvSecretReader = <br /> <span class="hljs-keyword">new</span> (<span class="hljs-string">"4633458b-17de-408a-b874-0445c86b69e6"</span>);<br /><br />Response<AuthorizationRoleDefinitionResource> kvSecretReaderDefinition =<br /> <span class="hljs-keyword">await</span> subscription.GetAuthorizationRoleDefinitionAsync(kvSecretReader);<br /><br />...</blockquote></span></pre><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="56ab">A magic GUID transformed into a magic role definition.</p><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="0b80">Step 2: Get the KeyVault where I want to set up the role assignment</p><pre class="wo wp wq wr ws wt wu wv bo ww ba bj"><span class="wx vm pd wu b bf wy wz l xa xb" data-selectable-paragraph="" id="3833"><blockquote>...<br /><br />Response<KeyVaultResource> getKeyVaultResponse = <br /> <span class="hljs-keyword">await</span> resourceGroup.GetKeyVaultAsync(keyVaultName);<br /><br />KeyVaultResource keyVault = getKeyVaultResponse.Value;<br /><br />...</blockquote></span></pre><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="758b">All resources can be grabbed from the resourceGroup component.</p><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="720f">Step 3: Create a role assignment content. It’s the definition what we want to do soon.</p><pre class="wo wp wq wr ws wt wu wv bo ww ba bj"><span class="wx vm pd wu b bf wy wz l xa xb" data-selectable-paragraph="" id="306d"><blockquote>...<br /><br />RoleAssignmentCreateOrUpdateContent roleAssignment = <br /> <span class="hljs-keyword">new</span>(kvSecretReaderDefinition.Value.Id, principalId)<br /> {<br /> PrincipalType = RoleManagementPrincipalType.ServicePrincipal<br /> };<br /><br /><span class="hljs-built_in">string</span> roleAssignmentName = Guid.NewGuid().ToString();<br /><br />...</blockquote></span></pre><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="0d5a">Here we have the definition that we want to assign a role (<code class="hy aiu aiv aiw wu b">kvSecretReaderDefinition</code>) for a resource (<code class="hy aiu aiv aiw wu b">principalId</code>) with a special name (<code class="hy aiu aiv aiw wu b">roleAssignmentName</code>) — yes a GUID is not a nice name, but it’s better to do so. 😉</p><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="34be">Step 4: The final step. Bring it all together.</p><pre class="wo wp wq wr ws wt wu wv bo ww ba bj"><span class="wx vm pd wu b bf wy wz l xa xb" data-selectable-paragraph="" id="e136"><blockquote>...<br /><br />ArmOperation<RoleAssignmentResource>? createRoleAssignmentOperation = <br /> <span class="hljs-keyword">await</span> keyVault<br /> .GetRoleAssignments()<br /> .CreateOrUpdateAsync(WaitUntil.Completed,roleAssignmentName,roleAssignment);<br /><br />...</blockquote></span></pre><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="7590"><b>Disclaimer:</b>
All my lines of code have more infrastructure than just this few lines.
In the original I have try-catches, checks and exception handling, of
course. 😄</p><h3 class="vl vm pd be vn vo vp vq vr vs vt vu vv vw vx vy vz wa wb wc wd we wf wg wh wi bj" data-selectable-paragraph="" id="f39b" style="text-align: left;">What I’ve realized</h3><p class="pw-post-body-paragraph uf ug pd uh b ui wj uk ul um wk uo up uq wl us ut uu wm uw ux uy wn va vb vc jm bj" data-selectable-paragraph="" id="d30d">Firstly,
bicep is less code than using the SDK. But the SDK have its right to
exist. I used it to create resources on demand in an Application which
had no access to a build pipeline system. Actually I’ve planned to
prepare a build pipeline to trigger a custom build for my use case, but
then I found out, I can’t do it. So the SDK was my solution.</p><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="7991">Secondly,
the SDK way is quite similar to bicep. Get a resource, grab its sub
resources, add or update the resource… done. I like the strong typed way
very much but also the dynamic parts of it.</p><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="34be"> </p><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="720f"> </p><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="0b80"> </p><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="1473"> </p><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="ac88"> </p><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="ac88"> </p><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="ac88"> </p><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="ac88"> </p><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="ac88"> </p>Janek Fellienhttp://www.blogger.com/profile/11037083301535227855noreply@blogger.comtag:blogger.com,1999:blog-6438666738561404296.post-78096945242272386712024-03-27T10:33:00.006+01:002024-03-27T10:34:02.390+01:00Invalid SKU Code “Free” — A Solution<p><img alt="A mostly green picture of a monitor with a big exclamation mark." class="bg tc ue c" height="467" src="https://miro.medium.com/v2/resize:fit:764/1*anvG4BlCZAkKBtBtWmCrLQ.png" width="700" /> <br /></p><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="0c77">Sometimes
it will happen that people will publish static WebApps to an Azure
Static WebApp Resource. Also the people think about to do this</p><ol><li class="uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc vd ve vf bj" data-selectable-paragraph="" id="998f">On a free SKU plan, because they don’t expect much traffic or its just for a dev test which needs not many features.</li><li class="uf ug pd uh b ui vg uk ul um vh uo up uq vi us ut uu vj uw ux uy vk va vb vc vd ve vf bj" data-selectable-paragraph="" id="c90a">By deploying it with <a class="af la" href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/" rel="noopener ugc nofollow" target="_blank">bicep</a>, just because its very simple and state of the art for software development.</li><li class="uf ug pd uh b ui vg uk ul um vh uo up uq vi us ut uu vj uw ux uy vk va vb vc vd ve vf bj" data-selectable-paragraph="" id="5fb9">By using an <a class="af la" href="https://azure.microsoft.com/en-us/products/key-vault" rel="noopener ugc nofollow" target="_blank">Azure Key Vault</a> for security reasons when an API needs secret values.</li></ol><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="a840">That’s a simple setup which should work very well.</p><h3 class="vl vm pd be vn vo vp vq vr vs vt vu vv vw vx vy vz wa wb wc wd we wf wg wh wi bj" data-selectable-paragraph="" id="8655" style="text-align: left;">But it’s not working?</h3><p class="pw-post-body-paragraph uf ug pd uh b ui wj uk ul um wk uo up uq wl us ut uu wm uw ux uy wn va vb vc jm bj" data-selectable-paragraph="" id="5ca1">When you setup a bicep script for your static web app it looks like:</p><pre class="wo wp wq wr ws wt wu wv bo ww ba bj"><span class="wx vm pd wu b bf wy wz l xa xb" data-selectable-paragraph="" id="d592"><blockquote>...<br /><br />resource staticWebApp <span class="hljs-string">'Microsoft.Web/staticSites@2022-03-01'</span> = {<br /> <span class="hljs-attr">name</span>: name<br /> <span class="hljs-attr">location</span>: location<br /> <span class="hljs-attr">sku</span>: {<br /> <span class="hljs-attr">name</span>: <span class="hljs-string">"Free"</span><br /> <span class="hljs-attr">tier</span>: <span class="hljs-string">"Free"</span><br /> }<br /> <span class="hljs-attr">identity</span>: {<br /> <span class="hljs-attr">type</span>: <span class="hljs-string">"SystemAssigned"</span><br /> }<br /> <span class="hljs-attr">properties</span>: {<br /> <span class="hljs-attr">stagingEnvironmentPolicy</span>: <span class="hljs-string">"Enabled"</span><br /> <span class="hljs-attr">allowConfigFileUpdates</span>: <span class="hljs-literal">true</span><br /> <span class="hljs-attr">provider</span>: <span class="hljs-string">"Custom"</span><br /> <span class="hljs-attr">enterpriseGradeCdnStatus</span>: <span class="hljs-string">"Disabled"</span><br /> }<br /> <span class="hljs-attr">tags</span>: tags<br />}<br /><br />...</blockquote></span></pre><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="eddc">or quite similar.</p><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="b929">In my case, it did not work. I’ve got an exception while deploying:</p><pre class="wo wp wq wr ws wt wu wv bo ww ba bj"><span class="wx vm pd wu b bf wy wz l xa xb" data-selectable-paragraph="" id="c721"><blockquote>...<br /><br /><span class="hljs-punctuation">{</span><br /> <span class="hljs-attr">"ErrorEntity"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span><br /> <span class="hljs-attr">"ExtendedCode"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"55925"</span><span class="hljs-punctuation">,</span><br /> <span class="hljs-attr">"MessageTemplate"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"SkuCode '{0}' is invalid."</span><span class="hljs-punctuation">,</span><br /> <span class="hljs-attr">"Parameters"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span><br /> <span class="hljs-string">"Free"</span><br /> <span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span><br /> <span class="hljs-attr">"Code"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"BadRequest"</span><span class="hljs-punctuation">,</span><br /> <span class="hljs-attr">"Message"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"SkuCode 'Free' is invalid."</span><br /> <span class="hljs-punctuation">}</span><br /><span class="hljs-punctuation">}</span><br /><br />...</blockquote></span></pre><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="bdad">Thats
really annoying. I’m absolutely sure the SKU Code ‘Free’ exists. I can
set up this value in the Azure Portal and by generating the <a class="af la" href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/overview" rel="noopener ugc nofollow" target="_blank">ARM template,</a> I get exactly this code. So what is the problem?</p><h3 class="vl vm pd be vn vo vp vq vr vs vt vu vv vw vx vy vz wa wb wc wd we wf wg wh wi bj" data-selectable-paragraph="" id="bd35" style="text-align: left;">The Solution</h3><p class="pw-post-body-paragraph uf ug pd uh b ui wj uk ul um wk uo up uq wl us ut uu wm uw ux uy wn va vb vc jm bj" data-selectable-paragraph="" id="4253">After
investigating a while, I found out that a ‘Free’ Azure Static WebApp
Resource can’t set up an ‘SystemAssigned’ identity. If you want to set
up a Managed Identity to use it for a Key Vault you need to select a SKU
‘Standard’ (BTW, it’s the same for “Bring your own Function”-feature).</p><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="b6a1">My
problem is the error message. If the SKU wrong because of Identity,
“Bring your own Function” or something else, so make it clear.</p><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="bf08">Now you know why you’ve got that error and my post was helpful for you.</p><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="b929"> </p><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="b929"> </p><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="b929"> </p><p class="pw-post-body-paragraph uf ug pd uh b ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc jm bj" data-selectable-paragraph="" id="b929"> </p><p class="pw-post-body-paragraph uf ug pd uh b ui wj uk ul um wk uo up uq wl us ut uu wm uw ux uy wn va vb vc jm bj" data-selectable-paragraph="" id="5ca1"> </p><p class="pw-post-body-paragraph uf ug pd uh b ui wj uk ul um wk uo up uq wl us ut uu wm uw ux uy wn va vb vc jm bj" data-selectable-paragraph="" id="5ca1"> </p><p class="pw-post-body-paragraph uf ug pd uh b ui wj uk ul um wk uo up uq wl us ut uu wm uw ux uy wn va vb vc jm bj" data-selectable-paragraph="" id="5ca1"> </p><p class="pw-post-body-paragraph uf ug pd uh b ui wj uk ul um wk uo up uq wl us ut uu wm uw ux uy wn va vb vc jm bj" data-selectable-paragraph="" id="5ca1"> </p>Janek Fellienhttp://www.blogger.com/profile/11037083301535227855noreply@blogger.comtag:blogger.com,1999:blog-6438666738561404296.post-91143383001900333132024-03-26T18:11:00.007+01:002024-03-26T18:11:50.565+01:00How to resolve the Azure LinuxDynamicWorkersNotAllowedInResourceGroup Error<p> A
few weeks ago, I started to fix some issues on an existing Azure
pipeline for deploying cloud resources. It’s an enterprise system which
was running since a year without problems. After some changes I decided
to redeploy the infrastructure. What can happen? Nothing has bee changed
except of a naming. But then I ran in an error</p><p></p><blockquote>”code”:
“LinuxDynamicWorkersNotAllowedInResourceGroup”, “message”: “Linux
dynamic workers are not available in resource group [name of our
resource group].”</blockquote><p></p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="5864">Why
is this happen? We did not change much in the infrastructure. The
deployment script was running very well. But now one year later, this
error appears suddenly.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="6c1e">After googeling I found <a class="az hk" href="https://github.com/Azure/Azure-Functions/issues/1952" rel="noopener ugc nofollow" target="_blank">this gitHub issue</a>. Which actually just redirects to a long <a class="az hk" href="https://github.com/Azure/app-service-announcements/issues" rel="noopener ugc nofollow" target="_blank">list of announcements</a> of the Azure App Service. Okay, but this is not a solution. I need one.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="c03f">A
short discussion with my colleagues and the dev community, I learned
that error is more or less a glitch and can be fixed by some
workarounds. But I don’t like workarounds, I need a fix for my deployment
script.</p><h3 class="anj abs vm am ank aho anl ahp mz ahr anm ahs ne ajo ann ajp ajq ajr ano ajs ajt aju anp ajv ajw anq bq" data-selectable-paragraph="" id="4a77" style="text-align: left;">What does it mean, this error?</h3><p class="pw-post-body-paragraph zm zn vm nv b zo anr zq zr zs ans zu zv nf ant zx zy nk anu aba abb np anv abd abe abf ki bq" data-selectable-paragraph="" id="646e">At
the moment, it’s not possible to deploy a Y1 Dynamic App Service Plan
type Linux in a resource group, where already an App Service Plan was
deployed. I did not test any configuration, maybe with a Windows Plan
anything works well. But in my case, I tried to create an <strong class="nv gl">App Service Plan S1 Standard Linux</strong> and an <strong class="nv gl">Azure Function App, hosted in a consumption (Y1 Dynamic) Linux plan</strong>, into one resource group.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="2dee">The deployment is developed as an Infrastructure as Code (IaC) solution in <a class="az hk" href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/overview?tabs=bicep" rel="noopener ugc nofollow" target="_blank">Bicep</a>.
Here I set up the resources I need in a very simple way. I describe and
list the resources and at execution the resources will be created in a
specific order. In my case, I found out the order of App Service Plan
creation is important. Usually it is not.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="cc5c">So
my solution now is to set the App Service Plans in dependency. First
the Y1 Dynamic Plan needs to be created and then the S1 Plan. In Bicep,
it is very simple.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="493d">The keyword in Bicep is <code class="cn abg abh abi abj b">dependsOn</code>.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="493d"><img alt="module s1AppService… dependsOn: [function App]" class="bn vj vk c" src="https://miro.medium.com/v2/resize:fit:764/1*MdDi5OjrEjuHtJX0CHDaZg.png" title="Bicep module dependsOn functionApp" /> <br /></p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="493d"> A
Bicep module provides a parameter, a list of resources on what this
module depends. First the depended resource needs to be created, then
the module will be created.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="874c">After this small change in my deployment script the Linux… Error disappeared.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="b79f">I hope it helps you too.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="493d"> </p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="493d"> </p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="493d"> </p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="493d"> </p>Janek Fellienhttp://www.blogger.com/profile/11037083301535227855noreply@blogger.comtag:blogger.com,1999:blog-6438666738561404296.post-47082097250082165892024-03-26T18:08:00.001+01:002024-03-26T18:08:02.172+01:00Raspberry Pi as LED-Strip Controller<p><img alt="" class="bn vj vk c" height="262" role="presentation" src="https://miro.medium.com/v2/resize:fit:764/1*J8djMbCIiiq8o-kPz1Tprw.png" width="700" /> <br /></p><p>Last year the company I’m working for, was requested to create a
sample for an IIoT (Industrial Internet of Things) use case. We’ve built
a LEGO® model with a few houses. The light was controlled by an
application which took weather data to simulate wind and solar power.
The light controller was, just as prototype, a Raspberry Pi connected
with a WS2812b LED-Strip.</p><p><img alt="A light strip in rainbow colors." class="bn vj vk c" src="https://miro.medium.com/v2/resize:fit:764/0*f9DTsz0C4KvSmksO.jpg" title="WS2812b addressable LED-Strip" /></p><p>These LEDs are controllable by software, so we were able to set up the
light in any LEGO® building different. Why should we do this? Simple
answer: not any household uses the same light, so why should we do this
in a model of a small town? 😄</p><p><img class="bn vj vk c" role="presentation" src="https://miro.medium.com/v2/resize:fit:764/1*eZ0tYJo-SkhWmeb690-v4w.png" title="LEGO® model with white light" /> <br /></p><p>This project got me thinking about to use LED lights instead of
fireworks for the New Year’s Eve party 2023. This post will describe
what I did and what my main issues were. <br /></p><h3 class="anj abs vm am ank aho ape ahp mz ahr apf ahs ne ajo apg ajp ajq ajr aph ajs ajt aju api ajv ajw anq bq" data-selectable-paragraph="" id="e969" style="text-align: left;">Prerequisites</h3><p class="pw-post-body-paragraph zm zn vm nv b zo anr zq zr zs ans zu zv nf ant zx zy nk anu aba abb np anv abd abe abf ki bq" data-selectable-paragraph="" id="37da">Firstly, we need the hardware</p><ul class=""><li class="zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf apj aby abz bq" data-selectable-paragraph="" id="6329">A Raspberry Pi (I use a Pi 2 Model B v1.1)</li><li class="zm zn vm nv b zo aca zq zr zs acb zu zv nf acc zx zy nk acd aba abb np ace abd abe abf apj aby abz bq" data-selectable-paragraph="" id="0c0c">For a better handling, a GPIO Hat</li><li class="zm zn vm nv b zo aca zq zr zs acb zu zv nf acc zx zy nk acd aba abb np ace abd abe abf apj aby abz bq" data-selectable-paragraph="" id="b79f">A W2812b Led-Strip</li><li class="zm zn vm nv b zo aca zq zr zs acb zu zv nf acc zx zy nk acd aba abb np ace abd abe abf apj aby abz bq" data-selectable-paragraph="" id="4e4c">And a power supply 5V, 2500mA output</li></ul><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="f31e">(The Pi 2 needs a Wifi module if you like to control it wireless. 😉)</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="8e8e">Secondly, the software</p><ul class=""><li class="zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf apj aby abz bq" data-selectable-paragraph="" id="a754">The OS for the RPi is Linux 10 (Buster)</li><li class="zm zn vm nv b zo aca zq zr zs acb zu zv nf acc zx zy nk acd aba abb np ace abd abe abf apj aby abz bq" data-selectable-paragraph="" id="d2b9">Application is developed in C# (.NET 6.0.402)</li></ul><h3 class="anj abs vm am ank aho anl ahp mz ahr anm ahs ne ajo ann ajp ajq ajr ano ajs ajt aju anp ajv ajw anq bq" data-selectable-paragraph="" id="5628" style="text-align: left;">Wiring</h3><p class="pw-post-body-paragraph zm zn vm nv b zo anr zq zr zs ans zu zv nf ant zx zy nk anu aba abb np anv abd abe abf ki bq" data-selectable-paragraph="" id="61f0">In
the past, I’ve learned in a RPi project to describe the wiring. The
most interesting part in this project here, actually all documented wiring were wrong. For example, this documentation <a class="az hk" href="https://www.thegeekpub.com/15990/wiring-ws2812b-addressable-leds-to-the-raspbery-pi/" rel="noopener ugc nofollow" target="_blank">here</a>
uses pin 18. The same pin is used in many other documentations, but in
my case, pin 18 is wrong. If I use it, nothing will happen.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="61e1">Why is it so?</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="b395">I think the reason is the program language. All the samples are developed in Python and uses the lib <code class="cn abg abh abi abj b">neopixel</code>, which is different in C#.</p><p><img alt="A code snipped in Python which imports the neopixel library and uses it on pin 18" class="bn vj vk c" src="https://miro.medium.com/v2/resize:fit:764/1*OJwk3FND_9k2foNzYLam9Q.png" title="Use neopixel in Python on pin 18" /> <br /></p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="2164">In C# I use a <code class="cn abg abh abi abj b">SpiDevice</code>. So I have to look for a different pin, related to the SPI pins. Luckily, I found a very helpful description of any pin <a class="az hk" href="https://pinout.xyz/" rel="noopener ugc nofollow" target="_blank">here</a>
and after reading a lot about SPI, I found out I need to take the pin
21, which is the GPIO 9, which is the SPI0 (zero), which is the MISO
(master in slave out) pin. 😱</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="30c6">So many different names. It was absolute horrible for someone who wants just turn on some light.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="506c">Finally, the wiring result is:</p><ul class=""><li class="zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf apj aby abz bq" data-selectable-paragraph="" id="4765">Pin 4: 5V</li><li class="zm zn vm nv b zo aca zq zr zs acb zu zv nf acc zx zy nk acd aba abb np ace abd abe abf apj aby abz bq" data-selectable-paragraph="" id="d193">Pin 6: Ground</li><li class="zm zn vm nv b zo aca zq zr zs acb zu zv nf acc zx zy nk acd aba abb np ace abd abe abf apj aby abz bq" data-selectable-paragraph="" id="25f3">Pin 21: Signal (called Din on the strip)</li></ul><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="6834">Because I used the GPIO Hat, it was way simpler to connect the wire.</p><h3 class="anj abs vm am ank aho anl ahp mz ahr anm ahs ne ajo ann ajp ajq ajr ano ajs ajt aju anp ajv ajw anq bq" data-selectable-paragraph="" id="e124" style="text-align: left;">Software</h3><p class="pw-post-body-paragraph zm zn vm nv b zo anr zq zr zs ans zu zv nf ant zx zy nk anu aba abb np anv abd abe abf ki bq" data-selectable-paragraph="" id="bc53">After
putting all the thing together I started to develop the application. My
first version was a command line application, starting a sequence of
effects. But now it is a web application to control the light via
WebAPI.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="3fa9">I
don't want to describe how to set up a WebAPI project in .NET. Also, I
don’t want to describe how to develop an API Controller. The interesting
part is the LED Service aka LED Strip.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="c3a4">To control the light, you need four namespaces:</p><p><img alt="using Iot.Device.Graphics; using Iot.Device.Ws28xx; using System.Device.Spi; using System.Drawing;" class="bn vj vk c" src="https://miro.medium.com/v2/resize:fit:764/1*A29UE2TwQhoM3jrLoqo8DQ.png" title="The namespaces" /> <br /></p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="e64c">You get it by referencing the NuGet packages <em class="aoc">Iot.Device.Bindings</em> and <em class="aoc">System.Device.Gpio</em>.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="ff1e">To set up a SPI device, you need to know which <code class="cn abg abh abi abj b">busId</code> is connected and which <code class="cn abg abh abi abj b">chipSelectLine</code>
is in use. 🤔Yes I had the same questions, what is a busId and
chipSelectLine. To be honest I don’t know, but luckily I used Linux for a
while and after a few error messages from the <code class="cn abg abh abi abj b">SpiDevice</code>
I remembered me where to find out the SPI device settings. Actually not
exactly the SPI device settings but the connected devices. You can
enter <code class="cn abg abh abi abj b">ls /dev/</code> in your Raspberry Pi terminal, and you will get the whole list of connected devices.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="ff1e"><img class="bn vj vk c" role="presentation" src="https://miro.medium.com/v2/resize:fit:764/1*nb7ElBK7ie6Uqjd-biGHAg.png" title="List of connected devices" /> <br /></p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="116a">In
the screenshot, you can see all my connected devices, also the
spidev0.0 and spidev0.1. After testing a lot, I found out that the
numbers are the busId (0) and the chipSelectionLine (1) for the MISO
pin. Crazy, isn’t it?</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="262e">All that experiments led me to get the right setting for the <code class="cn abg abh abi abj b">SpiDevice</code>.</p><pre class="abk abl abm abn abo abp abj apn rr apo bi bq"><span class="rb abs vm abj b bm app apq s apr abv" data-selectable-paragraph="" id="0bc6"><blockquote>SpiConnectionSettings spiSettings = <span class="hljs-keyword">new</span> (<span class="hljs-number">0</span>, <span class="hljs-number">1</span>)<br />{<br /> ClockFrequency = <span class="hljs-number">2</span>_400_000,<br /> Mode = SpiMode.Mode0,<br /> DataBitLength = <span class="hljs-number">8</span><br />};</blockquote></span></pre><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="4be1">The setting <em class="aoc">ClockFrequency</em>, <em class="aoc">Mode </em>and <em class="aoc">DataBitLength </em>values are just a copy by a sample developed in Python, but it works. 😉</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="7273">To initialize a Ws2812b LED strip, we need the <em class="aoc">SpiConnectionSettings </em>and
the length of the strip, which means the number of LEDs the strip have.
In my case, I have 60 LEDs to control, one meter. If you want to
control more than one meter, count the LEDs.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="7273"></p><blockquote>BTW, the power (5V) of the RPi is good enough for one or two meter, but
if you need longer strips you need more power. The Ws2812b strip
provides for any part a red and white cable. Here you can connect a
power supply to support the LEDs.</blockquote> The constructor of my <em class="aoc">LedStrip </em>class expects the <em class="aoc">SpiConnectionSetting </em>and the number of LEDs. Here the <code class="cn abg abh abi abj b">SpiDevice</code> will be created and assigned to an internal variable <code class="cn abg abh abi abj b">_ledStrip</code> which is type of <em class="aoc">Ws2812b</em>.<p></p><pre class="abk abl abm abn abo abp abj apn rr apo bi bq"><span class="rb abs vm abj b bm app apq s apr abv" data-selectable-paragraph="" id="1946"><span class="hljs-keyword"></span><blockquote><span class="hljs-keyword">using</span> Iot.Device.Graphics;<br /><span class="hljs-keyword">using</span> Iot.Device.Ws28xx;<br /><span class="hljs-keyword">using</span> System.Device.Spi;<br /><span class="hljs-keyword">using</span> System.Drawing;<br /><br /><span class="hljs-keyword">namespace</span> <span class="hljs-title">LedStripControllerApi.Services</span>;<br /><br /><span class="hljs-keyword">internal</span> <span class="hljs-keyword">class</span> <span class="hljs-title">LedStrip</span> : <span class="hljs-title">ILedStrip</span><br />{<br /> <span class="hljs-keyword">private</span> <span class="hljs-built_in">int</span> _numberOfLeds;<br /> <span class="hljs-keyword">private</span> Ws2812b _ledStrip;<br /><br /> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">LedStrip</span>(<span class="hljs-params">SpiConnectionSettings spiSettings, <span class="hljs-built_in">int</span> numberOfLeds</span>)</span><br /> {<br /> SpiDevice spiDevice = SpiDevice.Create(spiSettings);<br /><br /> _numberOfLeds = numberOfLeds;<br /><br /> _ledStrip = <span class="hljs-keyword">new</span> (spiDevice, numberOfLeds);<br /> }<br /><br />...<br />}</blockquote></span></pre><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="262e">So, the biggest part of magic is happened. The LED strip is connected
and the SPI device is initialized. Now we can take a short look into one
effect, just turn on the light.</p><pre class="abk abl abm abn abo abp abj apn rr apo bi bq"><span class="rb abs vm abj b bm app apq s apr abv" data-selectable-paragraph="" id="0e25"><span class="hljs-function"><span class="hljs-keyword"></span></span><blockquote><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">TurnOn</span>(<span class="hljs-params">Color color</span>)</span><br />{<br /> <span class="hljs-comment">// turn off all led</span><br /> Clear();<br /><br /> <span class="hljs-comment">// get the image of strip</span><br /> BitmapImage image = _ledStrip.Image;<br /><br /> <span class="hljs-comment">// iterate through led and set the color of the pixel</span><br /> <span class="hljs-keyword">for</span>(<span class="hljs-built_in">int</span> i = <span class="hljs-number">0</span>; i <= _numberOfLeds; i++){<br /> image.SetPixel(i, <span class="hljs-number">0</span>, color);<br /> }<br /><br /> <span class="hljs-comment">// update the data</span><br /> _ledStrip.Update();<br />}</blockquote></span></pre><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="06bb">In
the snipped, you can see that a LED strip will be controlled by an
image and its pixel. Any pixel represents a LED. Because we have just a
single line strip, the <em class="aoc">SetPixel </em>method uses 0 as y-coordinate.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="da4c">To
control the image, you have to put the image in a variable before
changing. I tried it to change it directly but without any result, so
don’t wonder, just do it the same way. 😄</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="ebab">Finally,
after set all pixel, aka LED, of the strip, you need to update the
Ws2812b instance. You don’t need to reassign the image, it is still
referenced.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="ebab"><span></span> <br /></p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="262e">Good news: <a class="az hk" href="https://github.com/jfellien/raspi-led-controller" rel="noopener ugc nofollow" target="_blank">Here</a> you will find the whole <a class="az hk" href="https://github.com/jfellien/raspi-led-controller" rel="noopener ugc nofollow" target="_blank">project</a>. Clone it, fork it, use it. <br /></p><p> </p><p> </p><p> </p><p> </p><p> </p><p> </p><p> </p><p> </p><p> </p>Janek Fellienhttp://www.blogger.com/profile/11037083301535227855noreply@blogger.comtag:blogger.com,1999:blog-6438666738561404296.post-4240490018010665192024-03-26T17:54:00.004+01:002024-03-26T17:54:43.431+01:00Application Versioning in Azure pipelines<p><img alt="" class="bn vj vk c" height="262" role="presentation" src="https://miro.medium.com/v2/resize:fit:764/1*K7Nu_eyqtqrzLatxUtBksw.png" width="700" /> <br /></p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="7bcc">Isn't
it bad when users can get the current version number of a running
application? It can’t, but in many cases, developers forget it to
implement or just don't do it because they can.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="79d9">Recently
I finalized a project with a few console and UWP applications. But
after a while, I noticed that I can't see the application versions of
any application. That’s why I started to write down this post.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="744e">In
the “good old times” developers did not have thought about deployment
pipelines. They’ve set the version number in a file, that's it. It was
the time as the code was locked for a developer, so nobody was able to
change the number at the same time. Now it’s different. This time we
have distributed teams, which developing at the same time on similar or
even the same files. It makes the versioning way harder, but simpler
too. We have to build pipelines. A pipeline is literary the last instance
who can change automatically the code. An outcome of a pipeline is a
package which should never have changed anymore. So why not set the
version number exactly here?</p><h3 class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="744e" style="text-align: left;"><strong class="bd">Versioning in a .Net Console Apps</strong></h3><p class="pw-post-body-paragraph zm zn vm nv b zo anr zq zr zs ans zu zv nf ant zx zy nk anu aba abb np anv abd abe abf ki bq" data-selectable-paragraph="" id="d638">When I start a console app, usually it prints out the current version number at start time. This is what I want to reach too.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="26a7">Because I have already created a pipeline YAML-File, I add one step before the <em class="aoc">VSBuild@1</em> task. You should have this task too. 😉 Add the new task before the build step.</p><pre class="abk abl abm abn abo abp abj ra abq bf kx bq"><span class="abr abs vm abj b fi abt abu s wu abv" data-selectable-paragraph="" id="7ed0"><blockquote>- task: PowerShell@2<br /> displayName: 'Set App Version'<br /> inputs:<br /> targetType: inline<br /> script: |<br /> [Reflection.Assembly]::LoadWithPartialName("System.Xml.Linq")<br /> $path = "$(pathToProjectFile)"<br /> $doc = [System.Xml.Linq.XDocument]::Load($path)<br /> $doc<br /> .Element("Project")<br /> .Element("PropertyGroup")<br /> .Element("Version")<br /> .SetValue("$(major).$(minor).$(patch).$(build)");<br /> $doc.Save($path)</blockquote></span></pre><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="61dd">This
step adds a short script which is looking and opens the project file as
XDocument. Because the structure of a .csproj file ist always the same, I
browse up to the element <em class="aoc">Version</em>. Typically a
project file does not contain this element by default. So feel free to
put it in the file by your self. Please put it in the <em class="aoc">PropertyGroup</em> section. For me, I entered a dummy version number as content in the <em class="aoc">Version </em>element, like 1.0.0.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="b055">The PowerShell script expects a few variables, which I’ve added at the top of my pipeline file.</p><pre class="abk abl abm abn abo abp abj ra abq bf kx bq"><span class="abr abs vm abj b fi abt abu s wu abv" data-selectable-paragraph="" id="1272"><blockquote>variables:<br /> pathToTheProjectFile: {add here your path}<br /> major: 1<br /> minor: 0<br /> patch: $[counter(variables['major'], 0)]<br /> build: $(Build.BuildId)</blockquote></span></pre><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="8b50">The values of <code class="cn abg abh abi abj b">major</code> and <code class="cn abg abh abi abj b">minor</code> are obvious, but <code class="cn abg abh abi abj b">patch</code> and <code class="cn abg abh abi abj b">build</code> are different. The <code class="cn abg abh abi abj b"><a class="az hk" href="https://learn.microsoft.com/en-us/azure/devops/pipelines/process/expressions?view=azure-devops#counter" rel="noopener ugc nofollow" target="_blank">counter</a></code> function is part of the pipeline engine and increases the given value for every build by one. It starts with the <code class="cn abg abh abi abj b">major</code> value with no additional seed (its zero). My second dynamic value is set up by a pipeline parameter, the buildId.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="888b">All
of that creates a new value for every build, which ist great to print
out the version number at application start. You will find the number in
the <code class="cn abg abh abi abj b">Assembly.GetExecutingAssembly().GetName().Version</code> property.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="8777">Oh
btw, this version number will be only shown in environments which uses
the build package. It’s because I don’t save the new value in the code
repository. If you like to do so, feel free to push the new value from
your pipeline into a special branch or something else. 😁</p><h3 class="abr abs vm am ank mv aow mw mz na aox nb ne nf aoy ng nj nk aoz nl no np apa nq nt apb bq" data-selectable-paragraph="" id="263c" style="text-align: left;"><strong class="bd">Versioning in an UWP App</strong></h3><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="8777">Actually, it's the same solution as it is for a console app. But a small
thing is different. The version number is not set up in the project
file. It's in the manifest file </p><pre class="abk abl abm abn abo abp abj ra abq bf kx bq"><span class="abr abs vm abj b fi abt abu s wu abv" data-selectable-paragraph="" id="58c5"><blockquote>- task: PowerShell@2<br /> displayName: 'version package manifest'<br /> inputs:<br /> targetType: inline<br /> script: |<br /> [Reflection.Assembly]::LoadWithPartialName("System.Xml.Linq")<br /> $path = "$(PathToYourProject)/Package.appxmanifest"<br /> $doc = [System.Xml.Linq.XDocument]::Load($path)<br /> $xName = [System.Xml.Linq.XName]"{http://schemas.microsoft.com/appx/manifest/foundation/windows10}Identity"<br /> $doc.Root.Element($xName).Attribute("Version").Value = "$(major).$(minor).$(patch).$(build)";<br /> $doc.Save($path)</blockquote></span></pre><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="6841">Here
I load the Package.appmanifest file as XML too. To find the version
part of the filem I need a special route. Actually also it’s possible to
select the version part by browsing through the elements. If you like
to go this way, you need from the <em class="aoc">Identity </em>element the <em class="aoc">Version </em>attribute. Finally I take the variables to set the value.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="312c">If you like to show the version number somwhere in your application, use the <code class="cn abg abh abi abj b">Package.Current.Id.Version</code> property to read the value.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="fda3">Done 👍</p><div class="ki sn sz hm vg"><div class="n p"><div class="cz bn da db dc dd"><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="f22a">Hopefully
I was able to describe it in a simple way. Feel free to play with the
numbers but be carefull, you have to note the rules of <a class="az hk" href="https://semver.org/" rel="noopener ugc nofollow" target="_blank">semantic versioning</a></p></div></div></div><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="26a7"><br /></p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="26a7"><br /></p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="26a7"><br /></p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="26a7"><br /></p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="26a7"><br /></p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="26a7"><br /></p><h3 class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="744e" style="text-align: left;"><strong class="bd"> </strong></h3>Janek Fellienhttp://www.blogger.com/profile/11037083301535227855noreply@blogger.comtag:blogger.com,1999:blog-6438666738561404296.post-54856480831218270282024-03-26T17:20:00.002+01:002024-03-26T17:20:09.983+01:00InvalidDataException in a UWP scenario with SignalR<p><img alt="" class="bn vj vk c" height="263" role="presentation" src="https://miro.medium.com/v2/resize:fit:764/1*oxJsIyQXI4AJfEqJEnllXg.png" width="700" /> <br /></p><p></p><p></p><p></p><p></p><p></p><p></p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="d154">Recently
I’ve created my first UWP App — yes it’s 2022, and I should go a very
different way, but unfortunately I needed a feature which only exists in
UWP still (later I will describe more 😊). One task of that UWP App is
to send small messages to subscribers. My decision to solve this feature
is to use an<a class="az hk" href="https://azure.microsoft.com/en-us/services/signalr-service/" rel="noopener ugc nofollow" target="_blank"> Azure SignalR Service</a>.
It's great for real time communication between distributed clients
around the world. Also, I’ve heard from colleagues in the tech community
it’s simple and clear to implement it in any application.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="f903">So far so good, as we Germans say. 😂</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="6b96">My
first step for realization was to read the documentations, which was
quite nice described. I found samples how to implement a
client-to-client communication with UWP. One client is the UWP app, the
second is a console app running on a Raspberry Pi. That was not the
problem. For establishing the connection … let me show you a picture, it
makes it a bit better for understanding.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="6b96"><img alt="" class="bn vj vk c" height="152" role="presentation" src="https://miro.medium.com/v2/resize:fit:526/1*2NhyQ7Qo766bMfAzRVACRA.png" width="510" /></p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="6b96">In the picture, you can see the current solution. The UWP App uses the
SignalR Service directly. It’s because the App runs in a secure
environment, so I can use the connection settings directly in the <code class="cn abg abh abi abj b">ServiceManagerBuilder</code> component (from namespace Microsoft.Azure.SignalR.Management).</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="6b96"><img class="bn vj vk c" role="presentation" src="https://miro.medium.com/v2/resize:fit:764/1*msXYu26AvZ2HtIIZaGQhqg.png" title="Build a service manager in the UWP app" /> <br /></p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="6b96">A few lines later, I create a hub with the ServiceManager.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="6b96"><img class="bn vj vk c" role="presentation" src="https://miro.medium.com/v2/resize:fit:764/1*V1SzRweUXa6xjTxhHYA8fA.png" title="Create a hub for sending messages" /> <br /></p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="6b96">The created hub allows me to send messages directly to the SignalR Service. That’s what I want, only sending, not receiving. <br /></p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="6b96"><img class="bn vj vk c" role="presentation" src="https://miro.medium.com/v2/resize:fit:764/1*TRTZ3wlfgRlYByjv-qgGWA.png" title="Send a message" /> <br /></p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="6b96">That was really simple, like the documentation and my colleagues mentioned. <br /></p><h3 class="anj abs vm am ank aho anl ahp mz ahr anm ahs ne ajo ann ajp ajq ajr ano ajs ajt aju anp ajv ajw anq bq" data-selectable-paragraph="" id="9a8d" style="text-align: left;">Message Receiver</h3><p class="pw-post-body-paragraph zm zn vm nv b zo anr zq zr zs ans zu zv nf ant zx zy nk anu aba abb np anv abd abe abf ki bq" data-selectable-paragraph="" id="5a4c">To
receive the messages, the console app first has to negotiate to the
SignalR service. Why? Why not go the same direct connection way? The
simple answer is: The hub component does not contain a receiver method.
That's it. 🤷♀️</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="4ad7">To solve this “issue” in the console app I use the <code class="cn abg abh abi abj b">HubConnection</code>
component from Microsoft.AspNetCore.SignalR.Client namespace. These
connections can receive messages, but before, I have to set up this
connection.</p><h1 class="anj abs vm am ank aho anl ahp mz ahr anm ahs ne ajo ann ajp ajq ajr ano ajs ajt aju anp ajv ajw anq bq" data-selectable-paragraph="" id="9a8d"><img class="bn vj vk c" role="presentation" src="https://miro.medium.com/v2/resize:fit:764/1*Lu-McbQ3foHrIG5ksGVzYA.png" title="Setup HubConnection" /> <br /></h1><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="6b96">The <code class="cn abg abh abi abj b">notificatrionUrl</code>is the URL of the negotiation server (called “SignalR Negotiation” in the picture). <br /></p><h3 class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="6b96" style="text-align: left;">Negotiation Service</h3><p class="pw-post-body-paragraph zm zn vm nv b zo anr zq zr zs ans zu zv nf ant zx zy nk anu aba abb np anv abd abe abf ki bq" data-selectable-paragraph="" id="0a7b">This
service is just a simple web application running in a local
environment, so my command line app can reach it. To establish the
connection for my command line app, I prepared a Negotiation endpoint.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="f6e1">First, I need a <code class="cn abg abh abi abj b">ServiceHubContext</code>. It's located in the Microsoft.Azure.SignalR.Management namespace too. In my solution, I use the <code class="cn abg abh abi abj b">StartAsync</code>
method of a hosted service in my web application. It's an interface to
mark an internal service of a web application. By implementing the <code class="cn abg abh abi abj b">StartAsync</code> method, you can prepare stuff in your web app before the app is handling requests in your endpoints.</p><h3 class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="6b96" style="text-align: left;"><img class="bn vj vk c" role="presentation" src="https://miro.medium.com/v2/resize:fit:764/1*IDN7p4SHvcxq7lFwEGUmgQ.png" title="Prepare a hub context" /> <br /></h3><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="6b96" style="text-align: left;">The second step is to provide an endpoint for negotiation. <br /></p><h3 class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="6b96" style="text-align: left;"><img class="bn vj vk c" role="presentation" src="https://miro.medium.com/v2/resize:fit:764/1*9ktb1vvlkVZ4D9Rq8TJaQA.png" title="Negotiation endpoint" /> <br /></h3><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="606c">(Just for explanation, the <code class="cn abg abh abi abj b">_hubContext</code> is the same instance as in the preparation before. It's injected in the constructor of my controller class)</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="b4ba">This
controller method negotiated a requester to use the SignalR service.
After the negotiation, a client app is able to send and receive
messages. It does not need the negotiation service anymore, except for
the app has been restarted.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="78f2">So,
anything looks great. The SignalR Service is prepared in the cloud as a
resource, my UWP app is able to send messages directly to this service,
a negotiation web app enables clients to connect to the SignalR service
too and finally my console line app is able to receive messages after a
successful negotiation.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="684e">But here comes the big BUT.</p><h3 class="anj abs vm am ank aho anl ahp mz ahr anm ahs ne ajo ann ajp ajq ajr ano ajs ajt aju anp ajv ajw anq bq" data-selectable-paragraph="" id="b8c4" style="text-align: left;">How to solve the big BUT?</h3><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="684e">The first message transfers leaded to a few errors. Not in my code. In
the SignalR library. I've got a lot of “System.IO.DataException in
Microsoft.AspNetCore.SignalR.Protocols,Json.dll” prints in the Debug
Window. But why? I send a message with two parameters of type string and
expect to receive a message with two parameters of type string.</p><blockquote><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="684e">ATTENTION, in the screenshot you will find the solution already <span class="vm">😁</span> <br /></p></blockquote><h3 class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="6b96" style="text-align: left;"> <img class="bn vj vk c" role="presentation" src="https://miro.medium.com/v2/resize:fit:764/1*9mJwzhmNRa9NZ6PE5FuW_A.png" title="Unchangeable type of sender" /></h3><h3 class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="6b96" style="text-align: left;"> <img class="bn vj vk c" role="presentation" src="https://miro.medium.com/v2/resize:fit:764/1*jr8in-r-1_IbEW0LuuaAGA.png" title="Wrong typed receiver" /></h3><h3 class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="6b96" style="text-align: left;"><img class="bn vj vk c" role="presentation" src="https://miro.medium.com/v2/resize:fit:764/1*uJ8ujqf41HTs2evxcX63IQ.png" title="Correct typed receiver" /> <br /></h3><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="ab84">I think the reason for that misunderstanding of typed receiver <a class="az hk" href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.signalr.client.hubconnectionextensions.on?view=aspnetcore-6.0" rel="noopener ugc nofollow" target="_blank">described here</a> is the intention to use (probably) a different sender. Maybe when I had used a <code class="cn abg abh abi abj b">HubConnection</code>
in my UWP app too, I think I had never seen the DataException. But as
long as we can use the SignalR Service directly, we will run into this
issue.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="8d9a">Hope it helpes you. 😉</p><h3 class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="6b96" style="text-align: left;"> </h3><h3 class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="6b96" style="text-align: left;"> </h3><h3 class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="6b96" style="text-align: left;"> </h3><p></p>Janek Fellienhttp://www.blogger.com/profile/11037083301535227855noreply@blogger.comtag:blogger.com,1999:blog-6438666738561404296.post-53717638550202875082024-03-26T17:08:00.000+01:002024-03-26T17:08:05.512+01:00Show Swagger Document in an Angular App<p style="text-align: left;">Recently I had an interesting request from one of my customers. They
wanted to have an API documentation close to its frontend, developed in
Angular. Well, actually a web designer would create a webpage and from
an API the page would load the data to put it on the page. But why we
will go this way? We have mostly a Swagger document, in YAML or JSON,
and probably a Swagger account to give acces to our customers. If we don't have an account, we still have the Swagger document. This document
is essential bounded to our development, so it would be great to use it.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="3574">So,
as the customer said “please add the documentation into my frontend
application”, a challenge started. Here I will describe the solution and
the traps I have fallen into.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="7f6b">My journey begun with a search for a npm package which deals Swagger documents well. I found some but <code class="cn abg abh abi abj b"><a class="az hk" href="https://www.npmjs.com/package/swagger-ui" rel="noopener ugc nofollow" target="_blank">swagger-ui</a></code> from npm was the one and only package which looked the best.</p><pre class="abk abl abm abn abo abp abj ra abq bf kx bq"><span class="abr abs vm abj b fi abt abu s wu abv" data-selectable-paragraph="" id="129c"><blockquote>> npm install --save swagger-ui</blockquote></span></pre><div><span class="abr abs vm abj b fi abt abu s wu abv" data-selectable-paragraph="" id="129c"><p style="text-align: left;">To use it in a page first we need an angular component for it. I started the Angular server:</p></span><pre class="abk abl abm abn abo abp abj ra abq bf kx bq"><blockquote><span class="abr abs vm abj b fi abt abu s wu abv" data-selectable-paragraph="" id="00d9">> ng serve</span></blockquote></pre><p class="abk abl abm abn abo abp abj ra abq bf kx bq" style="text-align: left;">Then I moved into the folder where the part of the webpage is stored in
which I wanted to add the Swagger documentation. In my case, it was the
settings dialog. Here I created a new component called
api-documentations:<span class="abr abs vm abj b fi abt abu s wu abv" data-selectable-paragraph="" id="00d9"> </span></p><pre class="abk abl abm abn abo abp abj ra abq bf kx bq"><blockquote><span class="abr abs vm abj b fi abt abu s wu abv" data-selectable-paragraph="" id="e968">> ng generate component api-documentations</span></blockquote></pre><p class="abk abl abm abn abo abp abj ra abq bf kx bq" style="text-align: left;">That created a subfolder with four files:</p><p class="abk abl abm abn abo abp abj ra abq bf kx bq" style="text-align: left;"><img alt="A list of generated files" class="bn vj vk c" height="142" src="https://miro.medium.com/v2/resize:fit:384/1*GtWxIv2ndzyZpjJjspvu7g.png" width="352" /> </p><p class="abk abl abm abn abo abp abj ra abq bf kx bq" style="text-align: left;"> </p><ol style="text-align: left;"><li><code class="cn abg abh abi abj b">api-documentations.component.html</code> is the design part of my new component but will not get any special stuff.</li><li><code class="cn abg abh abi abj b">api-documentations.component.scss</code> is the file with stylesheet definitions, but will not be used here.</li><li><code class="cn abg abh abi abj b">api-documentations.component.spec.ts</code> could be used for tests but I dont have any</li><li><code class="cn abg abh abi abj b">api-documentations.component.ts</code> this is will come the main part of my implementation</li></ol><p>Let's take a look into the <code class="cn abg abh abi abj b">.html</code> file. Here I changed only one thing but after a few errors I found out what was the <mark class="alm aln ap" style="background-color: white;">important</mark>.</p><pre class="abk abl abm abn abo abp abj ra abq bf kx bq"><blockquote><span class="abr abs vm abj b fi abt abu s wu abv" data-selectable-paragraph="" id="2e10"><div #customersapidocumentation id="customer-api-documentation"></div></span></blockquote></pre><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="0b2f">It's important to have a <code class="cn abg abh abi abj b">div</code> which contains an id in type of <code class="cn abg abh abi abj b">#[name the id you like]</code>. If you google for a Swagger implementation you will find some “solutions” but the way with <code class="cn abg abh abi abj b">#</code> will work due to the ViewChild-Selector in Angular.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="9430">This id we need to assign the Swagger generated content. This will happen in the <code class="cn abg abh abi abj b">.ts</code> file. So lets move to the <code class="cn abg abh abi abj b">api-documentations.component.ts</code> file.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="1f28">First, I imported the <code class="cn abg abh abi abj b">swagger-ui</code> package and the Swagger documentation as json:</p><pre class="abk abl abm abn abo abp abj ra abq bf kx bq"><span class="abr abs vm abj b fi abt abu s wu abv" data-selectable-paragraph="" id="be0d"><blockquote>import SwaggerUI from 'swagger-ui';<br />import customerApiDoc from './customerAPI-1.0.json'</blockquote></span></pre><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="20d3">in the compiler options.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="078b">Back to my component. After the <code class="cn abg abh abi abj b">@Component</code> section I implemented the <code class="cn abg abh abi abj b">AfterContentInit</code> interface and put the assignment code into the <code class="cn abg abh abi abj b">ngAfterContentInit()</code> method. Finally the connection between <code class="cn abg abh abi abj b">html</code> and generated documentation needs to be setup by define a <code class="cn abg abh abi abj b">ViewChild</code> element.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="c3a1">In the end the code in the <code class="cn abg abh abi abj b">.ts</code> file looks like this:</p><pre class="abk abl abm abn abo abp abj ra abq bf kx bq"><span class="abr abs vm abj b fi abt abu s wu abv" data-selectable-paragraph="" id="1d05"></span><blockquote><span class="abr abs vm abj b fi abt abu s wu abv" data-selectable-paragraph="" id="1d05">import { ElementRef } from '@angular/core';<br />import { Component, ViewChild, AfterContentInit } from '@angular/core';<br />import SwaggerUI from 'swagger-ui';<br />import customerApiDoc from './customerAPI-1.0.json';</span><span class="abr abs vm abj b fi acf abu s wu abv" data-selectable-paragraph="" id="2edb">@Component({ ... })</span><span class="abr abs vm abj b fi acf abu s wu abv" data-selectable-paragraph="" id="1b32">export class ApiDocumentationsComponent implements AfterContentInit {<br /> @ViewChild('customerapidocumentation',{static: true}) custApiDocElement: ElementRef | undefined</span><span class="abr abs vm abj b fi acf abu s wu abv" data-selectable-paragraph="" id="a726"> constructor() { }</span><span class="abr abs vm abj b fi acf abu s wu abv" data-selectable-paragraph="" id="9a59"> ngAfterContentInit(): void {<br /> const apiDocumentation = customerApiDoc;</span><span class="abr abs vm abj b fi acf abu s wu abv" data-selectable-paragraph="" id="67f8"> const ui = SwaggerUI({<br /> spec: apiDocumentation,<br /> domNode: this.custApiDocElement?.nativeElement,<br /> })<br /> }<br />}</span><span class="abr abs vm abj b fi abt abu s wu abv" data-selectable-paragraph="" id="be0d"> </span></blockquote></pre><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="6d3d">You can load the Swagger file from a public http endpoint too. Just enter the url and it will work. In some documentations for <code class="cn abg abh abi abj b">swagger-ui</code> you will see that you have to take <code class="cn abg abh abi abj b">dom_id</code>. Don't do it, it's wrong and will not work.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="3df6">To
find out what the right solution, it was an interesting way. But the
result is awesome. It looks like a original Swagger documentation. If
you change the document, you will channge the generated result too. For
example I’ve removed the virtual server part from my json file and the
result is there is no server anymore. Obviously.</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="c287">PS:
maybe you will ask why the documentation will not show in your
implementation. Let me guess one, you did not add the selector in your
page somewhere?</p><p class="pw-post-body-paragraph zm zn vm nv b zo zp zq zr zs zt zu zv nf zw zx zy nk zz aba abb np abc abd abe abf ki bq" data-selectable-paragraph="" id="1f28"> </p><pre class="abk abl abm abn abo abp abj ra abq bf kx bq"></pre></div><p class="pw-post-title vl fj vm am gl vn vo pu vp vq vr vs pw vt vu qn vv vw qo qq qr vx vy qs qu qv vz wa qw qy bq" data-selectable-paragraph="" data-testid="storyTitle" id="ac69" style="text-align: left;"></p>Janek Fellienhttp://www.blogger.com/profile/11037083301535227855noreply@blogger.comtag:blogger.com,1999:blog-6438666738561404296.post-15172680329287514662018-01-22T21:53:00.002+01:002018-01-22T21:53:55.126+01:00Am Rand und nicht am Abgrund<div class="separator" style="clear: both; text-align: center;">
</div>
<div style="margin-left: 1em; margin-right: 1em;">
<img class="_2zEKz" height="425" sizes="(max-width: 767px) 100vw, (max-width: 534px) 500px, (max-height: 509px) 500px, (min-aspect-ratio: 4272/2848) calc((calc(100vh - 175px)) * 1.5), calc(100vw - 34px)" src="https://images.unsplash.com/photo-1511215707251-99693c88dc1a?dpr=1&auto=format&fit=crop&w=1000&q=80&cs=tinysrgb" srcset="https://images.unsplash.com/photo-1511215707251-99693c88dc1a?auto=format&fit=crop&w=750&q=80 750w, https://images.unsplash.com/photo-1511215707251-99693c88dc1a?auto=format&fit=crop&w=1050&q=80 1050w, https://images.unsplash.com/photo-1511215707251-99693c88dc1a?auto=format&fit=crop&w=1350&q=80 1350w, https://images.unsplash.com/photo-1511215707251-99693c88dc1a?auto=format&fit=crop&w=1500&q=80 1500w, https://images.unsplash.com/photo-1511215707251-99693c88dc1a?auto=format&fit=crop&w=1650&q=80 1650w, https://images.unsplash.com/photo-1511215707251-99693c88dc1a?auto=format&fit=crop&w=1950&q=80 1950w, https://images.unsplash.com/photo-1511215707251-99693c88dc1a?auto=format&fit=crop&w=2100&q=80 2100w, https://images.unsplash.com/photo-1511215707251-99693c88dc1a?auto=format&fit=crop&w=2250&q=80 2250w, https://images.unsplash.com/photo-1511215707251-99693c88dc1a?auto=format&fit=crop&w=2550&q=80 2550w, https://images.unsplash.com/photo-1511215707251-99693c88dc1a?auto=format&fit=crop&w=2700&q=80 2700w, https://images.unsplash.com/photo-1511215707251-99693c88dc1a?auto=format&fit=crop&w=2850&q=80 2850w, https://images.unsplash.com/photo-1511215707251-99693c88dc1a?auto=format&fit=crop&w=3150&q=80 3150w, https://images.unsplash.com/photo-1511215707251-99693c88dc1a?auto=format&fit=crop&w=3300&q=80 3300w, https://images.unsplash.com/photo-1511215707251-99693c88dc1a?auto=format&fit=crop&w=3450&q=80 3450w, https://images.unsplash.com/photo-1511215707251-99693c88dc1a?auto=format&fit=crop&w=3750&q=80 3750w, https://images.unsplash.com/photo-1511215707251-99693c88dc1a?auto=format&fit=crop&w=3900&q=80 3900w, https://images.unsplash.com/photo-1511215707251-99693c88dc1a?auto=format&fit=crop&w=4050&q=80 4050w, https://images.unsplash.com/photo-1511215707251-99693c88dc1a?auto=format&fit=crop&w=4272&q=80 4272w, https://images.unsplash.com/photo-1511215707251-99693c88dc1a?auto=format&fit=crop&w=4500&q=80 4500w, https://images.unsplash.com/photo-1511215707251-99693c88dc1a?auto=format&fit=crop&w=5100&q=80 5100w, https://images.unsplash.com/photo-1511215707251-99693c88dc1a?auto=format&fit=crop&w=5700&q=80 5700w, https://images.unsplash.com/photo-1511215707251-99693c88dc1a?auto=format&fit=crop&w=6300&q=80 6300w, https://images.unsplash.com/photo-1511215707251-99693c88dc1a?auto=format&fit=crop&w=6900&q=80 6900w, https://images.unsplash.com/photo-1511215707251-99693c88dc1a?auto=format&fit=crop&w=7500&q=80 7500w, https://images.unsplash.com/photo-1511215707251-99693c88dc1a?auto=format&fit=crop&w=8100&q=80 8100w, https://images.unsplash.com/photo-1511215707251-99693c88dc1a?auto=format&fit=crop&w=8544&q=80 8544w" width="640" /></div>
<br />
<br />
<br />
Für ein spezielle Projekt habe ich mich in das Thema IoT Edge mit dem Raspberry PI versucht einzuarbeiten. Wenn es nach mir ginge, würde ich sagen mehr schlecht als recht, aber es kommt immer auf die Betrachtungsweise an. Durch mein Experimentieren habe ich viel gelernt, welches in den nächsten Monaten sicher noch öfter an unterschiedlichen Stellen erwähnt werden wird. Hier möchte ich im Grunde nur eine kurze Zusammenfassung bringen.<br />
<br />
<h3>
Am Rande der Technologie</h3>
Aus besagtem Grunde wollte ich mich intensiver mit dem Thema IoT beschäftigen. Im Besonderen sollte es der IoT Edge sein (sagt man das so, der Edge? Keine Ahnung) Was ist daran so besonders? Die Tatsache, dass dies der Begin der nächsten kleinen technologischen Revolution ist. IoT Edge verkörpert in seiner Art das Fog Computing. Das bedeutet, dass die Cloud erweitert wird. Nicht eine große Anzahl von verteilten Rechenzentren allein werden die Massen an Daten verarbeiten können. Die Cloud wird im Laufe der nächsten Jahre ausgelagert auch auf die Endanwendergeräte.<br />
Wie bitte? Mein Computer wird Teil der Cloud? Ja, das wird er und nicht nur der, sondern auch die vielen kleinen IoT Devices. Waschmaschinen, Kühlschränke - ja der IoT Kühlschrank kommt wieder - und all die anderen Geräte, die eine CPU haben, werden Teil des großen Ganzen. SkyNet lässt grüßen? Naja, wir werden sehen, wie klug wir die Geräte machen. Schließlich sind wir diejenigen, die diese Geräte a) programmieren und b) ihnen das "Leben" einhauchen.<br />
<br />
Gut, zurück zum Thema IoT Edge.<br />
<br />
<h3>
Himbeerkuchen</h3>
Mein Versuch begann damit einem Raspberry PI so viel Leben einzuhauchen, dass er in regelmäßigen Abständen die aktuellen Licht und Temperaturdaten meiner Wohnung übermittelt. Mit der richtigen Anleitung ging das sehr schnell.<br />
<h4>
Das Setup I :</h4>
Raspberry PI (RPI) mit Windows IoT Core und dem klassischen Raspberry PI Sensor Pack. Als Applikation lief eine Exe File mit einem Timer, der alle 5 Minuten die Daten übermittelte.<br />
<br />
Das war alles fast kein Problem, abgesehen von ein paar kleineren Netzwerkfehlern bei mir zu Hause. Das ganze war innerhalb von 6 Stunden erledigt.<br />
<br />
Das wahre Problem hier ist jedoch die Machbarkeit. Ein solches Setup entspricht nicht dem, was in der Realität zur Zeit vorherrscht. Auch wenn Microsoft gerne möchte, dass IoT Core mehr zum Einsatz kommt, Linux ist doch noch etwas verbreiteter. Also musste ich den nächsten Schritt gehen, RPI mit Linux.<br />
<h4>
Das Setup II:</h4>
Der RPI fühlt sich mit Linux einfach beeindruckend gut an. Ein Problem, das .Net Framework ist hierfür nicht geschaffen. Also muss .Net Core ran. Für mich tatsächlich das erste Mal, weil ich einfach abwarte wollte.<br />
Also, ran an den RPI, auf dem nun <a href="https://www.raspberrypi.org/downloads/" target="_blank">Raspian</a> installiert wurde. Dann noch schnell die Edge Umgebung drauf und NICHTS GEHT MEHR. Moment, was habe ich falsch gemacht?<br />
<br />
<h3>
Schlick und Modder</h3>
<div>
Als ich die erste Installation durchführte, ließ ich mich mächtig in die Irre führen, was mir mehrere Stunden Lernen einbrockte. Ich ging davon aus dass die Anleitung [1] geschrieben wurde, mit dem Wissen, dass es funktioniert. Weit gefehlt, der Autor hat nur vermutet, dass es klappt. </div>
<div>
Ich hatte schlichtweg vor, die Azure Functions Runtime auf einem RPI zum Laufen zu bringen, was laut der Beschreibung klappen sollte (Konjunktiv).</div>
<div>
Die ersten Versuche endeten damit, dass ich erst einmal lernte, wo man die Logs von docker findet. Dazu kam, dass ich feststellten durfte, dass die Dockerversion 17.11 CE für IoT Edge nicht brauchbar ist. Ach was sage ich, sie ist für niemanden zu gebrauchen, was ja auch dazu führte, dass sie sehr schnell gegen eine höhere Version ausgetauscht wurde. Aber bitte meine Lieben, warum erwische ich denn immer wieder diese Versionen, die nicht funktionieren. (Augenverdreh)</div>
<div>
<br /></div>
<div>
<a href="https://images.unsplash.com/photo-1483569577148-f14683bed627?dpr=1&auto=format&fit=crop&w=1000&q=80&cs=tinysrgb" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img alt="A man with his hands covered with mud" border="0" class="_2zEKz" height="424" sizes="(max-width: 767px) 100vw, (max-width: 534px) 500px, (max-height: 507px) 500px, (min-aspect-ratio: 4928/3264) calc((calc(100vh - 175px)) * 1.5098039215686274), calc(100vw - 34px)" src="https://images.unsplash.com/photo-1483569577148-f14683bed627?dpr=1&auto=format&fit=crop&w=1000&q=80&cs=tinysrgb" srcset="https://images.unsplash.com/photo-1483569577148-f14683bed627?auto=format&fit=crop&w=755&q=80 755w, https://images.unsplash.com/photo-1483569577148-f14683bed627?auto=format&fit=crop&w=1055&q=80 1055w, https://images.unsplash.com/photo-1483569577148-f14683bed627?auto=format&fit=crop&w=1355&q=80 1355w, https://images.unsplash.com/photo-1483569577148-f14683bed627?auto=format&fit=crop&w=1510&q=80 1510w, https://images.unsplash.com/photo-1483569577148-f14683bed627?auto=format&fit=crop&w=1655&q=80 1655w, https://images.unsplash.com/photo-1483569577148-f14683bed627?auto=format&fit=crop&w=1955&q=80 1955w, https://images.unsplash.com/photo-1483569577148-f14683bed627?auto=format&fit=crop&w=2110&q=80 2110w, https://images.unsplash.com/photo-1483569577148-f14683bed627?auto=format&fit=crop&w=2255&q=80 2255w, https://images.unsplash.com/photo-1483569577148-f14683bed627?auto=format&fit=crop&w=2555&q=80 2555w, https://images.unsplash.com/photo-1483569577148-f14683bed627?auto=format&fit=crop&w=2710&q=80 2710w, https://images.unsplash.com/photo-1483569577148-f14683bed627?auto=format&fit=crop&w=2855&q=80 2855w, https://images.unsplash.com/photo-1483569577148-f14683bed627?auto=format&fit=crop&w=3155&q=80 3155w, https://images.unsplash.com/photo-1483569577148-f14683bed627?auto=format&fit=crop&w=3310&q=80 3310w, https://images.unsplash.com/photo-1483569577148-f14683bed627?auto=format&fit=crop&w=3455&q=80 3455w, https://images.unsplash.com/photo-1483569577148-f14683bed627?auto=format&fit=crop&w=3755&q=80 3755w, https://images.unsplash.com/photo-1483569577148-f14683bed627?auto=format&fit=crop&w=3910&q=80 3910w, https://images.unsplash.com/photo-1483569577148-f14683bed627?auto=format&fit=crop&w=4055&q=80 4055w, https://images.unsplash.com/photo-1483569577148-f14683bed627?auto=format&fit=crop&w=4355&q=80 4355w, https://images.unsplash.com/photo-1483569577148-f14683bed627?auto=format&fit=crop&w=4510&q=80 4510w, https://images.unsplash.com/photo-1483569577148-f14683bed627?auto=format&fit=crop&w=4655&q=80 4655w, https://images.unsplash.com/photo-1483569577148-f14683bed627?auto=format&fit=crop&w=4928&q=80 4928w, https://images.unsplash.com/photo-1483569577148-f14683bed627?auto=format&fit=crop&w=5110&q=80 5110w, https://images.unsplash.com/photo-1483569577148-f14683bed627?auto=format&fit=crop&w=5710&q=80 5710w, https://images.unsplash.com/photo-1483569577148-f14683bed627?auto=format&fit=crop&w=6310&q=80 6310w, https://images.unsplash.com/photo-1483569577148-f14683bed627?auto=format&fit=crop&w=6910&q=80 6910w, https://images.unsplash.com/photo-1483569577148-f14683bed627?auto=format&fit=crop&w=7510&q=80 7510w, https://images.unsplash.com/photo-1483569577148-f14683bed627?auto=format&fit=crop&w=8110&q=80 8110w, https://images.unsplash.com/photo-1483569577148-f14683bed627?auto=format&fit=crop&w=8710&q=80 8710w, https://images.unsplash.com/photo-1483569577148-f14683bed627?auto=format&fit=crop&w=9310&q=80 9310w, https://images.unsplash.com/photo-1483569577148-f14683bed627?auto=format&fit=crop&w=9856&q=80 9856w" width="640" /></a>Nach dem Update von Docker auf allen Geräten konnte es endlich losgehen. Sollte man meinen. Dem macOS beizubringen, dass pip installiert werden soll ist auch nicht ganz logisch, wenn man die ganze Zeit mit <span style="font-family: Courier New, Courier, monospace;">sudo apt-get install</span> arbeitet. Mit pip sollten irgendwelche Tools nachinstalliert werden, die dann dummerweise auf dem Mac nicht funktionierten. Eine Woche später schon sieht das ganz anders aus, da hat wohl jemand mächtig am Bug-Killer gebastelt.</div>
<div>
Nach sehr vielen erfolglosen Versuchen richtete ich mir einen Linuxrechner ein, bei dem fast alles auf Anhieb funktionierte nur leider die Azure Functions Environment auf dem RPI nicht. Was ist da bloß los? Im Log vom edgeAgent (<span style="font-family: Courier New, Courier, monospace;">docker logs edgeAgent</span>) stand nur der Hinweis, dass die Function nicht gestartet werden konnte. </div>
<div>
<br /></div>
<div>
Also erstmal wieder auf Anfang. Blanke SD-Card mit frischem Raspian, saubere Linuxumgebung und mit mächtig Blutdruck ein Feedback an die Leute geschrieben, die die Dokumentation fabriziert hatten. Nach ca. 5 Stunden kam eine Antwort <i>"Kannste ma 'n Log zeigen"</i> Leute, welches Log? Von Docker gibt es drei und wer weiß, wo noch Zeug hingeschrieben wird.</div>
<div>
Die Logs, die ich gefunden habe musste ich aus technischen Gründen als Gist ablegen. Dort schaute sich tatsächlich jemand den Quatsch an und siehe da: <i>"Ja du, die Function startet nicht"</i>. Ach nee, Blitzmerker, das habe ich nach einer Woche fummeln auch festgestellt. Was ist denn das Problem? Any Idea? <i>"Na nimm doch mal ein anderes Image für dein <b>IoT Edge Module(</b></i><span style="color: #24292e;"><span style="font-family: Courier New, Courier, monospace;">microsoft/dotnet:2.0.0-runtime-stretch-arm32v7</span></span><i><b>)</b>"</i>. Gesagt getan. Das eine Image im Dockerfile gegen das andere ausgetauscht. Aber warte mal, was steht da? IoT Edge Module? Das ist keine Function. Die darauf folgende Nacht habe ich sehr unruhig geschlafen. Da bekommt man Hilfe und dann ist das total nutzlos, denn ich hatte ja nicht vor, ein Modul zu starten, sondern eine Function App. Oh Gott lass es vernunftbegabte Softwareentwickler regnen.</div>
<div>
<br /></div>
<div>
</div>
<h3>
Reinigender R(S)egen</h3>
<div>
Nach einer sehr unruhigen Nacht machte es plötzlich Pling. Ja klar, der Kollege wollte wirklich nur helfen und schickt mir quasi durch zehn Blumen gesprochen den Hinweis, dass Functions evtl noch nicht funktionieren. Ja Moment, das ließe sich doch sehr schnell herausfinden, ich hatte ja inzwischen schon gelernt, wie man mit Registries für Docker Container umgeht, wie man in VSCode die richtigen Extensions installiert und vieles mehr. </div>
<div>
<br /></div>
<div>
<img class="_2zEKz" height="426" sizes="(max-width: 767px) 100vw, (max-width: 534px) 500px, (max-height: 509px) 500px, (min-aspect-ratio: 5184/3456) calc((calc(100vh - 175px)) * 1.5), calc(100vw - 34px)" src="https://images.unsplash.com/photo-1460013477427-b0cce3e30151?dpr=1&auto=format&fit=crop&w=1000&q=80&cs=tinysrgb" srcset="https://images.unsplash.com/photo-1460013477427-b0cce3e30151?auto=format&fit=crop&w=750&q=80 750w, https://images.unsplash.com/photo-1460013477427-b0cce3e30151?auto=format&fit=crop&w=1050&q=80 1050w, https://images.unsplash.com/photo-1460013477427-b0cce3e30151?auto=format&fit=crop&w=1350&q=80 1350w, https://images.unsplash.com/photo-1460013477427-b0cce3e30151?auto=format&fit=crop&w=1500&q=80 1500w, https://images.unsplash.com/photo-1460013477427-b0cce3e30151?auto=format&fit=crop&w=1650&q=80 1650w, https://images.unsplash.com/photo-1460013477427-b0cce3e30151?auto=format&fit=crop&w=1950&q=80 1950w, https://images.unsplash.com/photo-1460013477427-b0cce3e30151?auto=format&fit=crop&w=2100&q=80 2100w, https://images.unsplash.com/photo-1460013477427-b0cce3e30151?auto=format&fit=crop&w=2250&q=80 2250w, https://images.unsplash.com/photo-1460013477427-b0cce3e30151?auto=format&fit=crop&w=2550&q=80 2550w, https://images.unsplash.com/photo-1460013477427-b0cce3e30151?auto=format&fit=crop&w=2700&q=80 2700w, https://images.unsplash.com/photo-1460013477427-b0cce3e30151?auto=format&fit=crop&w=2850&q=80 2850w, https://images.unsplash.com/photo-1460013477427-b0cce3e30151?auto=format&fit=crop&w=3150&q=80 3150w, https://images.unsplash.com/photo-1460013477427-b0cce3e30151?auto=format&fit=crop&w=3300&q=80 3300w, https://images.unsplash.com/photo-1460013477427-b0cce3e30151?auto=format&fit=crop&w=3450&q=80 3450w, https://images.unsplash.com/photo-1460013477427-b0cce3e30151?auto=format&fit=crop&w=3750&q=80 3750w, https://images.unsplash.com/photo-1460013477427-b0cce3e30151?auto=format&fit=crop&w=3900&q=80 3900w, https://images.unsplash.com/photo-1460013477427-b0cce3e30151?auto=format&fit=crop&w=4050&q=80 4050w, https://images.unsplash.com/photo-1460013477427-b0cce3e30151?auto=format&fit=crop&w=4350&q=80 4350w, https://images.unsplash.com/photo-1460013477427-b0cce3e30151?auto=format&fit=crop&w=4500&q=80 4500w, https://images.unsplash.com/photo-1460013477427-b0cce3e30151?auto=format&fit=crop&w=4650&q=80 4650w, https://images.unsplash.com/photo-1460013477427-b0cce3e30151?auto=format&fit=crop&w=4950&q=80 4950w, https://images.unsplash.com/photo-1460013477427-b0cce3e30151?auto=format&fit=crop&w=5100&q=80 5100w, https://images.unsplash.com/photo-1460013477427-b0cce3e30151?auto=format&fit=crop&w=5184&q=80 5184w, https://images.unsplash.com/photo-1460013477427-b0cce3e30151?auto=format&fit=crop&w=5700&q=80 5700w, https://images.unsplash.com/photo-1460013477427-b0cce3e30151?auto=format&fit=crop&w=6300&q=80 6300w, https://images.unsplash.com/photo-1460013477427-b0cce3e30151?auto=format&fit=crop&w=6900&q=80 6900w, https://images.unsplash.com/photo-1460013477427-b0cce3e30151?auto=format&fit=crop&w=7500&q=80 7500w, https://images.unsplash.com/photo-1460013477427-b0cce3e30151?auto=format&fit=crop&w=8100&q=80 8100w, https://images.unsplash.com/photo-1460013477427-b0cce3e30151?auto=format&fit=crop&w=8700&q=80 8700w, https://images.unsplash.com/photo-1460013477427-b0cce3e30151?auto=format&fit=crop&w=9300&q=80 9300w, https://images.unsplash.com/photo-1460013477427-b0cce3e30151?auto=format&fit=crop&w=9900&q=80 9900w, https://images.unsplash.com/photo-1460013477427-b0cce3e30151?auto=format&fit=crop&w=10368&q=80 10368w" width="640" /></div>
<div>
<br /></div>
<div>
Heute dann brachte mir eine Anfrage bei <a href="https://stackoverflow.com/questions/48379948/how-to-run-azure-functions-as-iot-edge-module-on-a-raspberry-pi/48387258#48387258" target="_blank">StackOverflow</a> die ersehnte Antwort, auch wenn sie für mich im Grunde niederschmetternd war, so hatte meine Suche endlich ein Ende. Meine Anfrage dort wurde prompt von meinen Community Kollegen beantwortet. Functions werden bei IoT Edge noch nicht unterstützt. Okay. Eine weitere Antwort brachte aber so viel Licht ins Dunkel, dass es mich für viele Tage erleuchten wird. (Nu bleib mal auf dem Teppich) </div>
<div>
<br /></div>
<span style="background-color: white; font-family: Arial, "Helvetica Neue", Helvetica, sans-serif; font-size: 15px;"><i><span style="color: #134f5c;">"So, I went to check the status of Azure Functions Runtime and the good news is that they have now a version of their runtime for ARM."</span></i></span><br />
<div>
<span style="background-color: white; color: #242729; font-family: Arial, "Helvetica Neue", Helvetica, sans-serif; font-size: 15px;"><br /></span></div>
<div>
Ich werde in absehbarer Zeit meine geliebten Functions auf eines der coolsten Devices nageln können. Herrlich. Vielen Dank an das Azure Functions Team.</div>
<div>
<br /></div>
<div>
Wenn ich Erfolg in diesem Projekt vermelden kann, dann werde ich einen weiteren Post schreiben.</div>
<div>
<br /></div>
<div>
~janekf</div>
<div>
<br /></div>
<div>
Links zu den Anleitungen:</div>
<div>
[1] Hervorragende Anleitung, um IoT Edge auf den RPI zu bekommen: <a href="https://blog.jongallant.com/2017/11/azure-iot-edge-raspberrypi/">https://blog.jongallant.com/2017/11/azure-iot-edge-raspberrypi/</a></div>
<div>
<br /></div>
<div>
[2] Microsofts Dokumentation, die zu Beginn sehr viel zu wünschen übrig ließ:</div>
<div>
<a href="https://docs.microsoft.com/en-us/azure/iot-edge/tutorial-simulate-device-linux">https://docs.microsoft.com/en-us/azure/iot-edge/tutorial-simulate-device-linux</a></div>
Janek Fellienhttp://www.blogger.com/profile/11037083301535227855noreply@blogger.comtag:blogger.com,1999:blog-6438666738561404296.post-2510354951399066422017-12-15T15:15:00.000+01:002018-01-02T21:46:29.296+01:00Von hinten durch die Brust ins Auge<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwgSA8eY9cexSPZdPZ8Ksl0ATE2DRy67H47EO83aOLPquxETw8XDGBGACA3eXjU_4RM1K2cwiluuDKOaW8XU3J8pLXkXgofHIBSBVlIgY7UhiOuFKFInuDjVGtd4zhZIF0WtSkJF7aaSCM/s1600/max-larochelle-421822.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="thunder" border="0" data-original-height="750" data-original-width="600" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwgSA8eY9cexSPZdPZ8Ksl0ATE2DRy67H47EO83aOLPquxETw8XDGBGACA3eXjU_4RM1K2cwiluuDKOaW8XU3J8pLXkXgofHIBSBVlIgY7UhiOuFKFInuDjVGtd4zhZIF0WtSkJF7aaSCM/s1600/max-larochelle-421822.jpg" title="" /></a></div>
<br />
<h2>
Wie der Hybrid Connection Manager den Datenbank Admin nervt</h2>
<div>
UPDATE [02.01.2018]: siehe Abschnitt 'Andere Sprache' und 'Resümee'</div>
<br />
Seit ich mich mit den <a href="https://azure.microsoft.com/de-de/services/functions/" target="_blank">Azure Functions</a> auseinandersetze höre ich von verschiedenen Leuten witzige aber auch unangenehme Bugs. Die meisten lassen sich auf die dahinterliegende Architektur rückschließen. Andere Fehler sind nicht wirklich nachvollziehbar oder haben ihre Ursache an völlig anderen Stellen. Nicht immer, wenn etwas nicht funktioniert, liegt der Grund in der Cloud. Einen speziellen Fall möchte ich euch hier vorstellen. Dazu muss ich aber einen kleinen Umweg gehen, denn wer sich bisher nicht all zu viel mit den Function Apps auseinandergesetzt hat könnte sonst den Faden verlieren.<br />
<br />
<h3>
Datenintegration mit Azure Functions</h3>
Azure Functions sind, als sie das erste mal publiziert wurden, unter anderem als Werkzeug für Data Pipelines beschrieben worden. Das ist im Grunde auch in Ordnung, wenn man kein Echtzeitverhalten erwartet.<br />
<br />
Für diese Pipeline richtet man eine Function App ein, die mindestens einen Endpunkt hat, der entweder getriggert wird, um Daten aus einer Datenbank zu lesen oder direkt Daten empfängt. Das geschieht in jedem Fall mittels eines HTTP Triggers.<br />
<br />
Daten aus einer Datenbank zu lesen ist eigentlich ziemlich einfach, wenn diese ebenfalls in der Azure Cloud eingerichtet ist. Dann kann man eine API Connection dahin aufbauen und mittels IN-Binding aus einer Tabelle/View die Daten lesen. Alles hübsch soweit, wäre da nicht die hässliche Realität. In dieser Realität sind die Datenbanken OnPrem im eigenen Data Center. Hierfür gibt es eine tolle Lösung, den <a href="https://docs.microsoft.com/de-de/azure/app-service/app-service-hybrid-connections" target="_blank">Hybrid Connection Manager</a>, quasi ein Reverse Proxy. Die Realität erlaubt sich einen weiteren Knüppel in das sauber geschmierte Rad der Azure Functions zu werfen, die Daten an sich. Wenn man ein IN-Binding auf eine Tabelle/View einrichtet, werden bei jedem Aufruf der Funktion alle Zeilen gelesen. Das mag bei kleinen Datenmenge okay sein, aber schon ab 500.000 Datensätzen fängt es an sehr langsam zu werden. Der Grund hierfür: das virtuelle Dateisystem hinter den Function Apps, das eine ziemlich schlechte IO Verwaltung hat. Noch ist das so, es wird aber sicher besser.<br />
<br />
Wenn man also viele Daten laden möchte, muss man sich des Paging oder den Continuations bemächtigen. Sprich seitenweises Laden der Daten. Dann steht man mit dem IN-Binding auf verlorenem Posten. Was nun?<br />
<br />
<h3>
Ein bisschen Old School</h3>
Man kann also das beeindruckend praktische IN-Binding nicht nutzen und auch eine direkte Connection zu den Daten existiert nicht. Warum dann die Functions dafür nutzen? Weil es ein supereinfaches System ist, bei dem man nur ein bisschen Code schreibt, um ans Ziel zu gelangen. Wollte man zum gleichen Ergebnis kommen ohne einer Function App, muss man sich um den Host und die ganze Infrastruktur kümmern. Das möchte man nicht, zumindest ich möchte das nicht mehr. Also bleibe ich bei der Lösung mit der Functions App aber mit ein bisschen Old School.<br />
<br />
Wenn man Daten aus einer Datenbank holt und dafür C# verwendet, dann ist das okay, aber nervend, weil damit alles typisiert sein muss. In der Azure Welt wird zum Glück sehr viel mit JSON gearbeitet. Darum ist es sehr praktisch, dass man Funktionen in einer Functions App in JavaScript schreiben kann. Für ein hübsches Schriftbild verendet man üblicherweise das <a href="https://www.npmjs.com/package/mssql" target="_blank">npm package <b><i>mssql</i></b></a>, um Daten aus einem SQL Server zu lesen.<br />
<br />
<h3>
Well connected</h3>
Alles ist vorbereitet. Wir haben eine Function App mit einer Funktion, geschrieben in JavaScript, die super einfach Daten aus einer Datenbank liest und irgendwie weiterverarbeitet. Blöd nur wenn plötzlich ein Datenbank Admin neben einem steht und fragt:<br />
<br />
<div style="text-align: center;">
<b>"Samma, wat hastn da jebaut? Ick hab hier hundate offne Connections. Dein User baut zwar uff, abber nich mehr ab."</b></div>
<br />
Wie jetzt? Ich habe doch überall das notwendige<span style="font-family: "courier new" , "courier" , monospace;"> pool.close()</span> oder <span style="font-family: "courier new" , "courier" , monospace;">sql.close()</span> eingebaut.<br />
<br />
Nach einiger Analyse stellt sich tatsächlich heraus, dass die Connection zwar geöffnet wird, aber nicht wieder abgebaut. Wie kann das sein? Eine Analyse muss her.<br />
<br />
<h4>
Anderes Package</h4>
Wenn es am <i><b>mssql</b></i> Package liegt, dann wechselt man eben auf <a href="https://www.npmjs.com/package/tedious" target="_blank"><i><b>tedious</b></i></a>, welches zwar im Hintergrund von <i><b>mssql</b></i> läuft, aber man kann ja nicht wissen.<br />
Ohne Erfolg, die Connections bleiben auch hier bestehen und werden nicht geschlossen.<br />
<br />
<h4>
Datenbank in der Cloud</h4>
Nanu, damit geht es plötzlich? Wenn die Datenbank in der Cloud läuft, dann baut sich die Connection ab. Okay, hier wird keine Hybrid Connection Manager gebraucht.<br />
Blöd nur, dass die Datenbank meistens aus rechtlichen Gründen nicht in der Cloud laufen darf. Das ist also keine Option als Lösung.<br />
<br />
<h4>
Andere Sprache</h4>
Bei genauerer Betrachtung der anderen Projekte, die ich mit Functions umgesetzt habe sieht man offensichtlich, dass ich mit C# und JavaScript arbeite. <strike>Ausgerechnet die Funktionen in C# und mit Datenzugriff scheinen die Connection sauber zu schließen, bzw. den Connection Pool korrekt zu nutzen. Sprich wenn ich alle Funktionen, die Datenbankzugriffe haben, auf C# umstelle, dann könnte ich auf der sicheren Seite sein.</strike><br />
<b>UPDATE</b>: Falsch gedacht. Nach eingehender Betrachtung habe ich feststellen müssen, dass der Connection Pool mit C# zwar eine Weile lang weiter verwendet wird, sprich keine weiteren Connections aufgebaut werden, aber nach einer Weile - Zeitraum unbekannt - werden weitere Pools angelegt. Die bereits vorhandenen werden dann nicht abgebaut, sondern bleiben bestehen. Mist aber auch. :(<br />
<br />
<h3>
Resümee</h3>
<div>
Nach einigen Tests ergab, dass JavaScript zwar die coolere Sprache für die Cloud ist, weil alles sofort in JSON zur Verfügung steht. Wenn aber in der Kombination JavaScript + Hybrid Connection Manager + SQL Server die Connections nicht wieder abgebaut werden, muss man in den sauren Apfel beißen und JavaScript durch C# + Newtonsoft.Json austauschen. <strike>In diesem Fall hat alles bestens funktioniert. Warum die Connections nicht abgebaut werden ist nicht wirklich klar. Dass in diesem Fall die Function Apps nichts damit zu tun haben würde ich daraus schließen, dass bei der Verwendung von C# alles okay ist und wenn man mit JavaScript eine Datenbank in der Cloud abfragt ist auch alles okay.</strike><br />
<b>UPDATE</b>: Leider falsch, siehe 'Andere Sprache'. Auch unter C# werden die Connections nicht korrekt abgebaut. Was man nun versuchen kann, ist das External Table Bindig zu verwenden. Dieses ist jedoch immer noch (seit fast zwei Jahren) im experimental Stadium.</div>
<br />
<br />
<br />
<br />
<br />
<br />
<br />Janek Fellienhttp://www.blogger.com/profile/11037083301535227855noreply@blogger.comtag:blogger.com,1999:blog-6438666738561404296.post-23203745178497195282016-10-26T23:01:00.000+02:002016-11-13T23:12:12.188+01:00Bis einer weint<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoK9rFK_Ted15fci1DMUmBtQNph04zzO7B4O8IHzPLapSlmpVWxlUabxsaB3M6I__RzGNkpnCfByVPCAFPtl_fvmGaObfBFEfsren6xd9VxHXMGhkLMcwnGm-idHky7pztctpDAu_K1Q7p/s1600/Hand-1.jpeg" imageanchor="1" style="clear: left; display: inline !important; float: left; margin-bottom: 1em; margin-right: 1em; text-align: center;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoK9rFK_Ted15fci1DMUmBtQNph04zzO7B4O8IHzPLapSlmpVWxlUabxsaB3M6I__RzGNkpnCfByVPCAFPtl_fvmGaObfBFEfsren6xd9VxHXMGhkLMcwnGm-idHky7pztctpDAu_K1Q7p/s1600/Hand-1.jpeg" /></a><br />
<br />
Was als Spass begann endet nun in vollem Ernst.<br />
<br />
<a href="https://twitter.com/mikebild" target="_blank">Mike Bild</a>, den ich (leider erst) Anfang 2010 kennenlernte, offerierte mir vor sechs Jahren, dass es eine Konferenz für die Community gibt, die man unbedingt besuchen sollte, wenn man die wirklich spannenden Themen kennen lernen möchte. Bis dato flog ich am Rande mit und interessierte mich für alles, was nach Zukunft aussah. Ja ehrlich, sogar die WCF habe ich anfänglich dazu gezählt. Und dann kam mein erster <a href="https://devopenspace.de/" target="_blank">Developer Open Space</a>, damals noch vorrangig auf die .Net Technologien ausgerichet. Diese Konferenz stellte alles bisherige in den Schatten. Jede BASTA oder sonstige kommerzielle Konferenz verkümmerte nur noch zu einem Haufen Elend. Hier in Leipzig traf man Hinz und Kunz der Softwareentwicklung, ging auf Tuchfühlung mit den wirklich spannenden Leuten und konnte ungezwungen mit ihnen ins Gespräch kommen. Ich kann mich noch gut an die ersten Begegnungen mit <a href="https://twitter.com/ilkerde" target="_blank">Ilker Cetinkaya</a>, <a href="https://twitter.com/lennybacon" target="_blank">Daniel Fisher</a> oder <a href="https://twitter.com/StefanLieser" target="_blank">Stefan Lieser</a> erinnern. Das waren echte Highlights auf dem Weg in die Community.<br />
<br />
Das erste Mal war beeindruckend. Im zweiten Jahr war die Sorge der Agendagestaltung genommen und ich reichte selbst etwas ein. Keine Ahnung was es war, aber Blut war geleckt. Ich wollte mehr davon, was dazu führte, dass Mike und ich zusammen in 2012 die längste Session aller Zeiten hielten. Sechs Stunden CQRS und der Raum war permanent gut gefüllt. Die Teilnehmer der Konferenz wurden einfach nicht satt, so dass wir auch nicht aufhörten. Das macht den Open Space aus. Keine Agenda, keine zeitliche Beschränkung und jeder ist zur richtigen Zeit im richtigen Raum. Wissen und Inspiration pur, keine Ablenkung oder Einschränkungen.<br />
<br />
Das änderte sich jedoch im Laufe der Zeit. Mehr Teilnehmer, mehr "Neulinge" (wie ich es auch einmal war), mehr Konsumenten, mehr Frontalvorträge und Ablenkung. Der klassische Open Space scheint verschwunden zu sein. Ja klar, die Meinungen der Teilnehmer sind trotzdem positiv, so auch meine. Man trifft sich mit den Kollegen, diskutiert manchmal innerhalb manchmal außerhalb der Sessions über das neue "Shiny Toy" und hat eine gute Zeit. Unbestritten. Und dennoch kündige ich hiermit meinen Abschied von all dem an.<br />
<br />
<b>Auf ein Wiedersehen im nächsten offenen Raum.</b><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihC35ECGlBHcIxnSD-fv-xffTkOL4MUQhkuNIlheUMS_8THzM24xHd7dN2P0PabHIFcirTyiK8retomGyjS_2S8iNoc6ac_WoX5TB_UdkkVasw3eUe_6LF2bZzFnGU4kiKw7LujzzvnEfT/s1600/hiking.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihC35ECGlBHcIxnSD-fv-xffTkOL4MUQhkuNIlheUMS_8THzM24xHd7dN2P0PabHIFcirTyiK8retomGyjS_2S8iNoc6ac_WoX5TB_UdkkVasw3eUe_6LF2bZzFnGU4kiKw7LujzzvnEfT/s1600/hiking.jpg" /></a></div>
<br />
<br />
Kommerz verschafft sich Platz. Nicht nur in Form der stetig steigenden Preise, sondern auch in der Ausführung. "Eine Werbeflut gibt es nicht" heißt es sinngemäß auf der Webseite, um dann am Empfang mit einem Tisch und einer Tüte voller Werbung begrüßt zu werden. Das schmeckt irgendwie bitter. Bin ich empfindlich hierbei? Kann gut sein. Ich nehme halt die Texte auf den Webseiten entsprechend wahr und lege sie für mich aus - mein subjektives Empfinden kann man mir nun mal nicht nehmen.<br />
<br />
"Der größte ... aller Zeiten mit 400 Teilnehmern!" wow, denkt man da zurecht. Da hat die Orga ordentlich einen ausgetütet, sich ins Zeug gelegt und Leute erreicht. Ich war etwas skeptisch, ob ich das gut finden soll, von 250 Teilnehmern im letzten Jahr auf nunmehr fast doppelt so viel. Da geht doch das familiäre verloren. Und dann das. Keine 400 Leute standen da beim Finden der Agenda. Die mühevoll vorbereitetes Garage des Hotels war zwar übersichtlich gefüllt, aber nicht mit 400 Leuten. Ich würde sagen, es waren 400 Anmeldungen, aber aktive Teilnehmer pro Tag waren vielleicht 200 bis 250 unterwegs, also die gleiche Menge wie schon die Jahre zuvor. Was für ein Glück, dass es nicht so viel war. Und dennoch, ein komischer Geschmack bleibt in der Formulierung "400 Teilnehmer". Muss man so an den Knöppen drehen - wie man in Berlin sagt? Sicher nicht, es sei denn, man möchte noch mehr Teilnehmer im nächsten Jahr erreichen.<br />
<br />
Glaubt mir, ich weiß was es bedeutet eine solche Veranstaltung zu organisieren. Die Berliner <a href="https://spartakiade.org/" target="_blank">Spartakiade</a> begleitete ich für 5 Jahre, bis 2016. Auch dies ist nun vorbei für mich. Der Aufwand, der Stress und die permanente passive Aggressivität, alles falsch zu machen, hat mich zu diesem Entschluss bewogen. Zudem kommt der Aspekt, bis heute nicht genau zu wissen was mit den Teilnehmer- und Sponsorengeldern passiert ist. Nur in groben Zügen kann ich den Fluss nachvollziehen, aber eine genaue Antwort auf meine Anfrage erhielt bisher nicht. Schade, dass wieder mal Freundschaften am Geld zerbrechen.<br />
Nun gut, die nächste Spartakiade ist sicher wieder die <i>größte und beste aller Zeiten</i>, nur halt ohne mich. Und der nächste Developer Open Space wird sicher auch <i>der größte und beste aller Zeiten</i>, ebenfalls ohne meine Teilnahme.<br />
<br />
Ich ziehe mit Freunden weiter. Menschen, die mir gut tun und mit denen ich gemeinsam etwas Neues entstehen lassen kann. Community Kollegen, die gerne miteinander ehrlich und respektvoll umgehen.<br />
<br />
~janekf<br />
<br />
<i>Auf Wiedersehen Ulrike, Esther, Krisztina, Karen, Irina, Kate, Thomas, Mike, Maik, Alex, Alexander, Christian, Steffen, Stefan, Staphan, Hans-Peter, Steve, Sia, Sebastian, Anton, Rocco, Richard, Daniel, Martin, Kai, Gregor, Torsten, Thorsten, Jens, Robert, Benjamin, Frank, Marco, Marko, Andreas, Robin, Marius, Holger, Michael, David, Jürgen, Phillip, Marcel, Marcell, Sascha, Oliver, Björn, Timur, Peter, Jan, Udo, Dariusz, Lars, Johannes, Fabian, Hendrik, Philip, Uli, Dennis, Max, Sven, Kostja, Dirk... und alle, die ich vergessen haben sollte.</i>Janek Fellienhttp://www.blogger.com/profile/11037083301535227855noreply@blogger.comtag:blogger.com,1999:blog-6438666738561404296.post-74545734987296372922016-07-10T22:51:00.000+02:002016-11-13T23:11:58.303+01:00Oberflächlich betrachtet - IV<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijKQlEgeHv8wWOacytePlcNe-aeaZIPfK9nKw6mNvjDb_S2xX83l_Fis9oDGwFg83cy9hoZdAH5lh6qZ0oD6ZqTUznhyphenhyphenoq2Baz33vmbXKfLXYd74nZIKvbSv8wyXSkZLWt5szQNlwcMfry/s1600/old_car.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijKQlEgeHv8wWOacytePlcNe-aeaZIPfK9nKw6mNvjDb_S2xX83l_Fis9oDGwFg83cy9hoZdAH5lh6qZ0oD6ZqTUznhyphenhyphenoq2Baz33vmbXKfLXYd74nZIKvbSv8wyXSkZLWt5szQNlwcMfry/s1600/old_car.jpg" /></a></div>
<br />
Dieser Teil der Blog Post Serie handelt von den Kleinigkeiten, die mir bei der Benutzung des Surface Book aufgefallen sind. Bisher habe ich versucht diese Kleinigkeiten nicht mit in die vorherigen Teile mit auf zu nehmen, obwohl es mächtig in den Fingern juckte.<br />
<br />
<h4>
Powerfull</h4>
Dann fang ich mal beim Offensichtlichsten an, der Batterie. Voller Vorfreude lud ich das Gerät am ersten Tag mit Hilfe des mitgelieferten Netzteils auf. Soweit so gut. Da ist mir das Folgende noch nicht aufgefallen. Beim zweiten Mal passierte etwas ziemlich Unerwartetes. Das Netzteil zum Book hat ein wirklich cooles Feature. Es ist eine USB Buchse verbaut, über die man ein entsprechendes Gerät, Handy oder ähnliches, mit aufladen kann. Super Idee, weiter so. Aber oh Schreck, wenn man über USB aufläd, wird das Book nicht aufgeladen. So zumindest die Ladeanzeige im Sperrbildschirm. Du meine Güte, wer denkt sich denn so etwas aus?<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-nJaWwVv9CzGQ2a75SbogBeS1a6qADWBKb2EM28Th80RxNDT2-8MoTEq2Qt2ZwKZcKkgyNGD2tKIaOUbVDhgJUkGqCvTVsqtAFrFt4UqK7xFvGeIzAaNEUYMziC-ligyYRq49y7LR8VLx/s1600/batterie.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-nJaWwVv9CzGQ2a75SbogBeS1a6qADWBKb2EM28Th80RxNDT2-8MoTEq2Qt2ZwKZcKkgyNGD2tKIaOUbVDhgJUkGqCvTVsqtAFrFt4UqK7xFvGeIzAaNEUYMziC-ligyYRq49y7LR8VLx/s640/batterie.jpg" width="480" /></a></div>
<br />
Aber Halt, da stimmt doch was nicht. Nach außen sieht es vielleicht so aus, aber tatsächlich ist das Book aufgeladen, nur sieht man das erst, wenn man sich anmeldet und das Icon zur Ladeanzeige in der Taskbar überprüft. Hässlicher kleiner Glitch du.<br />
<br />
<h4>
Powerless</h4>
Da ich schon bei der Batterie bin… Wer zum Henker kommt auf die glorreiche Idee ein mobiles Gerät aus zu liefern, das im vermeintlich ausgeschalteten Zustand mächtig Strom verbraucht, 3% in 30 Minuten? Das ist nicht geil, das ist peinlich.<br />
Nach einiger Zeit stellte sich heraus, dass das Energiemanagement nicht vernünftig eingestellt ist. Man muss den Akkumodus so hingehend ändern, dass man beim Zuklappen des Gerätes in den "Ruhezustand" wechselt. Werksseitig ist "Energie sparen" eingestellt, das noch eine Menge Hintergrundaktivität verursacht. Das sollte unbedingt für den Auslieferungszustand geändert werden.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjrAKXHLcz5zSPFJeP6g-hkvdLsW8USxG4Fm9_C34fVIt5S56nYspGJCtQAF7ddB16IP1K3YBfQcz7shX0DC5IhhyphenhyphenvXdvNZd_Vf7Tfu6ZgRbHjIGOkvPA2OKtY3eGivZypTcbx9IAxI8JQ/s1600/ruhezustand.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjrAKXHLcz5zSPFJeP6g-hkvdLsW8USxG4Fm9_C34fVIt5S56nYspGJCtQAF7ddB16IP1K3YBfQcz7shX0DC5IhhyphenhyphenvXdvNZd_Vf7Tfu6ZgRbHjIGOkvPA2OKtY3eGivZypTcbx9IAxI8JQ/s1600/ruhezustand.jpg" /></a></div>
<br />
<br />
<h4>
*Plock*</h4>
Was auch unbedingt geändert werden muss ist einer meiner Lieblingsfauxpas. Das Touchpad hatte ich in einer der vorherigen Blog Posts schon kurz erwähnt. Es ist für die klassische Bedienung durchaus geeignet - in der Schule würde man sagen "es hat sich stets bemüht". Aber dafür, dass es als das tolle Ding am tollen Ding angepriesen wird, muss ich sagen, ist es ziemlich ernüchternd. Das <a href="https://de.wikipedia.org/wiki/Stick-Slip-Effekt" target="_blank">Stick-Slip-Verhalten</a> kam schon zu Wort, nun weise ich auf den unsäglich hässlichen Klicksound hin. Ich weiß nicht, woran er mich erinnert, etwas gutes ist es auf keinen Fall. Zu hochfrequent und laut. Er macht einen sehr billigen Eindruck und sollte, wie bei Apples neuem Touchpad, abschaltbar sein.<br />
<br />
<h4>
Licht am Ende des Tunnels</h4>
<i>"Mein Gott, ich bin blind. Ich sehe nichts mehr. Alles Schwarz… oder? Nein Moment, ganz da hinten sehe ich noch was. Herrje, hier muss doch…".</i> Ich tappe im Dunkeln. Nichts zu sehen auf dem Display. Dabei habe ich doch nur die Helligkeit einstellen wollen. Im Infocenter auf den kleinen Button durch die Helligkeitsstufen klicken ist keine gute Lösung, wenn eine der Einstellungen fast komplett "Aus" bedeutet. Zum Glück konnte ich das Zimmer soweit abdunkeln, dass man den Button ganz vorsichtig schimmern sehen und in die Normaleinstellung zurück schalten konnte.<br />
Für alles mögliche gibt es Funktionstasten, aber nicht für die Displayhelligkeit. Das ist nicht gut. Inzwischen habe ich eine Lösung im Internet gefunden. Für Win10 gibt es die Short Cuts <b>fn+Entf</b> für "10% heller" und <b>fn+Backspace</b> für "10% dunkler". Sehr nützlich der Tip, denn die automatische Einstellung auf die Umgebungshelligkeit funktioniert nur mittelprächtig.<br />
<br />
<h4>
Kunststoffspaghetti</h4>
Was mich auch ziemlich stört sind Kabel. Im Besonderen die, die dich auf jeden Knick hinweisen, den du mal gemacht hast, die Knäul bilden und an Äste einer Korkenzieherweide erinnern. Bisher haben es nur zwei Hersteller von elektrischen Geräten geschafft ihre Kabel in das Gesamtbild hinein zu designen. Ich rede von OnePlus und Apple. Deren Kabel fassen sich angenehm an und bilden bei normaler Benutzung keine Knicke. Supi, das erwarte ich in 2016 auch von Microsoft. <i>"So ein Quatsch… Kabel sind doch nur Nebensache und gehören, wie der Klick Sound vom Touchpad in die unterste Schublade des Produktdesigners."</i><br />
Keines der Kabel zum Book ist irgendwie schön oder lässt sich hübsch zusammenlegen. Ein gebrauchtes nasses Handtuch über die Wäscheleine gelegt, sieht charmanter und lasziver aus, als diese Kunststoffspaghetti. Schade, wirklich schade, da sollte unbedingt dran gearbeitet werden. Kabel und Zubehör sollten ein angenehmes Gesamtbild zum eigentlichen Produkt erzeugen. Kann doch nicht so schwer sein.<br />
Und wenn ihr gerade dabei seid, die Designabteilung zu entlassen, schickt auch den Typen nach Hause, der sich die Dockingstation auf die Fahne schreibt. Wieso ist das (Peinlich)Kabel auf der linken Seite vom Dock, wo man instinktiv dieses Dock hinter das Book stellen möchte und somit das Kabel von links zurück auf die rechte Seite des Books führen muss? Im Internet findet man kaum Bilder von diesem Konstruktionsfehler. Könnte Absicht sein…<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-tSXtDV5L6IsZwySAtl1_D3EedffreBHYRHu3vGaOwjmCzUCGjv-N0FR-ZY_zjp7oVFOfpaC3z5-Y51tF2rnG1edaCRY12-soeh_Y7KLaxsALbRosBN_DUTUxuS-Rvts4aLWR_CTnBO-v/s1600/kabel.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-tSXtDV5L6IsZwySAtl1_D3EedffreBHYRHu3vGaOwjmCzUCGjv-N0FR-ZY_zjp7oVFOfpaC3z5-Y51tF2rnG1edaCRY12-soeh_Y7KLaxsALbRosBN_DUTUxuS-Rvts4aLWR_CTnBO-v/s1600/kabel.jpg" /></a></div>
<br />
<br />
<h4>
</h4>
<h4>
</h4>
<h4>
</h4>
<h4>
Vom Winde verweht</h4>
Gerade eben tauchte wieder etwas auf. Die schon einmal erwähnte Lüftung, wollte nun doch in den Blog Post rein. Erst sollte das ja nicht passieren, aber wer so sehr nach Aufmerksamkeit brüllt, wird mit ein paar Zeilen belohnt.<br />
Es ist etwas wärmer gerade, gute 25°C. Ich lege das Book kurz weg, da plötzlich ertönt ein bekanntes Geräusch. Bwwwwwwwwwwwwww… Ah, die Lüftung geht an. Na kann man ja mal machen, ich denke mir nichts dabei. Doch dann. irgendwer muss sich einen Scherz erlaubt haben und in mein Book einen kleinen Brummbär eingebaut haben. Haha, lustig. Nein im Ernst, wenn die Lüftung an ist und man hebt das Book kurz hoch, um es dann wieder ab zu legen, dann hört man ein klares Bwwww Bruuuhh. Nochmal Bwwww Bruuuhhh. Oh wie süß. Microsoft hat auch an die Kleinsten von uns gedacht und ein Brummbär Soundeffekt eingebaut. Wäre noch interessant, wie lange der Lüfter das Bruuuhh mitmacht. Irgendwann sind die kleinen Flügelchen abgerieben. Ist das in der Garantie enthalten oder darf man das Book bei eingeschalteter Lüftung nicht bewegen?<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4jkl-zGpEszYnBpThQUswUM8WKfxWJnfYAt3yYRzrRuSdSPDRbfCeWdOBOWWJblA_CCOc82D6Xx5wZhyrigwoh3YxsSXmB7mNAhyphenhyphenU7NCCNskgJ95A4afgmYjrhxsI5cVhKzRhRaBP12Ij/s1600/teddy.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="426" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4jkl-zGpEszYnBpThQUswUM8WKfxWJnfYAt3yYRzrRuSdSPDRbfCeWdOBOWWJblA_CCOc82D6Xx5wZhyrigwoh3YxsSXmB7mNAhyphenhyphenU7NCCNskgJ95A4afgmYjrhxsI5cVhKzRhRaBP12Ij/s640/teddy.jpg" width="640" /></a></div>
<br />
<br />
Falls ihr bei Microsoft noch jemanden braucht, der bereit ist euch echtes Feedback und Hinweise zu geben, ich mache das gerne, damit ihr besser werdet. ;)<br />
<br />
So, nun soll Schluss sein, mit dem Schimpfen. Ihr stellt euch sicherlich schon die Frage, warum ich das hier überhaupt noch mache und warum ich die Kiste nicht schon längst wieder zurück geschickt habe. Ich sags mal so - Strockholmsyndrom oder wie ein paar Kinderaugen alles wieder gut machen können.<br />
<br />
Bis zum nächsten und finalen Teil<br />
Tschö mit Ö<br />
<br />
~janekfJanek Fellienhttp://www.blogger.com/profile/11037083301535227855noreply@blogger.comtag:blogger.com,1999:blog-6438666738561404296.post-68765833016047621102016-06-30T22:43:00.000+02:002016-11-13T23:09:57.626+01:00Oberflächlich betrachtet - III<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbz4kR7ZOr0mLgUD3zoTcszv77akblDcxUbMSKoaNLXM10qvRpAMbKxuSWBU8IgJg-0JUYxSY6rkVZfihHXuPV78xG9I3BTxAtg7KmkPgHItwslYLm0L5MXY2RK8BeLZmss73iJQ41KbV8/s1600/run_small-1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbz4kR7ZOr0mLgUD3zoTcszv77akblDcxUbMSKoaNLXM10qvRpAMbKxuSWBU8IgJg-0JUYxSY6rkVZfihHXuPV78xG9I3BTxAtg7KmkPgHItwslYLm0L5MXY2RK8BeLZmss73iJQ41KbV8/s1600/run_small-1.jpg" /></a></div>
<br />
Was man versprochen hat, soll man bekanntlich auch halten. Die Serie zum Surface Book Review geht weiter. Ging es beim <a href="http://janekf.blogspot.de/2016/06/oberflachlich-betrachtet-i.html" target="_blank">ersten Teil</a> noch um den Bestellprozess, hat der <a href="http://janekf.blogspot.de/2016/06/oberflachlich-betrachtet-ii.html" target="_blank">zweite Teil</a> mehr das verfehlte optische Design und das versöhnende Display im Fokus.<br />
Als ich mit der Serie anfing, dachte ich noch, dass es nicht mehr als zwei Blog Posts werden. Falsch gedacht, es gibt mehr zu berichten als angenommen. Täglich kommen neue Dinge zum Vorschein, die wie der "kleine Hunger" um die Ecke schauen und freundlich winken.<br />
<br />
<i>"Huhu, da ist noch was, schreib auch über mich."</i><br />
<br />
Gerade eben erst habe ich bemerkt, dass die Lüfter auch mal arbeiten möchten. Ganz ungeniert geht das Gebläse an und fiept frisch fromm fröhlich frei sein Liedchen. <i>"DumdiehhiehhDumDiieehhDei"</i> Was soll das denn? Da war keinerlei Last auf dem Gerät. Bist du sauer, dass ich schon lange keinen Lüfter mehr gehört habe, weil ich Windows nicht gestartet habe? Vollpfosten...<br />
<br />
Zur Sache...<br />
<br />
Wie im vorherigen Blog Post versprochen, geht es heute um den Grund, warum ich nicht(!) auf dem Surface Book geschrieben habe.<br />
Der ein oder andere kennt mich und kennt auch meine Aversion gegen Tastaturen, die einfach nur billg wirken. Vor vielen Jahren fing das an, als ich nach einer endlos langen Serie von ziemlich menschen unwürdigen Tastaturen die erste Laptoptatstatur vom Sony Vaio in den Händen hielt. Boah, was für eine Schmeichelei an den Fingern. Ja und seither habe ich so meine Probleme, wenn die Tasten, die das Leben bedeuten, einem das Gefühl geben, man würde auf Kronkorken herumtrommeln. Da lob ich mir die hochwertigen Tastaturen, die einem das Schreiben angenehmer machen. Ja klar, das ist alles sehr subjektiv, aber wer möchte mir verbieten zu sagen, dass ich die Lenovo Tatstaturen als einen Graus wahr nehme - keiner - Hehe.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJRA6CmJye5q-ZyFqc9jkYeblg4JyQHeULFqZPlcr7Rvly0uNLtPs9tJUydUcRokaw3ZoAi442E9yVuD7Bao-gEgNHF-tpZCvGkamwKGAkwOLKddBCjsl1-I-D1NN536Yy6QJFZhyphenhyphenvgC-W/s1600/SurfaceBookKeyboard1.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJRA6CmJye5q-ZyFqc9jkYeblg4JyQHeULFqZPlcr7Rvly0uNLtPs9tJUydUcRokaw3ZoAi442E9yVuD7Bao-gEgNHF-tpZCvGkamwKGAkwOLKddBCjsl1-I-D1NN536Yy6QJFZhyphenhyphenvgC-W/s1600/SurfaceBookKeyboard1.jpg" /></a></div>
<br />
<br />
Und wie ist das jetzt mit dem Surface Book. Naja, wie man's nimmt. Wer auf einfach steht, der ist gut beraten. Die Tasten fassen sich zwar genau so nett (die kleine Schwester von Sch....) wie das Gehäuse an, sie tippen sich ziemlich gut und auch das Geräusch ist halbwegs in Ordnung. In Summe könnte man meinen, es ist eine Tschibo Tastatur, nicht ganz billig aber auch nicht die Oberklasse. Eben was für den typischen Manager, der sie nicht oft benutzt, aber damit schmücken möchte.<br />
<br />
Ihr hört schon, irgendwas kommt doch noch. Richtig, das super coole Feature, was einigen Herstellern noch fehlt und was andere Hersteller einfach um Längen besser machen. Die Beleuchtung der eizelnen Tasten. Wow, was für ein Reinfall - sorry Leute, da hat offenbar der Kollege aus der Designabteilung gedacht: "Hey noch ein bisschen mehr Grau könnte dem Gerät wirklich gut tun."<br />
Ihr glaubt es mir nicht? Hier ein Bild, welches unter völlg normalen Bedingungen aufgenommen wurde, nichts geschönt, nichts retuschiert.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhn19cob4arz9d-KeUPMhsZxQfcg7fgiW8HG7btQ6G4YQltrCNN5FWsxObKl5j68QDBO6jtYEN80UhOZe3WZ6kjr5sFE35pVn0UAQQ1bn8BHSZ5zEjQzin7jqbDIs_b9ANrBdAhdKhI-j8S/s1600/SurfaceBookKeyboard2.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhn19cob4arz9d-KeUPMhsZxQfcg7fgiW8HG7btQ6G4YQltrCNN5FWsxObKl5j68QDBO6jtYEN80UhOZe3WZ6kjr5sFE35pVn0UAQQ1bn8BHSZ5zEjQzin7jqbDIs_b9ANrBdAhdKhI-j8S/s1600/SurfaceBookKeyboard2.jpg" /></a></div>
<br />
<br />
Einige Kollegen können ja blind schreiben, ich nicht und ich kann vor allem dann nicht schreiben, wenn die Tasten quasi ausgeblendet sind. Das ist mein Problem, aber mit Sicherheit auch das anderer User.<br />
<br />
Was höre ich da... "Dann schau doch anders rauf, in einem anderen Winkel." Ja geile Idee, dann sollte man das Display aber etwas weiter nach hinten klappen können, was aus Gründen der Stabilität und des Schwerpunktes nicht geht - wogegen ich übrigens nichts habe.<br />
<br />
Um der Sache ein bisschen entgegen zu kommen möchte ich positiv erwähnen, dass in einer angemessenen Dunkelheit die Tasten mit Beleuchtung recht gut erkennbar sind, leider halt nur dann. Tagsüber verschwindet die Beschriftung und das ist nicht lustig. Gönnt dem Gerät ein Tageslichtsensor, oder nutzt den schon eingebauten, um die Helligkeit der Beleuchtung am Tage zu regeln, just a hint.<br />
<br />
Ach und noch ein kleiner Hinweis... Auch wenn es am Akku lutschten mag, lasst die Beleuchtung an, wenn sie eingeschaltet ist. Dieses An und Aus nervt schlichtweg.<br />
<br />
Noch etwas Positives heute? Ja, etwas wirklich Kleines. Das Trackpad tut seine Arbeit recht angenehm. Es spricht schnell an und es fehlen lauter hübsche Gesten. Das Scrollen ist von Applikation zu Applikation anders, meistens flüssig ab und zu viel zu ungenau. (*"Du wolltest doch was Positives schreiben" - "Hab ich doch, das Trackpad funktioniert besser als erwartet"*). Auch die Oberfläche des Trackpads ist suboptimal. Es fehlt ihr an Glätte. Wenn man etwas anklickt, gedrückt hält und dann verschieben möchte schlägt der <a href="https://de.wikipedia.org/wiki/Stick-Slip-Effekt" target="_blank">Stick-Slip-Effekt</a> voll zu. Und dann klingt das Verschieben, als hätte man die Flatulenz.<br />
Hihi... ich stell mir das gerade im Meeting vor. Lauter seriöse Herren, jeder hat ein hübsches Device vor sich zu stehen und der Kollege mit dem Surface Book möchte etwas präsentieren. Puups... peinliche Blicke... weiter im Text... Kicher.<br />
<br />
Keine Angst, am MacBook passiert das auch manchmal.<br />
<br />
Puups... grunz<br />
<br />
~janekf<br />
<br />
<br />
<br />Janek Fellienhttp://www.blogger.com/profile/11037083301535227855noreply@blogger.comtag:blogger.com,1999:blog-6438666738561404296.post-67459535837397263552016-06-27T22:37:00.000+02:002016-11-13T23:05:17.962+01:00Oberflächlich betrachtet - IINachdem ich im <a href="http://janekf.blogspot.de/2016/06/oberflachlich-betrachtet-i.html" target="_blank">letzten Post</a> über das Abenteuer geschrieben habe, wie das Surface Book in meinen Besitz geraten ist, möchte ich nun damit beginnen die ersten Eindrücke zu beschreiben. Ja und wie schon versprochen, es wird kein Blatt vor den Mund genommen... Das ist ernst gemeint.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUDjnUqk1160sJtK-PYhNS1a77AjMqZD2v5OR6fYh8s7hQRjLUN6cdSHQO9E_BjW8wzytZaB_0KQMkaLz2pIBUIlbUAvYPrG1Ko_xecYdkExJG8PeLT7MiK9NCb2_n_eLEvUGyCd5ThirZ/s1600/SurfaceBook-1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUDjnUqk1160sJtK-PYhNS1a77AjMqZD2v5OR6fYh8s7hQRjLUN6cdSHQO9E_BjW8wzytZaB_0KQMkaLz2pIBUIlbUAvYPrG1Ko_xecYdkExJG8PeLT7MiK9NCb2_n_eLEvUGyCd5ThirZ/s1600/SurfaceBook-1.jpg" /></a></div>
<br />
<br />
<br />
Ok, wie es in einem Review, einer Rezension oder sonst was für ein Art von Beschreibung üblich scheint, sollte man mit einer Liste der Themen, die man besprechen möchte, beginnen.<br />
<br />
1. Erster Eindruck<br />
2. Zweiter Eindruck<br />
3. Dritter Eindruck<br />
4. alle anderen Eindrücke<br />
<br />
So, das ist erledigt. Ich denke, die Agenda ist nüchtern genug, so nüchtern, wie mein erster Eindruck.<br />
Gott... Liebe Leute von Microsoft, habt ihr euch im Vorfeld erkundigt, welches Grau das langweiligste ist, was man nehmen kann?<br />
Aus Erfahrung kann ich sagen, dass es interessantere Grautöne gibt, als diesen. Auf den ersten Blick wirkt das Gehäuse wie reinster billiger Kunststoff, doch dann kommt die Überraschung schlechthin. Dann, wenn man die Hand irgendwo auf das Gehäuse legt, wird man kühl und berechnend begrüßt, das mag ich mehr, als das, was mir das Auge versprochen hat. Ein wenig wie 560er Sandpapier fühlt es sich an. Aus meiner Sicht hat man hier alles an Design rein getan, was die (räusper) Designabteilung leisten konnte.<br />
<br />
Nun gut, eine zweite Chance - von noch vielen - gebe ich dir mein gutes Stück. Fangen wir damit an, es auf zu klappen. Bitte... nur ein mal... ganz vorsichtig. Ach ja klar, eine rutschfreie Unterlage wird gebraucht, damit sich das Display irgendwie von der Tastatur löst. Ja, sie haben sich aber auch wirklich sehr lieb und wollen für immer zu sammen bleiben. Was ich sagen möchte, das Display und die Tastatur lassen sich nicht wirklich leicht lösen, jedenfalls nicht, wenn der Tisch unter dem Gerät recht glatt ist, wie ein Holz- oder Bürotisch. Um an sein Ziel zu kommen braucht es also entweder einen anderen Griff, einen Gegenhalter oder eine rutschfeste Unterlage. Eines von dem hat man garantiert bei der Hand, sodass dem Glück nichts mehr im Wege steht.<br />
<br />
<i>BTW: ich habe mich für einen anderen Griff entschieden, nachdem ich feststellen durfte, dass an der Stelle, wo man instinktiv das Gerät öffen möchte, der Ein/Ausschalter bzw. der Lautstärkeregler ist. (leises Kopfschütteln begleitet diesen Absatz)</i><br />
<br />
Wow... Meine Güte... Das ist mal ein Display. Dagegen - ok ich übertreibe jetzt ein bisschen - kommt einem das Retina Display vom MacBook Pro 15" wie das Bild einer VHS Kasette vor. Nein ehrlich, das ist das billianteste und klarste Bild, das ich seit Monaten gesehen habe. Der eingebaute Augenfehler, den ich seit Jahren mit mir herum schleppe kommt wieder vollstens (psst, ihr Gramatik Samurais) zur Geltung. Ich sehe wieder jeden Schatten hin und her flimmern, Wahnsinn.<br />
Technische Details, bzgl. der Auflösung könnt ihr im Internet nachschlagen oder in den anderen Tests nachlesen, dafür ist diese Blog Post Reihe nicht gedacht.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpmhVOuWykVvYK-k896pxxUE2pgT4Rra512EBmS_YVLU2uDzsnUVBduabiS3VxH8-aeDDvfzO9BDI4JAWYrjQVY4YXl7j5v4Fc6D-JAnC9rVMYTfY6urKYOTodFP8RbCoRwP2DQsoU3X6d/s1600/SurfaceBookDisplay.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpmhVOuWykVvYK-k896pxxUE2pgT4Rra512EBmS_YVLU2uDzsnUVBduabiS3VxH8-aeDDvfzO9BDI4JAWYrjQVY4YXl7j5v4Fc6D-JAnC9rVMYTfY6urKYOTodFP8RbCoRwP2DQsoU3X6d/s1600/SurfaceBookDisplay.jpg" /></a></div>
<br />
<br />
Schon beim Hochladen des Bildes, musste ich Kichern. Die Kamera, mit der ich das Bild aufgenommen habe, hat nicht einmal ansatzweise eine so gute Qualität, um das Display ins rechte Licht setzten zu können. Und trotzdem, es musste einfach sein.<br />
Ich bin so sehr beeindruckt, dass ich den Blick kaum abwenden möchte und dennoch schreibe ich diesen Post am anderen Rechner - aus Gründen. Gründen, die ich im nächten Blog Post darstellen werde.<br />
<br />
Gut gut, ein Hinweis. Der Grund liegt dem Display gegenüber.<br />
<br />
---<br />
Mir fällt gerade ein. Falls jemand eine Unboxing Beschreibung haben möchte. Ich fasse mich kurz. Langweilig und umständlich. Der Karton ist hochwertig, alles passt zusammen aber das war's auch schon. Das Gerät lässt sich nicht smooth aus der Verpackung heben. Wenn man mit dem Fingernagel (!) an der dafür vorgesehenen Stelle pult, öffnet sich das Gerät mühelos, anstatt dass es aus dem Karton kommt. Halt mal, vielleicht sollte man den Karton immer dabei haben zum... Ach, lassen wir das.<br />
<br />
~janekf<br />
<br />
<br />
<br />Janek Fellienhttp://www.blogger.com/profile/11037083301535227855noreply@blogger.comtag:blogger.com,1999:blog-6438666738561404296.post-88659720567709431662016-06-25T22:33:00.000+02:002016-11-13T23:06:07.597+01:00Oberflächlich betrachtet - IEin Blog Post über den Weg hin zum und mit dem <a href="https://www.microsoft.com/surface/de-de/devices/surface-book" target="_blank">Surface Book von Microsoft</a>.<br />
<br />
Ich hätte es im Prinzip erwarten können. Bei meinem bisherigen Glück mit Onlinebestellungen ist der Weg, hin zu dem Moment, da ich die Ware in den Händen halten kann, ein sehr steinger. Genau wie sich die Deutsche Fußballmannschaft in 2014 nach vorn kämpfen musste, war es keine Selbstverständlichkeit das Gerät nun auf den Beinen liegen zu haben, um diesen Post zu schreiben. Aber fangen wir ganz vorn an.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgg0sl1yPXZQzgrJHTIGbHX-zJsrEcjwdsAxZ0P1nT1HVPTfG1S5sKHppAzjlI0GGOqX3UvsI6tU3B9WCkusqEEHvpeoJSz-ChYEIjZbpBql7UFsAStWzE63kvZlk2CROXAw_HJ8rW9K6Yk/s1600/da_isses-1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgg0sl1yPXZQzgrJHTIGbHX-zJsrEcjwdsAxZ0P1nT1HVPTfG1S5sKHppAzjlI0GGOqX3UvsI6tU3B9WCkusqEEHvpeoJSz-ChYEIjZbpBql7UFsAStWzE63kvZlk2CROXAw_HJ8rW9K6Yk/s1600/da_isses-1.jpg" /></a></div>
<br />
<br />
<h3>
Insiderprogramm</h3>
Eines Tages erreichte mich eine Mail, die mir versprach, dass die Teilnehmer des <a href="https://insider.windows.com/" target="_blank">Microsoft Insiderprogramms</a> eine Sonderkondition zum Kauf des Surface Book erhalten - nett. Und dazu das Dock, welches man für den Anschluss weiterer Geräte extrem gut gebrauchen kann, kostenfrei oben drauf. Coole Aktion, dachte ich. Ein kurzer Blick in die Twitter Timeline zeigte mir, dass auch andere diese Mail erhalten hatten und nun darüber diskutierten, ob man zuschlagen sollte oder eben nicht. Ich sags mal so... es gab mehr Leute dagagen, als dafür.<br />
<br />
Hey, lass ich mich durch die Meinung anderer beeinflussen - ja klar. Also selber eine Meinung bilden und einen Blick in den Store riskieren.<br />
<br />
Pfff.... Volle Ausbaustufe... hossa. Das ist definitv zu viel für ein Gerät, dass erst noch seine Berechtigung erkämpfen muss. Und da ich seit einiger Zeit mit einem MacBook Pro rum mache, wurde mir die Entscheidung noch schwerer gemacht.<br />
<br />
Auf der anderen Seite, wie soll ein solcher Hybrid jemals eine Chance bekommen, wenn man immer nur abwartet. Also... eine Ausbausstufe weniger ausgewählt, Rabattcode eigegeben und die Bestellung ausgelöst.<br />
<br />
<b>Wenn ich einen Screenshot gemacht hätte, ihr könntet jetzt sehen, dass das ein Unheil seinen Lauf nehmen wird.</b><br />
<br />
Statt einer Bestätigung, dass die Bestellung erfolgreich war, meldete sich die Webseite: "Ähm... keine Ahnung, was eben passiert ist, aber Bestellung pfutsch. Mach mal noch mal."<br />
<br />
<i>Ich so:</i> "Ok, kein Problem, mach ich einfach nochmal."<br />
<br />
<i>Webseite so:</i> "Ähm, nee du, irgendwas ist nicht so richtig gut mit deiner Kreditkarte. Mach mal nochmal"<br />
<br />
<i>Ich so:</i> (rolleyes) "Na gut... jetzt mit Paypal."<br />
<br />
<i>Webseite so:</i> "Super... alles hat geklappt. In 2-4 Tagen bist du Besitzer eines Surface Book, i7, 8GB RAM, 256 GB HDD"<br />
<br />
<i>Ich so:</i> "Supi, und wenns nicht gefällt, kann ich's ja zurück schicken. :-)"<br />
<br />
Nach besagten vier Tagen wurde ich sehr unruhig, denn weder eine Bestätigungsmail noch eine Versandbenachrichtigung oder sonst irgendetwas kam bei mir an. Also ran an den Microsoft Support, im Chat. (Später habe ich noch das halbe Team im Support per Telefon kennen gelernt.)<br />
Man sagte mir, dass es ein Problem bei der Bestellung gab und alles noch im grünen Bereich ist. Ich brauche mir keine Sorgen machen, das Geld wird erst bei Versandbestätigung abgebucht. Ha, falsch gedacht. Noch im selben Augenblick schaue ich auf's Konto und siehe da, die Buchung ist erfolgt, nur halt kein Versand. Das teile ich dem Kollegen auf der anderen Seite mit. Mit dem Effekt... Chat beendet. <b>Einfach so.</b><br />
<br />
Na gut, ich möchte euch wirklich alles ersparen, was dann kam... etliche Minuten am Telefon und etliche Ausreden, warum es denn gerade jetzt nicht klappt. Hey Leute, dachte ich mir, ich wende mich mal direkt an die Kollegen in der Microsoft Community. Eine kurze Nachricht an Jan Schenk und die Eskalation nahm ihren Lauf. Er hat sich rührend für mich eingesetzt - ein dickes Dankeschön nochmal an dieser Stelle.<br />
<br />
Es hat insgesamt gute drei Wochen gebraucht, bis die Finanzabteilung bei Microsoft die Buchung wieder frei gegeben hat. Da muss definitiv dran gearbeitet werden, denn meine Kohle lag schon lange auf eurem Konto.<br />
Ich hatte inzwischen schon eine private Supportmitarbeiterin, die sich herzlichst um mich kümmerte, Statusberichte lieferte, zu jeder Tages- und Nachtzeit. Beeindruckend, auch ein Dank an Olivia :)<br />
<br />
<h3>
Da isses</h3>
Nach dieser Odyssee konnte ich das Gerät endlich in der Hand halten. Fast.<br />
Ganz so einfach war es dann doch nicht. Der Lieferprozess wurde von meiner Olivia dankenswerter weise nach Nürnberg umgelenkt, weil ich dort zur <a href="http://www.developer-week.de/" target="_blank">DWX</a> war. Eigentlich sollte das Gerät am Montag da sein, aber was soll ich sagen. Mittwoch ist auch irgendwie Ok, im Rahmen der Vergangenheit. Man konnte nicht früher - angeblich irgend ein Code; Zeitverschiebung; Sonnenflecken - ach was weiß ich.<br />
<br />
Aus der Sicht des Surface spielte sich dann in etwa folgende Szene ab.<br />
<i><br /></i>
<i>Im Hotel angekommen hat man mich an einen der Mitarbeiter übergeben. Leider hat offenbar Microsoft vergessen den Namen meines Käufers auf den Lieferschein zu drucken, was im Hotel zunächst für Verwirrung sorgte, aber ein beherzter Mitarbeiter - nennen wir ihn Hotelmanager - fand das Paket sehr interessant und packte schon mal aus. "Boah, was zur Hölle ist das denn?" schrie er "gleich mal ausprobieren." Das war so gegen 10 Uhr. Zu seinem Pech wurde er dann doch wieder vom Tagesgeschäft eingeholt, denn weiter als bis zum Einrichten des WLan kam er nicht. Nun stand ich hier so rum, ungenutzt und etwas deplatziert.</i><br />
<i>Nach gut einer Stunde tat sich was. Einer der Haustechniker kam rein und packte mich recht lieblos wieder zusammen. Irgend etwas war geschehen. Im Hintergrund hörte ich den Manager schnaufen und auch der Techniker war nicht sonderlich erbaut.</i><br />
<i>Zurück im dunklen Karton, wurde ich an jemand anderen übergeben. Offenbar handelte es sich hier um jemanden, der mich erwartet hatte, denn ich hörte aus dem Karton heraus: "da isses, cool".</i><br />
<br />
Liebe Leser, ich kann euch sagen, dass so ein Gesicht eines Herren ziemlich bedeppert aussieht, wenn man ihm sein unerwartetes Spielzeug einfach so weg nimmt.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHHPOI90oSpmnR7ugbybGQu8Hvb0E4_gem6cRsG-nu-R_P1XicavYIxrsCNy2maldF3POxXI1L-w7qF_0keCkhXZ1_HUuagm6v06Yu-ofgtjFhFfcSEFtqDFPyF7yztC4F5L-34hWOweMZ/s1600/use_it.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHHPOI90oSpmnR7ugbybGQu8Hvb0E4_gem6cRsG-nu-R_P1XicavYIxrsCNy2maldF3POxXI1L-w7qF_0keCkhXZ1_HUuagm6v06Yu-ofgtjFhFfcSEFtqDFPyF7yztC4F5L-34hWOweMZ/s1600/use_it.jpg" /></a></div>
<br />
<br />
So viel dazu erst einmal. Im <a href="http://janekf.blogspot.de/2016/06/oberflachlich-betrachtet-ii.html" target="_blank">nächsten Blog Post</a> gehe ich auf die ersten Eindrücke und Erfahrungen ein. Seid euch gewiss, es wird kein Blatt vor den Mund genommen.<br />
<br />
~janekfJanek Fellienhttp://www.blogger.com/profile/11037083301535227855noreply@blogger.comtag:blogger.com,1999:blog-6438666738561404296.post-86372490559885059852016-03-13T22:23:00.000+01:002016-11-13T23:04:12.750+01:00Das erste Mal ein Webinar...... und der Demo Gott hatte kein Erbarmen. Doch von Anfang an.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMn4Abu1WUEzvVAk0Hh2Jiw2u7OfGBcAkyoBjcprTDHlgTiFwkMQwo4op3S3z6SZ0Jj8RMH8uulndT3E-6hqpin-rPT_ApQjemyUKXM6pUtAYmpgUw7ebZXEQZKpQDlsda0tzQVZrTTqMQ/s1600/The-Adventure-Begins.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMn4Abu1WUEzvVAk0Hh2Jiw2u7OfGBcAkyoBjcprTDHlgTiFwkMQwo4op3S3z6SZ0Jj8RMH8uulndT3E-6hqpin-rPT_ApQjemyUKXM6pUtAYmpgUw7ebZXEQZKpQDlsda0tzQVZrTTqMQ/s1600/The-Adventure-Begins.jpg" /></a></div>
<br />
Am 23. Februar gab ich mein aller erstes Webinar. Ein ziemlich befremdliches Gefühl, da man quasi ins Leere hinen redet. Natürlich dürfen die Zuhörer Kommentare abgeben oder Fragen stellen, aber es ist ein sehr asynchroner Vorgang, bei dem auch schon mal der Kontext verloren gehen kann. Nun gut... ich hatte mich so gut es ging eingerichtet und die Demos noch einmal durchgespielt. Die Kollegen der <a href="http://developer-media.de/" target="_blank">developer-media</a> checkten nochmals die Verbindung und den Ton. Alles OK, es kann losgehen.<br />
<br />
<h4>
17:00 Uhr "Good Morning Germany"</h4>
Geduldig hatten die Teilnehmer gewartet und nach einer kleinen Vorstellungsrunde ging es auch schon los. Folien zeigen, kurz erklären, wo man her kommt und was heute präsentiert wird.<br />
Es ging um die Anbindung der Multimodel Datenbank <a href="http://orientdb.com/" target="_blank">OrientDB</a> an eine CQRS Applikation. Mit zwei drei Folien war alles erklärt, auch warum ich mich für OrientDB entschieden hatte. Der praktische Teil kann beginnen.<br />
<br />
<h4>
17:23 Uhr "Let the show begin"</h4>
Um ein besseres Verständnis her zu stellen entschied ich mich für eine strikte Trennung der Entwicklungen, bzw. Applikationen. Die CQRS Applikation wurde in Windows auf einer virtuellen Maschine präsentiert und die Datenbank auf meinem \*ux Hostsystem.<br />
Der Einstieg war einfach, mittels diverser Tags im git Repository sollten die Entwicklungsschritte schnell sichtbar gemacht werden. Diese Technik finde ich durchaus praktisch und verwende es schon seit einger Zeit.<br />
Bei Schritt 3 von 5 brach das tolle System zusammen und ich erhielt einige Hinweise, wie man das wieder richten könnte - vielen Dank an dieser Stelle noch einmal.<br />
<br />
<h4>
17:52 Uhr "Houston, wir ..."</h4>
Nach etlichen Versuchen die Demo mit Speichern von Events und dem Anlegen von Datenbanken über den Webclient, musste der Teil abgebrochen werden. Wirklich schade, weil es ein schön rundes Paket war. Nun gut, der Demo Gott wollte das nicht, also war da auch nichts zu machen. Meinen Teilnehmer versprach ich, mir die Sache mal an zu schauen und siehe da... Ich weiß nun warum das alles nicht so klappte.<br />
<br />
<h4>
Alice im Wunderland</h4>
Bei einem der `git` Kommandos muss ich versehentlich den Ordner mit dem Datenbank Server gelöscht haben. Jedenfalls waren die Datein spurlos verschwunden. Was mich dabei am meisten wundert ist, dass ich gar kein Tracking des Ordners im <span style="font-family: Courier New, Courier, monospace;">git</span> Repo eingestellt hatte. Und trotzdem ist der Ordner einfach leer - plötzlich. Darauf wäre ich innerhalb des Webinares nicht gekommen, dort mal nach zu schauen, weil ich davon ausgehe, dass untracked Files nicht einfach so gelöscht werden.<br />
Als ich am späten Abend die Demo wieder ausprobierte - man lässt ja so etwas nicht auf sich sitzen - klappte alles wieder wunderbar.<br />
<br />
<h4>
The Show must go on</h4>
Was lerne ich für die Zukunft daraus? Zum einen darf man sich nicht auf den Demo Gott verlassen, das ist einfach dumm. Zum anderen werde ich nicht noch einmal mit getrennten Systemen arbeiten. Es fühlt sich irgendwie verwirrend an, wenn man zwischen den VMs hin und her schaltet. Außerdem werde ich die Technik mit dem Repository verfeinern. Am besten, indem ich mir den Inhalt eines Repositories per Datei Manager anzeigen lasse, wärend ich die `git` Kommandos abschicke.<br />
<br />
Im geplanten <a href="http://smart-data-developer-conference.de/cqrs-und-multi-model-db-ein-herz-und-eine-seele/" target="_blank">Workshop zur Smart Data Konferenz</a> werden diese Probleme mit Sicherheit nicht mehr auftreten. Dazu bin ich nun zu gut vorbereitet. ;-)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKBtRXqnW_eDKV3XjeZUHhN3g7_tP8QgSLNBhnyNGgWtRKXGYT3F3-X6hYTYegpxBSUvfQDWXHiCKEv1VKBxmtE4jNsGJS9tFXpZxIa-m9KNKIKQclYJnymi_9tpaIDLPPSjThqNoHH6YF/s1600/geschenk.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="423" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKBtRXqnW_eDKV3XjeZUHhN3g7_tP8QgSLNBhnyNGgWtRKXGYT3F3-X6hYTYegpxBSUvfQDWXHiCKEv1VKBxmtE4jNsGJS9tFXpZxIa-m9KNKIKQclYJnymi_9tpaIDLPPSjThqNoHH6YF/s640/geschenk.jpg" width="640" /></a></div>
<br />
<br />
Für die jenigen, die sich dafür interessieren, was in dem Webinar gezeigt wurde, gibt es einen <a href="https://shop.dotnetpro.de/shop.php?formular_id=44&step=produkt&id=963&company_id=130&objekt_id=15&kat_id=76&mit_warenkorb=1&eabo2_webform=lmia0nsloud3ujc3hhsii7sh4n7hlbio" target="_blank">Mitschnitt</a> bei der developer-media zu erwerben. Und die dazugehörigen Folien kann man <a href="https://github.com/jfellien/smart-data.webinar/blob/master/doc/CQRS%20Multimodel%20Webinar%20Folien.pdf" target="_blank">hier herunterladen</a>.<br />
<br />
Auf ein nächstes Mal, ich freue mich schon darauf.<br />
<br />
~janekf<br />
<div>
<br /></div>
Janek Fellienhttp://www.blogger.com/profile/11037083301535227855noreply@blogger.comtag:blogger.com,1999:blog-6438666738561404296.post-59255555580182055962016-02-15T22:14:00.000+01:002016-11-13T23:07:24.810+01:00Ich bin Speaker<div class="separator" style="clear: both; text-align: center;">
<a href="http://smart-data-developer-conference.de/wp-content/uploads/sites/10/2016/02/SMARTDATA_Speaker.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://smart-data-developer-conference.de/wp-content/uploads/sites/10/2016/02/SMARTDATA_Speaker.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
<br />
Es ist mir ein besonderes Vergnügen mitteilen zu können, dass ich als Sprecher auf der diesjährigen <a href="http://smart-data-developer-conference.de/" target="_blank">Smart Data</a> Konferenz dabei bin. Und nicht nur das, ich werde sogar einen Workshop geben, bei dem es darum geht das <a href="https://de.wikipedia.org/wiki/Command-Query-Responsibility-Segregation" target="_blank">CQRS Konzept</a> zusammen mit der Multi-Model-Datenbank <a href="http://orientdb.com/" target="_blank">OrientDB</a> vor zu stellen.<br />
<br />
Im Grunde ist das schon fast ein Zufall, denn eigentlich hatte ich mit dem Thema Datenbanken abgeschlossen. Sie gibt es und damit fertig. Doch in einer unruhigen Winternacht, stolperte ich mehr durch Zufall über die Graphen Datenbank <a href="http://neo4j.com/" target="_blank">Neo4j</a>. Ein interessantes Stück Software, mit dem man wirklich eine Menge machen kann. Da mir allerdings ein Platzhirsch erst dann imponiert, wenn er sich mit anderen messen kann, suchte ich gleich nach einer Alternativen und stieß auf OrientDB. Hier fiel sofort auf, dass etwas anders ist. Sie zeichnet sich darin aus, zwei unterschiedliche Datenbankmodelle an zu bieten. Zum einen Graphen, wie Neo4j, und zum anderen Documents, wie MongoDB oder RavebDB. Eine sehr interessante Kombination, gerade dann, wenn man bedenkt, dass das CQRS Konzept mit mehreren Persistenzen arbeitet.<br />
<br />
Ja und darüber werde ich auf der Smart Data reden. Wer sich schon im Vorfeld ein Bild davon machen möchte, am <b>23.2.</b> gebe ich ein <a href="http://developer-media.de/?course=cqrs-und-multi-model-db" target="_blank">Webinar</a> hier zu.<br />
<br />
Also, man sieht sich, im Netz oder auf der Smart Data.<br />
<br />
Ach... ein kleines Schmankerl habe ich noch. Ich kann eine Freikarte für den 18.4. verlosen, wer zuerst kommt, malt zuerst. Einfach melden unter Twitter bei <a href="https://twitter.com/janekf" target="_blank">@janekf</a><br />
<br />
Viel GlückJanek Fellienhttp://www.blogger.com/profile/11037083301535227855noreply@blogger.comtag:blogger.com,1999:blog-6438666738561404296.post-21943069351396226922015-10-09T22:08:00.000+02:002016-11-13T23:04:12.730+01:00Naturgewalten<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheOmWL9SgFfDQxa-pbBdOwCUsI5DCPT1f1WI5K89270sBaXYkyYOBAuZeo0z3E1ww1zCYk71NxNdVXmvyDCJchixdZBgWUoPGYhyphenhyphenXDtLcc2O3o92krZzLqT1ivgLei1BHwsA6U7gGdK6OE/s1600/Storm.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheOmWL9SgFfDQxa-pbBdOwCUsI5DCPT1f1WI5K89270sBaXYkyYOBAuZeo0z3E1ww1zCYk71NxNdVXmvyDCJchixdZBgWUoPGYhyphenhyphenXDtLcc2O3o92krZzLqT1ivgLei1BHwsA6U7gGdK6OE/s1600/Storm.jpg" /></a></div>
<br />
Nur noch eine Woche, sieben Tage, einhundertachtundsechzig Stunden und die Mittagspause am Workshoptag des <a href="https://devopenspace.de/" target="_blank">Developer Open Space</a> ist vorüber. Bis dahin werden meine Teilnehmer und ich die ersten Erfahrungen in <a href="http://ziobrando.blogspot.de/2013/11/introducing-event-storming.html" target="_blank">Event Storming</a> geteilt haben. Vielleicht sogar schon eine der Wände mit Stickies zugepappt und mit <a href="http://www.gesundheit.de/wissen/haetten-sie-es-gewusst/ernaehrung/suppenkoma" target="_blank">Suppenkoma</a> eine Auswertung gemacht haben.<br />
<br />
Ich freue mich schon auf die nächste Woche. Zwei Konferenzen, die unterschiedlicher nicht sein können, aber viel Spaß versprechen. Die erste, die <a href="http://adc.ms/15/default" target="_blank">ADC 2015</a> in Mannheim, gehört eher zu den Klassikern. Eine Konferenz, bei der es Vorträge gibt und viele interessierte Entwickler zusammen kommen, um über die neuesten Entwicklungen zu diskutieren. Ich bin das erste Mal dabei und daher besonders gespannt, wie es wird. Hier werde ich als Premiere auf einer Konferenz mein CQRS Framework <a href="https://github.com/jfellien/fluent-cqrs" target="_blank">"fluent-CQRS"</a> vorstellen - dass es jemals soweit kommen würde, hätte ich nie gedacht, aber wie wir alle wissen: <i>"IT Wege sind unergründlich"</i>.<br />
<br />
Tja und die zweite der Konferenzen ist mir ja schon richtig ans Herz gewachsen. Der <a href="https://devopenspace.de/" target="_blank">Developer Open Space</a> in Leipzig jährt sich für mich - ach herrje - zum fünften Mal. Ein Jubiläum, ein Grund zum Feiern.<br />
Hier in Leipzig fing so einiges an, hier lernte ich die Community richtig kennen, neue Freunde und super Kollegen. Völlig neue Sichtweisen eröffneten sich mir und auch unfassbar gute Ideen haben wir gewälzt. Dafür an dieser Stelle ein großes <b>Danke</b> an euch alle.<br />
<br />
Nun gut, dieser Developer Open Space scheint wiedermal einige Rekorde zu brechen. Mehr Workshops, mehr Anmeldungen, mehr Community, das wird super. Ich, wie gesagt, werde einen Event Storming Workshop geben, aber eigentlich wäre ich noch viel lieber zum <a href="http://neo4j.com/" target="_blank">Neo4j</a> Workshop vom <a href="https://twitter.com/mesirii" target="_blank">Michael Hunger</a> gegangen. Naja, was tut man nicht alles für seine Freunde :)<br />
<br />
Wenn dann der Freitag vorbei ist, geht's eigentlich erst richtig los. Diese Konferenz bemächtigt sich eines Konzeptes, dem Open Space, das recht ungewöhnlich für Entwicklerkonferenzen ist. Ja gut, es gibt immer mehr, die sich diesem Konzept nähern, aber tatsächlich habe ich es hier kennen und schätzen gelernt. Was steckt dahinter? Die Teilnehmer der Konferenz erstellen die Tagesagenda erst direkt vor den Sessions. Damit erreicht man, dass nur Themen angesprochen werden, die die Teilnehmer wirklich interessieren - simpel und wirkungsvoll. Mal schauen, was dieses Jahr alles am Board zu finden ist, denn für mich ist es insofern interessant, weil am kommenden Wochenende der Startschuss für die Organisation der <a href="https://spartakiade.org/" target="_blank">Spartakiade</a> fallen wird.<br />
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYZwxgDejvVF7NymkU9T-Nlo8CBhdfd9L7IgDrlpFb-9HGNVrI8_N5wcmDppo-9CLpdifO9OrZvafjnSWJ8DYzxptcZIONxHcWb6ZXIHijOb-6_VoApEIWyhNSueFSADJcyhr_qsNp5xlE/s1600/LegoSeriousPlay.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYZwxgDejvVF7NymkU9T-Nlo8CBhdfd9L7IgDrlpFb-9HGNVrI8_N5wcmDppo-9CLpdifO9OrZvafjnSWJ8DYzxptcZIONxHcWb6ZXIHijOb-6_VoApEIWyhNSueFSADJcyhr_qsNp5xlE/s1600/LegoSeriousPlay.jpg" /></a></div>
<br />
Kommenden März, 19.03.16 und 20.03.16 um genau zu sein, werden wieder die Pforten für die Berliner Entwicklerkonferenz geöffnet, bei der es nur Workshops gibt. Workshops, wie sie kommenden Freitag stattfinden werden, nur halt zwei Tage lang volles Programm. Damit dieses spannend und abwechslungsreich gestaltet werden kann, brauche ich die Anregungen vom Open Space, ganz einfach. Wir von der Spartakiade Orga wollen doch wissen, was euch gefällt, was ihr trainieren möchtet, wo die Schuhe drücken.<br />
<br />
Und warum nun Naturgewalten?<br />
<br />
Hey Leute, schaut euch den Blog Post genau an: Event Storming, fluent-CQRS und Community?<br />
<br />
;-)<br />
<br />
<br />
<br />
<br />Janek Fellienhttp://www.blogger.com/profile/11037083301535227855noreply@blogger.comtag:blogger.com,1999:blog-6438666738561404296.post-39979264676642759492015-05-17T22:01:00.000+02:002016-11-13T23:08:18.569+01:00Komm mal wieder raus<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtxl8PU-avfYrZfOs2IB9xTO7LxRcsD7AYvM-RH-2iOHKV1s5jKpqjrYIOxnhgszV6BlD90vi5q6R11RoVyzoA4GNavuih9Mf-u7MYkYSJS6HHfGSB-LdEUBD-2ZAyCsbFqtzsgQ7RFQwF/s1600/DWX2014_all_speakers_download_fullsize-1.JPG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtxl8PU-avfYrZfOs2IB9xTO7LxRcsD7AYvM-RH-2iOHKV1s5jKpqjrYIOxnhgszV6BlD90vi5q6R11RoVyzoA4GNavuih9Mf-u7MYkYSJS6HHfGSB-LdEUBD-2ZAyCsbFqtzsgQ7RFQwF/s1600/DWX2014_all_speakers_download_fullsize-1.JPG" /></a></div>
<br />
Vom 15.06. bis 18.06.2015 findet zum wiederholten Male die <a href="http://www.developer-week.de/" target="_blank">DWX</a>, eine Entwicklerkonferenz in Nürnberg, statt. Auch in diesem Jahr darf ich mich zu den Sprechern zählen, worüber ich sehr froh bin. Zum einen trifft man wieder Kollegen, die für regelmäßige Besuche zu weit weg wohnen und zum anderen darf ich unter anderem einen Vortrag halten, der viel weniger technische Inhalte vermittelt, sondern mehr in die sozial kommunikative Ebene von Teams geht.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlY1YCbvPB7OQKpBp-XIa769-VRruiaZpaRdnFon4Fb-2CSIt6s2C5PDIao3jK6PSMuAnda1V-8JN5p4N2e0KB6fN5sThPIUkju9Lr8aMn1rPRTWPQaWP4OsQGhk6T6JmZgIbDmw5KQp6C/s1600/jfe-eventstorming.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlY1YCbvPB7OQKpBp-XIa769-VRruiaZpaRdnFon4Fb-2CSIt6s2C5PDIao3jK6PSMuAnda1V-8JN5p4N2e0KB6fN5sThPIUkju9Lr8aMn1rPRTWPQaWP4OsQGhk6T6JmZgIbDmw5KQp6C/s1600/jfe-eventstorming.jpg" /></a></div>
<br />
<br />
Doch bevor ich etwas mehr darüber verliere, möchte ich einen Vortrag über Event Storming erwähnen, den ich zusammen mit <a href="http://www.heimeshoff.de/" target="_blank">Marco Heimeshoff</a>, einem Kollegen aus der Community, halten werde.<br />
<br />
Aus meiner aktuellen Sicht, macht sich eine Methode auf den Weg, das iPhone der Methoden zu werden, simpel revolutionär. Im Kern geht es darum, mit einfachen Mitteln, Geschäftsprozesse zu beschreiben. Diese Beschreibungen werden aktiv in den Entwicklungsprozess von Software eingebettet, sodass ein allgegnwärtiges gemeinsames Bild des Systems in den Köpfen der Stakeholder entsteht. Kommunikationsbarrieren und (all zu oft im Weg stehende) Befindlichkeiten werden instinktiv beseitigt. Dass die Dokumentation nebenbei auch noch entsteht, bildet das Sahnehäubchen bei Event Storming.<br />
Ich bin begeistert von dieser Methode und hoffentlich schaffen wir es, diese Begeisterung unter die Leute zu bringen.<br />
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmH-gDfXwuy4mBk0etT5TBID4ZWBmFjKhzzaey9E5rauKiq_Rkz-n-nZJTg-QMvtYkW2q4pBNPIeb5WANjU9GrcWZ6f6jYClmoMFc5d0h0Mnas3jhcupMhHSiAysl1O303FyJgPCtqTJdD/s1600/schlucht-1.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmH-gDfXwuy4mBk0etT5TBID4ZWBmFjKhzzaey9E5rauKiq_Rkz-n-nZJTg-QMvtYkW2q4pBNPIeb5WANjU9GrcWZ6f6jYClmoMFc5d0h0Mnas3jhcupMhHSiAysl1O303FyJgPCtqTJdD/s1600/schlucht-1.jpg" /></a></div>
<br />
Der anfänglich erwähnte Vortrag möchte mit Barrieren innerhalb von Teams aufräumen. All zu oft erleben wir es, dass ein Kollege den Commit vom Vortag eines anderen zurückrollt und nicht ein Wort darüber verliert. In anderen Situationen geraten Entwickler in schier endlose Diskussionen um scheinbar unbedeutenden Code. Oder, was auch viel zu oft passiert, sind Missverständnisse von Architekturen, die zu Grabenkämpfen führen.<br />
Wenn man in solchen misslichen Situationen versucht Klärung zu schaffen, gerät man wieder in eine endlose Diskussion oder im schlimmsten Fall in einen Streit.<br />
<br />
In den letzten Jahren bin ich auch des öfteren in solche Situationen geraten. Anfänglich hatte ich keine Idee, wie man konstruktiv darauf reagieren kann. Inzwischen hat sich eine Erkenntnis heraus kristallisiert, unterstützt durch diverse Gespräche mit Personen, die sich wirklich auskennen.<br />
<br />
Wir Menschen sind einfach gestrickt. Wir leben in Symbiose bzw. im Gleichgewicht miteinander. Unser Bestreben ist es entweder ein Nest zu bauen oder mit wehenden Fahnen Neues zu entdecken (siehe <a href="http://blog.devcrowd.de/von-siedlern-und-entdeckern/" target="_blank">von Siedlern und Entdeckern</a>). Durch diesen Unterschied entsteht in vielen Situationen eine kommunikative Schlucht, die scheinbar nicht zu überwinden ist. Dabei ist die Lösung so einfach wie simpel.<br />
<br />
Mit diesem Cliffhanger lasse ich euch jetzt allein und freue mich auf die Teilnehmer der DWX. :)<br />
<br />
<br />
~janekfJanek Fellienhttp://www.blogger.com/profile/11037083301535227855noreply@blogger.comtag:blogger.com,1999:blog-6438666738561404296.post-6245144894904042372015-02-22T21:57:00.000+01:002016-11-13T23:04:12.746+01:00Spartakiade 2015<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2MAUZ3oKYkT891UvKfQ2PqgxsDpnEvEzZ9CUB4G7TqI7QwHVquyrZ_5_f-D43eyV2SoueVTCS0CPQtId9f0NY3v_RfRS0nal7B3MrQyWzaOcyIUAtIMrbjnogm3r2tYNeqU1OGWvMqDYK/s1600/DSC_0064.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2MAUZ3oKYkT891UvKfQ2PqgxsDpnEvEzZ9CUB4G7TqI7QwHVquyrZ_5_f-D43eyV2SoueVTCS0CPQtId9f0NY3v_RfRS0nal7B3MrQyWzaOcyIUAtIMrbjnogm3r2tYNeqU1OGWvMqDYK/s640/DSC_0064.JPG" width="428" /></a></div>
<br />
<br />
Es ist knapp ein Jahr her, dass die <a href="http://spartakiade.org/" target="_blank">Spartakiade</a> 2014 die Pforten geschlossen hat. Es war eine schöne Konferenz. Ja klar, wieder zu wenig Schlaf, aber dafür um so mehr Spass.<br />
<br />
In 2014 hatten wir den Fokus auf Softwareentwicklung für mobile Endgeräte, und wie ich finde, mit wirklch großem Erfolg. In diesem Jahr sollte eine Schippe drauf gelegt werden. Statt einem Kernthema <a href="http://blog.devcrowd.de/und-los-gehts/" target="_blank">probieren wir es mit eine etwas größeren Fächerung der Themen</a>. Es wird funktionale Programmierung geben, IoT - natürlich - und JavaScript von allen Seiten. Den von mir so sehr gewünschten Anteil von nichttechnischen Themen, haben wir glücklicherweise auch hochkarätig besetzen können. Agilympische Spiele mit <a href="http://www.conplement.de/UdoWiegaertner.html" target="_blank">Udo Wiegärtner</a>, <a href="http://ziobrando.blogspot.de/2013/11/introducing-event-storming.html#.VOovdkJ0A5Q" target="_blank">EventStorming</a> oder <a href="http://de.wikipedia.org/wiki/Lego_Serious_Play" target="_blank">LEGO Serious Play</a> sollen hier genannt werden. Ich freu mich riesig.<br />
<br />
Ja und was muss noch unbedingt erwähnt werden. Na klar, wir sind umgezogen. Der co.up wurde zu klein und so konnte ich mich ein paar Wochen damit herumschlagen einen anderen Ort zu finden. Wie der Zufall es so will, habe ich den ehemaligen IT Leiter (sagt man das so?) von ImmoblienScout24 bei einer Konferenz getroffen. Er war innerhalb weniger Minuten überzeugt und bot die Räume von IS24 an. Was für ein Glück. Es sieht dort nicht nur super aus, es liegt auch besser - finde ich.<br />
<br />
Seit einigen Tage ist die <a href="http://www.eventbrite.de/e/spartakiade-2015-tickets-15754958505?aff=spartakiade" target="_blank">Anmeldung</a> online und es sind schon die ersten Workshops ausgebucht. Toll, ich bin begeistert.<br />
<br />
Also, wir sehen uns auf der Spartakiade<br />
Sport freiJanek Fellienhttp://www.blogger.com/profile/11037083301535227855noreply@blogger.comtag:blogger.com,1999:blog-6438666738561404296.post-88953480645502521942015-01-04T21:52:00.000+01:002016-11-13T23:04:12.756+01:00Neues Jahr, neues Glück<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiR_apCIyjGTNeTGaElwhSBte47t6jiXRBspEerSjRKdGgwT3DSjsNHlSP1opJbOg4ZAnmxUsdkH9J3CVH1bHlukYMYWN2Yp21SWmL77_hNZXbvqVVq2QlhhSiExm-vVpKvQhwW-S0hCZSX/s1600/IMG_20150101_151411.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiR_apCIyjGTNeTGaElwhSBte47t6jiXRBspEerSjRKdGgwT3DSjsNHlSP1opJbOg4ZAnmxUsdkH9J3CVH1bHlukYMYWN2Yp21SWmL77_hNZXbvqVVq2QlhhSiExm-vVpKvQhwW-S0hCZSX/s640/IMG_20150101_151411.jpg" width="473" /></a></div>
<br />
<br />
Ein gesundes neues Jahr wünsche ich allen Lesern meines Blogs. Mein Weg ändert sich in 2015 ein wenig. Die devCrowd wird wesentlich leiser, doch dafür darf ich an einer großen Sache mitmachen. Das freut mich sehr, denn ich kam dazu ein wenig wie die Jungfrau zum Kinde - btw. die Jungfrau kam gar nicht zum Kinde, sondern "eine junge Frau" kam zum Kinde; schöner Übersetzungsfehler.<br />
Gut, was ist passiert? Ich habe mich seit November letzten Jahres recht bedeckt gehalten, doch heute kann ich es verkünden. Ich werde die Leitung der Entwicklung in der <a href="http://www.de.rhenus.com/dienstleistungen/mehrwertlogistik/endkundenbelieferung.html" target="_blank">Rhenus Home Delivery</a> übernehmen. Wie kam es dazu?<br />
<br />
Als ich im Oktober beim <a href="http://devopenspace.de/" target="_blank">Developer Open Space</a> im Leipzig meinen EventSourcing Workshop gehalten habe, muss das einen nachhaltigen Eindruck beim leitenden Softwarearchitekten der Rhenus hinterlassen haben, denn kurz nach dem Workshop erhielt ich eine Anfrage, ob ich diesen Workshop auch in Berlin halten könne. "Na klar" sagte ich, dann aber einen Tag länger, um auch <a href="http://verraes.net/2013/08/facilitating-event-storming/" target="_blank">EventStorming</a> durch führen zu können, schließlich sollte ein neues Feature für die vorhandene Softwarelandschaft bei der Rhenus besprochen werden.<br />
<br />
Gesagt getan, der Workshop war auch aus meiner Sicht ein Erfolg. Einen Tag später erhalte ich das Angebot des amtierenden Entwicklungsleiters, seine Aufgabe zu übernehmen, weil er noch viele andere Aufgaben inne hält und sich leider nicht in Gänze auf die Entwicklung konzentrieren kann. Mich freute diese Anfrage sehr, denn auch wenn ich schon eine Weile selbstständig bin, komme ich ich nicht umhin zu behaupten, dass diese Situation nicht die beste ist. Immer dieser Stress, ob man im nächsten Monat noch ein erträgliches Projekt hat. Zudem hatten mich die letzten beiden großen Projekte ziemlich kaputt gespielt, sodass ich dem Angebot der Rhenus sehr offen gegenüber stand.<br />
<br />
Nach ein zwei sehr guten Gesprächen, war die Sache geritzt, nur noch die vertraglichen Dinge mussten geklärt werden und ich konnte bruhigt in die Jahresendfeiertage gehen.<br />
<br />
Ab dem 05.01.15 gehts los, ich darf in einer Branche, die ich gut kenne, mit einem Team, das ich auch schon kennen gelernt habe, meine Ideen an den Mann und die Frau bringen. Man gibt mir die Möglichkeit neue Wege zu gehen, um ausgetretene Pfade zu verlassen. Die Weichen für eine gute Zeit sind gestellt - <a href="http://de.wikiquote.org/wiki/Star_Trek_VII:_Treffen_der_Generationen" target="_blank">das wird sicher ein Spaß</a>.<br />
<br />
Ja und was möchte ich noch sagen... keine Angst, ich bleibe weiterhin in der Community tätig. Blog und Artikel schreiben, Konferenzen besuchen und Vorträge halten, alles kein Problem mit der Rhenus, denn diese Öffentlichkeitsarbeit wird begrüßt und unterstützt.<br />
<br />Janek Fellienhttp://www.blogger.com/profile/11037083301535227855noreply@blogger.comtag:blogger.com,1999:blog-6438666738561404296.post-21588133109872765732014-12-07T21:48:00.000+01:002016-11-13T23:04:12.728+01:00Ich schreib mal was über irgendwas<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJuNbPNwBMFRduD3sNn9ZUisOLwy74BIP4AvBTbqillcARBSOj9ohoMhiECLIy5DbCC6SV2btxmjo8sDSHycHocDNY3ANit7yoMr5LAGPymAwMoRogzQXQeTzkfsQdUBP6xt3YuCCpDOZs/s1600/natural_tunnel-1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="425" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJuNbPNwBMFRduD3sNn9ZUisOLwy74BIP4AvBTbqillcARBSOj9ohoMhiECLIy5DbCC6SV2btxmjo8sDSHycHocDNY3ANit7yoMr5LAGPymAwMoRogzQXQeTzkfsQdUBP6xt3YuCCpDOZs/s640/natural_tunnel-1.jpg" width="640" /></a></div>
<br />
<br />
<blockquote class="tr_bq">
was<br />irgendwas</blockquote>
<br />
<i>Was denn, da steht doch "was" über "irgendwas"</i><br />
<br />
<br />
Bin ich doch letztens gefragt worden, ob ich nicht ein Buch schreiben möchte, über das was ich technologisch betrachtet sehr gerne tue - <a href="http://www.heise.de/developer/artikel/CQRS-neues-Architekturprinzip-zur-Trennung-von-Befehlen-und-Abfragen-1797489.html" target="_blank">CQRS</a>.<br />
Ja, warum eigentlich nicht? Dass es ein schweres Unterfangen ist, weiß ich ziemlich genau, habe ich doch gerade erst einen Artikel für die <a href="http://www.dotnetpro.de/" target="_blank">dotnetpro</a> über <a href="http://durandaljs.com/" target="_blank">Durandal</a> geschrieben, einem JavaScript UI Framework. Das Ding raubte mir fast den letzten Nerv. Nicht das Framework, nein, der Artikel. Und eigentlich auch nicht der Artikel, sondern vielmehr die Art, wie ich heran gegangen bin.<br />
<br />
Ich wollte eine Heldengeschichte erzählen, weil sich <a href="http://durandaljs.com/" target="_blank">Durandal</a> vom Heldenschwert <a href="http://de.wikipedia.org/wiki/Durendal" target="_blank">Durendal</a> ableitet. Ja und was passt besser als die neuzeitlichen Helden von <a href="http://marvel.com/" target="_blank">Marvel Comic</a>? Korrekt, die von <a href="http://www.dccomics.com/" target="_blank">DC</a>. Doch leider fehlt es bei <a href="http://www.dccomics.com/" target="_blank">DC</a> an der passenden Infrastruktur, sodass ich mich mit Marvel auseinander setzen durfte.<br />
Die <a href="http://developer.marvel.com/" target="_blank">API von Marvel</a> erlaubt es Daten und Fakten rund um ihre Charaktere ab zu fragen, tolles Ding das. Nun nahm ich diese API und knüpfte sie an das Durandal Framework, auch nicht schwer.<br />
<br />
Soweit so gut. Dummerweise habe ich jedoch das gewählte Beispiel für den Artikel wieder einmal künstlich so komplex gemacht, dass ich Stunden verbrachte, um das Backend zu schreiben, um dann wieder fest zu stellen, dass der geneigte Leser damit kaum etwas anfangen kann - Warum? das ist vollkommen egal.<br />
<br />
Also noch einmal von vorn. Projekt öffnen, aktuelles Backend in die Hand nehmen und mehr als 50% Code löschen, macht ja kein Sinn den Kram da drin zu lassen. Dann schnell mit dem Marvel Portal verknüpfen und ein paar Daten selber herunter laden. Diese werden in einem JavaScript Modul verpackt, so dass es aussieht, als währe es eine Datebank. Fertig ist der Lack.<br />
Ich weiß gar nicht, warum ich mich so schwer damit getan habe, immerhin heißt es doch "fail fast" - ach Quatsch, mit "fail" haben die Manager immer Probleme, wir nennen es wie <a href="https://twitter.com/totheralistair" target="_blank">Alistair Cockburn</a> retweetete: "learn fast".<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1-UUf0Lq3VCGvh8pR1KP8Tn-PJFLdEalSNOcSfXmhM_6MH364v78ZvqAtFcbE7L38dXHFb6Gr0mY3u1A13y57QFYP3sBR7-T4EOK39Gulcc3O3MQmFUwi3kN856pxa_iWcO-COH1nAP3O/s1600/Screen-Shot-2014-12-17-at-11-15-55.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1-UUf0Lq3VCGvh8pR1KP8Tn-PJFLdEalSNOcSfXmhM_6MH364v78ZvqAtFcbE7L38dXHFb6Gr0mY3u1A13y57QFYP3sBR7-T4EOK39Gulcc3O3MQmFUwi3kN856pxa_iWcO-COH1nAP3O/s640/Screen-Shot-2014-12-17-at-11-15-55.png" width="542" /></a></div>
<br />
<br />
<blockquote class="tr_bq">
Das ist ja mal eine Aussage, "learn fast" ist gleich bedeutend mit "fail fast" - ich denke, da bahnt sich ein weiterer Blog Post an :)</blockquote>
<br />
Ja gut, kaum war die Pseudodatenbank geschaffen, lief es wie geschmiert und der Fertigstellung des Artikels stand nichts mehr im Weg.<br />
<br />
Danke für diese nette Erfahrung und das Buchschreiben kann ich mir unter diesem Gesichtspunkt doch noch einmal durch den Kopf gehen lassen. Wer auch dafür ist, kann mir unter Twitter Motivationsnachrichten schreiben. ;-)Janek Fellienhttp://www.blogger.com/profile/11037083301535227855noreply@blogger.comtag:blogger.com,1999:blog-6438666738561404296.post-47769976975639380052014-11-06T21:36:00.000+01:002016-11-13T23:04:12.737+01:00Und los gehts<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIpJeUkadIu93YGsnM74IDniBnnPGm05I4tx2l-y9unzF9Ps-4eB4apOYay5VfjEZjyPQpohPFyI06TqfEhFU4UYLfkXNKOsDSnB25ub9BAANdZmLZwB1LKWg1w4jPlWldfFcigvQRzALM/s1600/spartakiade-da-entlang.jpg" imageanchor="1" style="clear: left; display: inline !important; margin-bottom: 1em; margin-right: 1em; text-align: center;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIpJeUkadIu93YGsnM74IDniBnnPGm05I4tx2l-y9unzF9Ps-4eB4apOYay5VfjEZjyPQpohPFyI06TqfEhFU4UYLfkXNKOsDSnB25ub9BAANdZmLZwB1LKWg1w4jPlWldfFcigvQRzALM/s1600/spartakiade-da-entlang.jpg" /></a><br />
<br />
Es geht wieder los, in die nächste Runde der <a href="http://spartakiade.org/" target="_blank">Spartakide</a>. Vor einigen Tagen habe ich damit begonnen, die ersten Trainer anzuschreiben. Von einigen habe ich schon eine positive Antwort oder zumindest ein Interessensbekenntnis. Wunderbar ist das, denn dann entsteht nicht ganz so viel Stress und ich kann mich mehr auf den Rest konzentrieren.<br />
<br />
In der Vorbebesprechung mit Torsten zur nächsten Spartakiade, haben wir eine Neuerung beschlossen. Es kommt mehr Abwechslung rein durch ein breiteres Angebot. Eigentlich eine richtig gute Sache. Und, weil ich immer eine Story zu den Projekten brauche habe ich mir folgendes ausgedacht.<br />
<br />
Die Workshops werden in die Kategorien Leichtathletik, Kraftsport, Mehrkampf und Mannschaftssport eingeteilt. Damit lassen sich die Inhalte des Workshops gut beschreiben, denn<br />
<br />
<br />
<ul>
<li><b>Leichtathletik</b> sind die Einsteiger Workshops</li>
<li><b>Kraftsport</b> die richtig herausfordernden.</li>
<li>unter <b>Mehrkampf</b> gruppieren sich die Workshops mit mehreren Inhalten und</li>
<li><b>Mannschaftssport</b> ist Teamarbeit.</li>
</ul>
<br />
<br />
Na dann bin ich mal gespannt, wie die Trainer ihre Workshops einstufen werden.<br />
<br />
Sport frei, bis März kommenden Jahres.Janek Fellienhttp://www.blogger.com/profile/11037083301535227855noreply@blogger.comtag:blogger.com,1999:blog-6438666738561404296.post-21226256057879827942014-11-03T21:33:00.000+01:002016-11-13T23:04:12.724+01:00Klopf klopf<blockquote class="tr_bq">
Wer ist da?<br />Der Hohn</blockquote>
<br />
Irgendwie prasseln immer mehr Nachrichten auf mich ein und es gelingt mir nur noch sehr schwer sie zu filtern.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcrbRLDQ4LdTTlSFkwcWPZ_S5hvklNdPQUhY_Yy_EY-BMgHig2hPVptBkDGmatMMHT4w0-nIRZrRA4rXXLndVGDz5lmx8PR9gLrQwI5MnGQrLEmQ2V1jkUmeoKeXh7CVOH42k2wCc9q7Mj/s1600/wheels-1.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcrbRLDQ4LdTTlSFkwcWPZ_S5hvklNdPQUhY_Yy_EY-BMgHig2hPVptBkDGmatMMHT4w0-nIRZrRA4rXXLndVGDz5lmx8PR9gLrQwI5MnGQrLEmQ2V1jkUmeoKeXh7CVOH42k2wCc9q7Mj/s1600/wheels-1.jpg" /></a></div>
<br />
Diverse weltpolitischen Konflikte lassen mich in einer Art Habachtstellung verharren. Ohnmächtig beobachte ich was in der Welt passiert und bin endlos verärgert, dass man nichts wirklich bewirken kann.<br />
Gerade heute Morgen höre ich im Radio, dass in Deutschland die Flüchtlingsfrage immer komplexer und undurchsichtiger wird. Wie hieß es doch so schön <i>"... neuntausend Flüchtlinge aufnehmen geht nicht, bei einem Land mit 80 Millionen Einwohnern?..."</i> Ja genau, es ist ein klitze kleiner Tropfen und die Politiker zerreißen sich den Mund deswegen. Vielleicht sollten eben diese Politiker für ein Jahr in das betroffene Land reisen und dort vor Ort Flüchtlingshilfe lernen.<br />
<br />
Ein Gedanke schoss mir durch den Kopf. Warum nicht ein Haus kaufen, wo man Arbeitsplätze ein richtet, die ausschließlich von Menschen auf der Flucht besetzt werden. Klar, man macht sich nach deutschem Recht strafbar, weil Menschen, denen alles genommen wurde, Heimat, Familie und Lebensgrundlage, dürfen in Deutschland nicht arbeiten, nicht ein mal einen unbezahlten Praktikumsplatz dürfen sie annehmen. Ich werde den Gedanken nicht los, dass hinter diesen Gesetzen diejenigen stecken, die sonst <i>"... erst Arbeit für Deutsche..."</i> propagieren. Wohin soll das noch führen? Wohin?<br />
<br />
Schon allein die Tatsache, dass ich gar nicht so viel Geld habe, mal eben schnell ein Haus zu kaufen, geschweige denn, dass man eine Genehmigung bekommen würde für so ein Projekt. Am Ende würde Gevatter Staat auf seine Gesetzte beharren und lieber Mutter Theresa ins Gefängnis stecken als Nächstenliebe zu zeigen.<br />
<br />
Nächstenliebe - keine Sorge, ich gehöre keinerlei Sekte oder sonstigen religiösen Gruppierungen an. Ich benutze nur meinen Kopf und bin maßlos enttäuscht. Werde ich dadurch radikal? Nein nicht wirklich. Ich bin nur ohnmächtig.<br />
<br />
<br />
<br />Janek Fellienhttp://www.blogger.com/profile/11037083301535227855noreply@blogger.comtag:blogger.com,1999:blog-6438666738561404296.post-57759732500372724522014-10-20T21:28:00.000+02:002016-11-13T23:04:12.740+01:00Alles nur Ereignis<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlGSQQoYDlLL6kzZCcp_HtlNdvx3a0CSoXzJQ98LeWfR3hGufQLwmVDslUeN3I0JQ4dfcEttcZ7WrrcEDfa9AHsk7-LKAEXi-8sJKHt_Eh8leeN1ECx77GhQLqP7j_vijPZqPQ08R52trQ/s1600/openspace-leute.jpg" imageanchor="1" style="clear: left; display: inline !important; margin-bottom: 1em; margin-right: 1em; text-align: center;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlGSQQoYDlLL6kzZCcp_HtlNdvx3a0CSoXzJQ98LeWfR3hGufQLwmVDslUeN3I0JQ4dfcEttcZ7WrrcEDfa9AHsk7-LKAEXi-8sJKHt_Eh8leeN1ECx77GhQLqP7j_vijPZqPQ08R52trQ/s1600/openspace-leute.jpg" /></a><br />
<br />
Es ist der 16. Oktober 2014, das Wetter schickt sich nicht an Herbst zu werden. Im Gegenteil es mach eher den Eindruck, dass es sich zurecht gemacht hat, für die bevortehenden drei Tage. Es ist <a href="http://devopenspace.de/" target="_blank">Developer Open Space</a> Zeit. Eine Zeit, bei der sich gut 200 Entwickler in Leipzig treffen, um gemeinsam über Themen zu diskutieren, die sie selber bestimmen und daher besonders interesieren.<br />
<br />
Ach ich lass es lieber, den Open Space zu beschreiben, man muss es selber mit erleben. Jahr für Jahr ändert sich das Flair. Mal ist es nerdig, mal philosophisch. In diesem Jahr könnte man von heterogen sprechen. Viele unterschiedliche Themen haben es in die Agenda geschafft und Kassenschlager der Vorjahre blieben außen vor. Das ist der Open Space in Leipzig.<br />
<br />
<a href="http://torstenweber.de/" target="_blank">Torsten Weber</a> (einer der Organisatoren des Open Space) fragte mich einige Wochen zuvor, ob ich einen Workshop halten möchte, einen Tag vor dem Event, für die gleichen Teilnehmer. Na klar sage ich da zu und schlage eines meiner Kernthemen vor - das EventSourcing. Keine Sorge, ich werde jetzt nicht darüber schreiben, was das ist, dafür ist hier kein Platz.<br />
<br />
Es ist der 16. Oktober, ich mache mich fertig, für die kommenden Tage. Viel muss ich nicht einpacken, es ist warm draußen. Vielmehr bin ich aufgeregt auf den morgigen Workshop, denn in der Vorbereitung ist einiges anders gelaufen als gedacht. Naja, so ist das mit der IT, es kommt immer etwas dazwischen.<br />
<br />
Auf dem Weg nach Leipzig habe ich Lars Kumbier mitgenommen, er suchte noch nach einer Mitfahrgelegenheit, da die Lockführer mal wieder streiken und er ohne Auto in der Stadt ist.<br />
Die Autofahrt gestaltet sich extrem kurzweilig, da Lars und ich feststellen, dass wir auf einer gewissen Ebene die gleichen Meinungen über Teambuilding und Entwicklungsmethodiken teilen. Toll mal von anderen Menschen bestätigung für seine Ideen zu erhalten.<br />
<br />
Es ist immer noch der 16.Oktober und es ist schon viel passiert, denn auch das ist der Open Space.<br />
<br />
<h3>
EventSourcing</h3>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijcXn-p0FUHY79nOa5jbYg0xWyLCaWhWE95fkDDMebRHz53-7hHI3tHmFAvRxsEpuyuIlcLzAEe5HTOIectsx6a5wckFoDRrfmgn8faFtroLDNkn22LkZYKFnGWXDcRetCwNLlfO9DtUTZ/s1600/openspave-eventsourcing.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijcXn-p0FUHY79nOa5jbYg0xWyLCaWhWE95fkDDMebRHz53-7hHI3tHmFAvRxsEpuyuIlcLzAEe5HTOIectsx6a5wckFoDRrfmgn8faFtroLDNkn22LkZYKFnGWXDcRetCwNLlfO9DtUTZ/s1600/openspave-eventsourcing.jpg" /></a></div>
<br />
Mein erster Workshop auf solch einer Entwicklerveranstaltung. Die Messlatte liegt extrem hoch und ich habe sie selber noch viel höher gelegt. Dass das eine schlechte Wahl war, stelle ich binnen kürzester Zeit fest und ändere sofort mein Konzept für den Worshop. Statt einer Legacy Applikation, die zur EventSorcing Applikation umgebaut werden soll, entscheide ich mich für eine Neuentwicklung, quasi von der Pieke an. Das ist leichter nach zu vollziehen.<br />
<br />
Ja und warum fälle ich diese Entscheidung? Es sitzen so viele Teilnehmer im Raum, dass es mir unmöglich gewesen wäre mich auf jeden gebührend konzentrieren zu können.<br />
<br />
Also, neues Konzept, gleicher Inhalt.<br />
<br />
Bis zur Mittagspause musste leider der Code von den Teilnehmern abgeschrieben werden, zum einen, weil die Netzqualität ziemlich schlecht war aber auch weil ich nicht in der Lage war, die Auflösung des Beamers entsprechend ein zu stellen.<br />
<br />
Nun gut, der schwere Anfang wurde überwunden und mit Livecoding und ganz viel praktischem Einsatz konnte der Workshop erfogreich beendet werden. Jeder Teilnehmer hatte am Ende eine funktioniere Applikation, die der Struktur einer EventSourcing Architektur folgt.<br />
<br />
Tage später erhielt ich sogar noch weitere Lösungen, an denen weiter geschraubt wurde. Das finde ich super, dass hier noch weiter gearbeitet wurde. Vielleicht konnte ich ja doch den ein oder anderen Entwickler mit dem EventSourcing Virus infizieren. :)<br />
<br />
Es ist der 17.Oktober 2014 und ich bin sehr zufrieden, auch wenn es anfangs holprig war. Versprochen, beim nächsten Mal klappt es auf jeden Fall.<br />
Auch das kann der Open Space sein.<br />
<br />
<br />
<h3>
Open Space</h3>
Langsam füllt sich der große Raum im Commundo Tagungshotel. Ab 10 Uhr sollten eigentlich alle da sein und das Zusammenstellen der Agenda kann beginnen. Einige Themen sind schon bekannt, weil sie in einer World Coffee Runde ermittelt wurden. So gelingt einem der Einstieg in dieses Konferenzformat viel leichter. Ja und dieses Jahr sind sehr viele neue Gesichter zu sehen. Also gibt es auch viele, die erst eineml sehen müssen, wie es funktioniert.<br />
<br />
Viele Themen kommen ans Board, sehr viele. Einige davon schieben wir in den Sonntag - ja das darf man - genau so, wie ab zu stimmen, in welchem Raum zu welcher Zeit welches Thema besprochen wird.<br />
<br />
Als die Agenda fertig ist, beginnt das Gewusel. Das beliebteste Foto in den kommenden Minuten ist die Agenda selbst. Dies wird zu Hauf über Twitter veröffentlicht, so dass eigentlich jeder im Raum den Plan auf seinem Smartphone abspeichern kann.<br />
<br />
Stunde um Stunde vergeht. Die Gespräche zwischen den Sessions gestalten sich genau so interessant, wie die Sessions selber.<br />
<br />
Es ist der 18. Oktober - es ist Open Space.<br />
<br />
Wenn man die Zeit zwischen den beiden Tagen normal verbringen möchte, dann geht man am ertsen Tag bis mindestens 4 Uhr früh ins Joseph Pub und versucht fest zu stellen, welche Themen noch vorgestellt werden sollten. Die irresten Dinge kommen da auf den Tisch. Aber nicht alles wird am Sonntag vorgestellt.<br />
<br />
Der 19. Oktober hat begonnen.<br />
<br />
Wie schon am Tag zuvor, besucht man die Sessions, die einen interessieren. Ich konnte glücklicherweise noch einmal eine Session einberufen, die ich tags zuvor verpasst habe. So komme ich in den Genuss EventStorming kennen zu lernen. Eine Methodik, die verwendet wird, wenn man eine Applikation, die nach DDD modelliert wird, strukturieren möchte. Super Angelegenheit.<br />
<br />
Plötzlich ist die Zeit rum, die Teilnehmer dünnen sich aus. Die ersten fahren nach Hause, auch ich denke darüber nach. Noch ein paar Gespräche und das Verabschieden nicht vergessen, dann kann es los gehen.<br />
<br />
So viele Eindrücke schon wieder und die Gewissheit, das was ich im kommenden Jahr vor habe, endgültig um zu setzen.<br />
<br />
Es ist der Abend des 19. Oktober, das war mein Open Space.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcki0mrHYnweYrHU3fEwJSbWtcigKHy2AsuC7mX5il8tTTO1TKhl9-i95ptrP1ALdktMW4uWFLvycI7_vmvOFFSoPEmz3_RI3oQMK5pMjIfPM0FSTF7iPAuBVFgwxQGsGT9ip7AKGcY7P4/s1600/openspace-janek.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcki0mrHYnweYrHU3fEwJSbWtcigKHy2AsuC7mX5il8tTTO1TKhl9-i95ptrP1ALdktMW4uWFLvycI7_vmvOFFSoPEmz3_RI3oQMK5pMjIfPM0FSTF7iPAuBVFgwxQGsGT9ip7AKGcY7P4/s1600/openspace-janek.jpg" /></a></div>
<br />Janek Fellienhttp://www.blogger.com/profile/11037083301535227855noreply@blogger.com