-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathfeed.xml
520 lines (335 loc) · 50.1 KB
/
feed.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Ampelofilosofies</title>
<description>Random comments on random subjects in random language</description>
<link>http://www.ampelofilosofies.gr</link>
<atom:link href="http://www.ampelofilosofies.gr/feed.xml" rel="self" type="application/rss+xml" />
<item>
<title>Using chat as a software team</title>
<description><p>My guidelines for using chat (Teams, Slack, whatever you fancy) as a collaboration tool in a software development team are as follows:</p>
<h2 id="chat-is-asynchronous">Chat is asynchronous</h2>
<p>Always provide context when addressing someone. Never go “Hi!”. Ask the question immediately and with as much information as you can provide.</p>
<p>If you don’t provide context you are demanding the immediate attention and response from your counterpart thus underutilizing the medium’s asynchronous nature.</p>
<p>If it is urgent, call. I reserve the right to not answer. If I don’t answer, message me the context.</p>
<h2 id="knowledge-should-be-available-to-all">Knowledge should be available to all</h2>
<ul>
<li>Use a common channel</li>
<li>Pose a question with context</li>
<li>Post the answer afterwards if a solution occurs outside of the chat</li>
</ul>
<p><strong>Avoid the use of direct messages or ad-hoc groups</strong>.</p>
<p>They can be used to reduce the noise in the common channel but should not be the first approach. Initiate group work in the common channel which can then be spun off in a side channel.</p>
<p>A common channel has several advantages:</p>
<ul>
<li>It is a known central reference point.</li>
</ul>
<p>There’s no need track of where and when a conversation happened.</p>
<ul>
<li>It exerts some control over the notification flood.</li>
</ul>
<p>DMs are interruptions. A common channel allows users to choose how their own interaction pattern whether that is an immediate response or a periodic check.</p>
<ul>
<li>It helps disseminate knowledge in an indirect way.</li>
</ul>
<p>Perusing the channel inevitably presents an overview of the team’s activity to all.</p>
<ul>
<li>It widens the pool of potential responders to the whole team</li>
</ul>
<p>You never know who has the answer.</p>
<h2 id="text-is-king">Text is king</h2>
<p>Do not post screenshots of terminal screens, stacktraces or errors.</p>
<p>No, seriously, please don’t. There’s nothing more tedious than trying to zoom on text in a picture, nothing to copy and edit.</p>
</description>
<pubDate>Tue, 28 Jan 2025 18:15:00 +0100</pubDate>
<link>http://www.ampelofilosofies.gr/work/2025/01/28/using-chat-in-development</link>
<guid isPermaLink="true">http://www.ampelofilosofies.gr/work/2025/01/28/using-chat-in-development</guid>
</item>
<item>
<title>Adventures in the land of AI</title>
<description><p>The advent of AI marks a fundamental change to the discipline of software engineering. It is one of those changes that rearranges the way people work and think about that work. So, in the interest of self-preservation I have been spending time with various AI models.</p>
<p>There are two avenues that I am interested in pursuing this, how it affects my coding and how it affects a team.</p>
<h2 id="delegating-coding-tasks">Delegating coding tasks</h2>
<p>Everyone is enthusiastic about how much of a productivity boost tools like GitHub CoPilot bring and all the introductory articles and demos are wild about how easy it is to get to a running application in “seconds”.</p>
<p>Yes…and definitely no. I’ve been conducting a couple of experiments with simple tasks that crop up daily.</p>
<p>My goto question was “how do I ensure the an Azure Pipeline, when triggered, executes only if there is no run of the same pipeline currently active”.</p>
<p>All systems will hallucinate Azure Pipelines YAML syntax that is very believable. Believing them will cost you a couple of hours and some frustration. None of the clarifying prompts used subsequently could convince the system to not hallucinate.</p>
<p>As context: this is a trick question. There is no easy, out-of-the-box supported way to do this in Azure Pipelines.</p>
<p>In one particularly egregious example, ChatGPT kept re-writing the same line of code using all the ways the language had to do string interpolation, without actually changing the answer.</p>
<p>That question was on how to perform WebDAV deletes in Ruby. The code provided used Faraday, but was using custom HTTP requests, which the library does not support.</p>
<p>ChatGPT responded with the same piece of code after every correction prompt, only rewriting one line:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># First answer</span>
<span class="n">response</span> <span class="o">=</span> <span class="n">client</span><span class="p">.</span><span class="nf">run_request</span><span class="p">(</span><span class="ss">:propfind</span><span class="p">,</span> <span class="n">server_url</span><span class="p">,</span> <span class="kp">nil</span><span class="p">,</span> <span class="p">{</span> <span class="s1">'Depth'</span> <span class="o">=&gt;</span> <span class="s1">'1'</span> <span class="p">})</span>
<span class="c1">## Second answer</span>
<span class="n">response</span> <span class="o">=</span> <span class="n">client</span><span class="p">.</span><span class="nf">connection</span><span class="p">.</span><span class="nf">run_request</span><span class="p">(</span><span class="ss">:propfind</span><span class="p">,</span> <span class="n">server_url</span><span class="p">,</span> <span class="kp">nil</span><span class="p">,</span> <span class="p">{</span> <span class="s1">'Depth'</span> <span class="o">=&gt;</span> <span class="s1">'1'</span> <span class="p">})</span>
<span class="c1">## Third answer</span>
<span class="n">response</span> <span class="o">=</span> <span class="n">client</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="ss">:run_request</span><span class="p">,</span> <span class="ss">:propfind</span><span class="p">,</span> <span class="n">server_url</span><span class="p">,</span> <span class="kp">nil</span><span class="p">,</span> <span class="p">{</span> <span class="s1">'Depth'</span> <span class="o">=&gt;</span> <span class="s1">'1'</span> <span class="p">})</span>
</code></pre></div></div>
<p>I find the above example hilarious. Reminds me of when I catch my son lying, point it out and then watch how he digs himself deeper trying to deny it.</p>
<p>The general observations are:</p>
<ul>
<li>AIs are currently seemingly incapable of saying “I don’t know” or “that is not possible”. This is very important and it is a big flaw when used in a professional context, specifically while programming.</li>
<li>Prompting is an art and it is the art of properly identifying requirements and being able to phrase them clearly and unambiguously. We are going to have some hilarious misunderstandings.</li>
<li>Niche knowledge is far from the AIs reach at the moment. It is an easy way to get them to hallucinate.</li>
</ul>
<p>I find the first point very dangerous. It makes every answer a suspect that requires cross-examination and verification. Either that or gain a false sense of confidence about how easily some things are achievable.</p>
</description>
<pubDate>Fri, 01 Nov 2024 12:15:00 +0100</pubDate>
<link>http://www.ampelofilosofies.gr/work/2024/11/01/adventures-in-ai-land</link>
<guid isPermaLink="true">http://www.ampelofilosofies.gr/work/2024/11/01/adventures-in-ai-land</guid>
</item>
<item>
<title>Unpopular opinion: Happiness</title>
<description><p>“Happiness” is a dumb metric within a work context.</p>
<p>Success is measured in outcome not output and blithely sailing past a deadline while deliriously happy is not my idea of a good thing.</p>
<p>Also, satisfaction at work, while important, is not measurable in the emotion scale I associate with happiness.</p>
<p>Confidence, the feeling of achievement, satisfaction in a job well done and appreciation of said work are all contributing factors to a stable emotional base.</p>
<p>Happiness though, is a different category and dependent on a different social context. It relies in part on the experiences within the work context but cannot not be quantified in isolation.</p>
</description>
<pubDate>Wed, 14 Aug 2024 13:15:00 +0200</pubDate>
<link>http://www.ampelofilosofies.gr/work/2024/08/14/unpopular-opinion-happiness</link>
<guid isPermaLink="true">http://www.ampelofilosofies.gr/work/2024/08/14/unpopular-opinion-happiness</guid>
</item>
<item>
<title>Autonomy in software development teams</title>
<description><p>The subject is autonomy within a software development team, or rather the consequences of interpreting a very broad and vague term such as the single word “autonomy” in very different ways depending on where you come from, how experienced you are or what suits you.</p>
<p>My first reaction once I got the idea of writing this down was to go back through the sources, my own influences over the years and the research that buttressed my own vocal support of autonomy. To hunt down the origin of the use of words like agency and self-determination. The borrowed metaphors from psychology and social sciences selectively interwoven within the discipline of software development. To present the research and quote the papers.</p>
<p>But I can’t really be bothered because the accumulated experience taps me on the shoulder and says “nah, that’s all theory. In practice none of this ever holds 100% true and every team you’ve been on has been a unique blend”.</p>
<p>So, f* it, I’ll just write what I have experienced and hope my years in this job have enriched my sample enough to bear statistical significance without really believing it will.</p>
<h2 id="observation-1-humans-are-lazy">Observation #1: Humans are lazy</h2>
<p>Probably by design, something about the way our brains process signals and the fact that it takes so much energy to actually run that brain of ours.</p>
<p>The observation is that people automatically fall back in their comfort zones. They also underperform if they find themselves outside their comfort zone for prolonged periods of time.</p>
<p>Remaining outside your comfort zone requires effort. The fact that it will eventually expand your comfort zone is irrelevant to the point. We reserve the expenditure of energy for things we care about.</p>
<h2 id="observation-2-diversity-is-brilliant-but-expensive">Observation #2: Diversity is brilliant but expensive</h2>
<p>Expensive in terms of effort and mental and psychological energy expenditure. Dealing with differences and alternate, often times opposing points of view, is outside most people’s comfort zone.</p>
<h2 id="conclusion-1">Conclusion #1</h2>
<p>Putting the first two observations together results in something along the lines of “putting a diverse team together requires a significant amount of initial effort and will only work if the team is able to establish a comfort zone inclusive of it’s diversity”.</p>
<p>Consequently it is no surprise to me that most teams tend to homogenize over time: we pick the people that share our comfort zone or with which we have already developed a comfort zone.</p>
<p>There is a very interesting side-observation to this: The prevalent work mode for software developers in the past two decades has been the frequent switch of employer.
This on first consideration would appear as a good thing as it repeatedly forces people to operate in a new team environment. It can be argued that this is a good thing as in theory it continually expands the pool of people and personalities you come into contact with.
My own opinion is that this is a logical fallacy. Given our inherent laziness and the investment of effort required in maintaining diversity, temporality is an incentive for the opposite.
In plain words: if you’re not going to stick around long enough and you are less productive when outside your comfort zone, it makes sense to homogenize and select for less effort required.</p>
<h2 id="observation-3-projects-depend-on-individuals">Observation #3: Projects depend on individuals</h2>
<p>There is never a team where all individuals contribute equally. Depending on the size of a team we are looking for a number between one and a low single digit number of people who are invested in achieving the team’s goal.</p>
<p>In some cases it is very difficult to get people to bother at all, especially in the beginning.</p>
<p>These individuals, the ones who care about the stated goal, are the drivers.
The ones, who are here to do the job and get paid, well, they are the professionals.</p>
<p><em>I will not attempt to talk about people that neither care nor do the job. Meeting this type has been a rare occurrence in my 30 years of professional experience, which is a benefit of working in a field that attracts motivated people</em>.</p>
<p>To have an autonomous team with members who have agency requires the somebodies who care to relinquish a lot of the control aspects that they care about in the first place (things like how work is organized, how the team communicates, the creative and creation process etc.).</p>
<h2 id="observation-4-success-depends-on-collective-effort">Observation #4: Success depends on collective effort</h2>
<p>No individual contribution is enough to lead a team to success. Individual contributions can easily lead a team to failure, but success depends on collective effort.</p>
<p>There is too much complexity, too much creative work required and a lot of “magic” - as in <a href="https://en.wikipedia.org/wiki/Clarke%27s_three_laws">“Any sufficiently advanced technology is indistinguishable from magic”</a> - in software development for one person. Ergo, you need several working together.</p>
<p>Combined with observation #3 this presents us with the driver for most modern management theories: how to motivate people so that they go along towards the goal.</p>
<p>It is also in my view the limiting factor for true diverse, autonomous teams.</p>
<h2 id="conclusion-2-teams-require-autonomy-for-individuals-it-depends">Conclusion #2: Teams require autonomy, for individuals it depends</h2>
<p>Full autonomy for every team individual without goal alignment inadvertently leads to conflict. We can scale this up: in a complex project with multiple teams, full team autonomy within the project is not efficient.</p>
<p>Consensus building, which is essential for collective effort requires individuals to self-regulate and limit their autonomy within the context of a team. Learning how to do this without conflict is hard.</p>
<p>Hierarchical structures with clear leadership mandates simplify things immensely - at least at first glance.
The “just follow orders” paradigm is not prevalent in our sector. See observation #4 for a possible reason but also because modern software systems require contribution in imprecisely understood areas that are not easily quantified or measured.</p>
<p>Which is ironic, because the whole sector sells quantifiable attributes and measurability as an inherent trait.</p>
<p>But for the time being, the level of complexity and expertise required safeguards the relative independence of the experts.</p>
<p>A.I.’s promise to partly to eliminate this by industrializing a large chunk of the software development aspects and platform engineering’s recent popularity are reactions to the inefficiencies of unchecked autonomy.</p>
<p>It remains to be seen if the swing will go past the equilibrium but given that we are once again discussing technical solutions to what is essentially a social problem I would bet that in 5 or so years I will be hearing people being overly critical of how bossy ChatGPT has become.</p>
</description>
<pubDate>Sun, 10 Mar 2024 15:15:21 +0100</pubDate>
<link>http://www.ampelofilosofies.gr/software/2024/03/10/autonomy-in-practice</link>
<guid isPermaLink="true">http://www.ampelofilosofies.gr/software/2024/03/10/autonomy-in-practice</guid>
</item>
<item>
<title>A decade in eight months</title>
<description><p>It has been a decade in less than 8 months.</p>
<p>The last time I had some time to gather and collect thoughts is shrouded in mental mist. In the beginnings of April, while adjusting to a full lockdown with far reaching personal consequences, I took on a new challenge by casually accepting a new project assignment.</p>
<p>The new team needed a “data lead”, someone described as “knows databases”. It has been about 20 years since I’ve had to earnestly confront normalisation forms or stored procedures or even query optimisation and indexes but I wasn’t really worried (hence the “casual” acceptance).</p>
<p>I was right not to worry… about databases. Eight months later and all we use is a key-value store.</p>
<p>It has been a decade in less than 8 months.</p>
<p>My team has delivered the impossible: a working, web scale system in a landscape of ever changing requirements and priorities that serves tens of millions of clients daily, all in under 4 months.</p>
<p>My team is able to pivot within hours and delivers features within a day or two. My team has had to pivot and re-prioritize every other week for the past 4 months - need trumps planning every freaking time.</p>
<p>My team has done this working 100% remotely. With cats and dogs, kids and spouses present and overburdened wifi.</p>
<p>My team is doing voodoo and they do it soooo well.</p>
<p>I am immenselly proud to be part of this team.</p>
<p><img src="https://media.giphy.com/media/V2Ylf5EhsUPMQ/giphy.gif" alt="Go and do the voodoo" /></p>
<p>It has been a decade in less than 8 months.</p>
<p>The list of lessons hammered under relentless pressure and unprecedented visibility is not fully formed yet. And it is already long.</p>
<p>There are so many things to talk about, I need a sabbatical just to put the list together.</p>
<p>Actually having a list of discrete subjects to talk about <em>is</em> the hardest thing. Breaking apart the melange of compromises, decisions, solutions discarded, solutions chosen and lucky guesses all done in a astonishingly short time.</p>
<p>Looking back at incidents in a manner that isolates them from each other, the sequence they occured and the environment they occured in invites errors. Misconception and misunderstanding.</p>
<p>The usual reductive way I follow when deciding what to focus on when crafting an experience report is not going to work this time. There is not a single point, something easily punted into a single sentence aphorism (“Automate all the things!”, “People before technology!”, “Repository first!”) that can do justice to the past eight months.</p>
<p>I’ve read about big formative projects that gave birth to ground-breaking approaches on how teams create software. This feels like one of those projects, even though there is nothing ground-breaking in the tools and methods my team uses.
I catch myself going through all the material, presentations, notes and memories of conference encounters.</p>
<p>This time I look for the uncertainties, the references to compromise, the “it depends”, the hesitation before delivering a list of rules, the caveats.</p>
<p>It would be a lie to say that people don’t talk about compromises and trade-offs. More like that the warnings and conditionals are discarded with the passage of time leaving a shiny, polished success recipe, a myth.</p>
<p>I need a new way of telling stories about (software) systems and the teams of people that build them.</p>
</description>
<pubDate>Sun, 29 Nov 2020 15:15:21 +0100</pubDate>
<link>http://www.ampelofilosofies.gr/software/2020/11/29/decade-in-eight-months</link>
<guid isPermaLink="true">http://www.ampelofilosofies.gr/software/2020/11/29/decade-in-eight-months</guid>
</item>
<item>
<title>Tales of Teamcity: Failures in Kotlin</title>
<description><p><em>This is part of a series of posts documenting my ongoing adventures in TeamCity, starting at <a href="/software/2020/03/31/adventures-in-kotlin-1">Tales of Teamcity: Adventures in Kotlin</a></em></p>
<p>Kotlin is cool. I am a fool.</p>
<p>These two sentences are both true. The best aggro moment of the last three days was when I spent over two hours trying to figure out why the following script failed:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nn">jetbrains.buildServer.configs.kotlin.v2019_2.*</span>
<span class="n">version</span> <span class="p">=</span> <span class="s">"2019.2"</span>
<span class="nf">project</span> <span class="p">{</span>
<span class="n">description</span> <span class="p">=</span> <span class="s">"TeamCity as Code"</span>
<span class="nf">buildType</span><span class="p">(</span><span class="nc">Experiment</span><span class="p">)</span>
<span class="p">}</span>
<span class="kd">object</span> <span class="nc">Experiment</span> <span class="p">:</span> <span class="nc">BuildType</span><span class="p">({</span>
<span class="n">name</span> <span class="p">=</span> <span class="s">"experiment"</span>
<span class="nf">vcs</span> <span class="p">{</span>
<span class="nf">root</span><span class="p">(</span><span class="nc">DslContext</span><span class="p">.</span><span class="n">settingsRoot</span><span class="p">)</span>
<span class="p">}</span>
<span class="nf">steps</span> <span class="p">{</span>
<span class="nf">script</span> <span class="p">{</span>
<span class="n">name</span> <span class="p">=</span> <span class="s">"Docs"</span>
<span class="n">scriptContent</span> <span class="p">=</span> <span class="s">"rake doc:gaudi"</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">})</span>
</code></pre></div></div>
<p>I even went as far a posting an issue on the TeamCity support site. And then I went to bed, slept through the night, looked at the code again this morning and remembered I am writing code in a JVM language.</p>
<p>So I added</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nn">jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.script</span>
</code></pre></div></div>
<p>at the top.</p>
<p>Remember, I am a professional and I have been doing this for 25 years.</p>
<p>It helps that your TeamCity instance hosts the DSL reference at <em>app/dsl-documentation/index.html</em>.
It also helps to read said reference.</p>
<p>But mostly, it helps when you just go to bed and try again when you’re fresh.</p>
<hr />
<p>The response to my brain-dead-due-to-lack-of-sleep support request came as I was writing this. Response time less than 16 hours. I am liking this.</p>
</description>
<pubDate>Tue, 31 Mar 2020 19:15:21 +0200</pubDate>
<link>http://www.ampelofilosofies.gr/software/2020/03/31/adventures-in-kotlin-2</link>
<guid isPermaLink="true">http://www.ampelofilosofies.gr/software/2020/03/31/adventures-in-kotlin-2</guid>
</item>
<item>
<title>Tales of Teamcity: Adventures in Kotlin</title>
<description><p>TeamCity is one CI system I haven’t had a lot of contact until now. As will become evident, this has now changed.</p>
<p>So, alongside a crash course in basic Kotlin, I now have to figure out how to get my brand of build automation working in TeamCity.</p>
<h2 id="the-gatekeeper">The gatekeeper</h2>
<p>I have one criterion for accepting a build management system:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Build job specifications have to be stored in the repository
</code></pre></div></div>
<p>Let’s explore if TeamCity makes it past the door and how far we can take it.</p>
<h2 id="first-contact">First contact</h2>
<p>First contact is always a search along the lines of “build DSL, TeamCity”. I was already aware that TeamCity offers a DSL based on Kotlin and so we landed very fast on the <a href="https://blog.jetbrains.com/teamcity/2019/03/configuration-as-code-part-1-getting-started-with-kotlin-dsl/">blog series</a> describing these features.</p>
<p>This gets TeamCity through the door. It’s also a pretty cool taster for what Kotlin can do: the DSL looks clean and it looks like the web UI offers a way to get easily from clicked-together to code.</p>
<p>I have studiously ignored all the IDEA bait in those posts. You should not need code completion to put a few pipelines together (narrator: he was mostly wrong).</p>
<p>I have also skipped and jumped over the Maven references. Seriously, I have a pom allergy. It is probably going to bite me in the behind as soon as this system gets reasonably complicated and I am going to need tests, but it was all I could do to keep reading after my eyes brushed over that XML.</p>
<h2 id="reality-check">Reality check</h2>
<p>OK, I’m armed with Kotlin and I’ve got a TeamCity instance and I’ve got a project and I see that all the settings are version controlled. But they all go to this one repository somewhere beyond my reach.</p>
<p>It turns out you need pretty wide-reaching access rights to be able to activate versioned settings. Luckily, it took about 10 seconds of pointed question asking and:</p>
<p><img src="/images/AchievementUnlocked.png" alt="Achievement Unlocked" class="no-float" /></p>
<p>Seriously, I’m framing this - it was my fastest 0-to-admin time ever!</p>
<h2 id="get-off-my-master">Get off my master</h2>
<p>Turning on versioning for project settings has one drawback: Every time you change something in the web UI, Teamcity will commit the changes in the designated repository. And it does it on master.</p>
<p>Now, depending on the workflow you follow for your git usage this may be a good or a bad thing.</p>
<p>First, lets agree that in principle, no changes should be done in the UI. Also, that if, by any chance any changes are done in the UI, whatever we have in the repository should overwrite them.</p>
<p>This is rule of git acquisition number 23:</p>
<p><code class="language-plaintext highlighter-rouge">The repository comes first</code></p>
<p>So, when we set up versioning we set the appropriate option:</p>
<p><img src="/images/tc_no_ui_changes.png" alt="No UI changes allowed" class="no-float" /></p>
<p>Now, the comment accompanying the option gives me hope that things have been done properly.</p>
<p>The goal here is to have the build setup correspond to the state of the code base at the time of the commit you are building. The <a href="https://www.jetbrains.com/help/teamcity/storing-project-settings-in-version-control.html">docs</a> hit all the right notes for this setting. This remains to be tested.</p>
<p>As outlined in <a href="/software/2019/06/18/disaster-resistant-git">disaster resistant git</a> I recommend using pull requests on the quest to emulate trunk-based development.</p>
<p>This means that master is locked, changes are allowed only via pull request and there are merge checks that mandate a successfull build.</p>
<p>In the TeamCity context such a setup guarantees that no changes in the UI will be accepted. But it will generate a whole bunch of errors for anyone making changes.</p>
<p>It also makes it difficult to explore and experiment with options and see how they translate to DSL code. Doubly so, because not all options that change the settings offer a nice ‘View DSL’ button - for example adding NuGet Feeds</p>
<h2 id="playground">Playground</h2>
<p>Basically I have a playground repository with a scaffolded <a href="https://github.com/damphyr/gaudi">gaudi</a> that I can use to click things together. I think I already stumbled on a bug for a runner, so expect a post on community, support and bug reports.</p>
<p>I’ve already put a variant of the <a href="https://blog.jetbrains.com/teamcity/2019/04/configuration-as-code-part-3-creating-build-configurations-dynamically/">Configuration as Code, Part 3: Creating Build Configurations Dynamically</a> to good use and it has opened some interesting questions, so that will be the next post.</p>
</description>
<pubDate>Tue, 31 Mar 2020 14:15:21 +0200</pubDate>
<link>http://www.ampelofilosofies.gr/software/2020/03/31/adventures-in-kotlin-1</link>
<guid isPermaLink="true">http://www.ampelofilosofies.gr/software/2020/03/31/adventures-in-kotlin-1</guid>
</item>
<item>
<title>ForgetMeNot: Organized xUnit reports in Jenkins</title>
<description><p>One of the hackiest formats under wide adoption is the JUnit report format.</p>
<p>It is not really from JUnit, it’s from Ant. It is not really documented anywhere - some people try to figure it out by reading the source (after looking for it first in the JUnit sources - lots of fun following the different StackOverflow threads on this).</p>
<p>Given that there is no official schema or spec I am not surprised in the totally inconsistent behaviour of any tool claiming to read/write or understand the JUnit report format.</p>
<p>There is one particular hero <a href="https://twitter.com/WindyRoadTech">@WindyRoadTech</a>, who created <a href="https://github.com/windyroad/JUnit-Schema">an XSD schema</a>. What I am about to do will fail the schema validation (at the time of writing).</p>
<p>The problem with JUnit reports created by tools other than Ant is that the original implementation makes some assumptions.</p>
<p>These are that you are basically running Java and that your code is organized in Java packages, i.e. it has a format of Package.Something.Whatever.Class.</p>
<p>What Ant did was split the full class name of a testcase and add pieces of it as attributes to the <em>testsuite</em> and <em>testcase</em> elements of the report.</p>
<p>Time goes by, and all kinds of tools start using this JUnit format - I blame Jenkins and the JUnit report plugin for introducing people to pretty colors they could show other people.</p>
<p>More time went by, generations in Internet years. The JUnit plugin was too limited, so the xUnit plugin was born. This one could understand lots of report formats.</p>
<p>But the way the report is organized did not change. xUnit shows tests grouped in packages.
It figures out what to use as a package name by using the <em>classname</em> attribute of the <em>testsuite</em> elements</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;testsuite</span> <span class="na">name=</span><span class="s">"InterestingTests"</span> <span class="na">tests=</span><span class="s">"5"</span> <span class="na">failures=</span><span class="s">"0"</span> <span class="na">disabled=</span><span class="s">"0"</span> <span class="na">errors=</span><span class="s">"0"</span> <span class="na">time=</span><span class="s">"50.582"</span> <span class="na">timestamp=</span><span class="s">"2020-03-12T17:40:33"</span> <span class="na">classname=</span><span class="s">"Integration"</span><span class="nt">&gt;</span>
</code></pre></div></div>
<p>You would expect that all test cases within that element would be listed under that package. But no. Apparently the reporter parses the classname for <strong>each</strong> testcase and builds “packages” out of that.</p>
<p>So if you have a bunch of let’s say GTest tests and emit an XML report, all of your tests are going in the <em>Root</em> package, since, you know, no <em>Java</em> namespaces and one has to choose a default name (which GTest hard-codes).</p>
<p>What is a build enginneer to do, but post-process that XML report so that his team gets nicely categorized tests. No need for fancy code, brute force it in Ruby:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Rewrites (in place) an XML report produced by gtest to add a classname to testsuites and</span>
<span class="c1"># adapt the classnames to test cases.</span>
<span class="c1"># so that they sort nicely when presented by the xUnit plugin in Jenkins</span>
<span class="k">def</span> <span class="nf">classify_test_report</span><span class="p">(</span><span class="n">test_report</span><span class="p">,</span> <span class="n">test_class</span><span class="p">)</span>
<span class="n">content</span> <span class="o">=</span> <span class="no">File</span><span class="p">.</span><span class="nf">read</span><span class="p">(</span><span class="n">test_report</span><span class="p">)</span>
<span class="n">xml</span> <span class="o">=</span> <span class="no">Nokogiri</span><span class="o">::</span><span class="no">XML</span><span class="p">(</span><span class="n">content</span><span class="p">)</span>
<span class="n">suites</span> <span class="o">=</span> <span class="n">xml</span><span class="p">.</span><span class="nf">root</span><span class="p">.</span><span class="nf">xpath</span><span class="p">(</span><span class="s2">"//testsuite"</span><span class="p">)</span>
<span class="n">testcases</span> <span class="o">=</span> <span class="n">xml</span><span class="p">.</span><span class="nf">root</span><span class="p">.</span><span class="nf">xpath</span><span class="p">(</span><span class="s2">"//testcase"</span><span class="p">)</span>
<span class="n">testcases</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">entry</span><span class="o">|</span>
<span class="n">entry</span><span class="p">[</span><span class="s2">"classname"</span><span class="p">]</span> <span class="o">=</span> <span class="s2">"</span><span class="si">#{</span><span class="n">test_class</span><span class="si">}</span><span class="s2">.</span><span class="si">#{</span><span class="n">entry</span><span class="p">[</span><span class="s2">"classname"</span><span class="p">]</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span>
<span class="n">suites</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">entry</span><span class="o">|</span>
<span class="n">entry</span><span class="p">[</span><span class="s2">"classname"</span><span class="p">]</span> <span class="o">=</span> <span class="n">test_class</span>
<span class="k">end</span>
<span class="n">write_file</span><span class="p">(</span><span class="n">test_report</span><span class="p">,</span> <span class="n">xml</span><span class="p">.</span><span class="nf">serialize</span><span class="p">)</span>
<span class="k">return</span> <span class="n">test_report</span>
<span class="k">end</span>
</code></pre></div></div>
<p>That <em>write_file</em> comes from <a href="https://github.com/damphyr/gaudi">gaudi</a>, but, you know, it writes the file to disk.</p>
</description>
<pubDate>Thu, 12 Mar 2020 13:15:21 +0100</pubDate>
<link>http://www.ampelofilosofies.gr/software/2020/03/12/forgetmenot-xunit-reports</link>
<guid isPermaLink="true">http://www.ampelofilosofies.gr/software/2020/03/12/forgetmenot-xunit-reports</guid>
</item>
<item>
<title>ForgetMeNot: Pass values onwards in Azure Devops</title>
<description><p>Azure Devops has this really cool feature, where you can use specially formated stdout strings to pass different commands.</p>
<p>They are called <a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/scripts/logging-commands?view=azure-devops&amp;tabs=bash">logging commands</a> and by far the most useful of those is setvariable which allows us to set a variable in one task, that is then available as an environment variable in subsequent tasks:</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>
<span class="nb">echo</span> <span class="s2">"##vso[task.setvariable variable=testvar;]testvalue"</span>
</code></pre></div></div>
<p>A useful example for this:</p>
<p>Let us say we use <a href="https://gitversion.net/docs/">GitVersion</a> to alleviate the headache of versioning and we put together a pipeline to publish a Nuget package.</p>
<p>The <a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops">dotnet task</a> in Azure Devops (as well as the <a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/package/nuget?view=azure-devops#versioning-schemes">nuget task</a>) offers the byEnvVAr versioning scheme, which allows you to pass the desired version number in an environment variable.</p>
<p>Use you favourite scripting language to calculate the version number and a logging command, for example with bash</p>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="pi">-</span> <span class="na">script</span><span class="pi">:</span> <span class="s">echo "##vso[task.setvariable variable=THE_CORRECT_VERSION;]`GitVersion /output json /showvariable FullSemVer`"</span>
</code></pre></div></div>
<p>and then pack the Nuget package without worrying about the version:</p>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="pi">-</span> <span class="na">task</span><span class="pi">:</span> <span class="s">DotNetCoreCLI@2</span>
<span class="na">inputs</span><span class="pi">:</span>
<span class="na">command</span><span class="pi">:</span> <span class="s">pack</span>
<span class="na">packagesToPack</span><span class="pi">:</span> <span class="s2">"</span><span class="s">$(project)"</span>
<span class="na">arguments</span><span class="pi">:</span> <span class="s2">"</span><span class="s">--configuration</span><span class="nv"> </span><span class="s">$(buildConfiguration)"</span>
<span class="na">versioningScheme</span><span class="pi">:</span> <span class="s">byEnvVar</span>
<span class="na">versionEnvVar</span><span class="pi">:</span> <span class="s">THE_CORRECT_VERSION</span>
</code></pre></div></div>
</description>
<pubDate>Mon, 27 Jan 2020 13:15:21 +0100</pubDate>
<link>http://www.ampelofilosofies.gr/software/2020/01/27/forget-me-not-setvariable</link>
<guid isPermaLink="true">http://www.ampelofilosofies.gr/software/2020/01/27/forget-me-not-setvariable</guid>
</item>
<item>
<title>Published author...sort of</title>
<description><p>In the past year a group of Zühlke coleagues led by <a href="https://twitter.com/sypounentes">Christian Abegg</a> and <a href="https://twitter.com/peitor">Peter Gfader</a> put together a collection of articles about things we consider important with the aim of publishing them as a book.</p>
<p>That book is finally out!</p>
<p>The official blurb is</p>
<p><em>In «Machines – Code – People» readers learn about best practices, cultural philosophies, great ideas and practically proven concepts. In 50 short articles Zühlke engineers share what they are passionate about. You will find many useful tips from various areas of today’s tech industry. The range of topics covered includes the latest technical developments as well as collaboration topics and individual values and techniques.</em></p>
<p>You can buy the dead tree version on <a href="https://www.amazon.de/Machines-Code-People-engineers-passionate/dp/3748141181/ref=sr_1_1?__mk_de_DE=%C3%85M%C3%85%C5%BD%C3%95%C3%91&amp;keywords=machines+code+people&amp;qid=1561359217&amp;s=gateway&amp;sr=8-1">Amazon</a>, you can browse it for free <a href="https://zuehlke.github.io/machines-code-people/">online</a> or download one of the <a href="https://zuehlke.github.io/machines-code-people/articles/preface.html">e-book versions</a></p>
<p>I consider this a 70% step to crossing “be a published author” off the bucket list.</p>
<p>I am especially proud, not just because of my article in the book (it is an edited version of the <a href="/software/2014/07/17/vars-build-rules">build rules</a> post in this blog) but because I came up with a title the rest of the company found cool.</p>
<p>Taken verbatim from our internal discussion when deciding on the title:</p>
<p><em>It alludes (admittedly over-simplified, but what do you expect from a title) to the course Zuehlke has taken over the 50 years of its history: From building machines and electronics, to adding software and processes (code), innovation and business consulting which is ultimately people.</em></p>
<p><em>It also works as the three things we do best (if you put the people in the context of working with the machines and code ;) ).</em></p>
</description>
<pubDate>Wed, 26 Jun 2019 14:15:21 +0200</pubDate>
<link>http://www.ampelofilosofies.gr/software/2019/06/26/published-author</link>
<guid isPermaLink="true">http://www.ampelofilosofies.gr/software/2019/06/26/published-author</guid>
</item>
</channel>
</rss>