-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
1335 lines (952 loc) Β· 73.8 KB
/
index.html
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
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Hello there, stranger.</title>
<meta name="GENERATOR" content="Blackfriday Markdown Processor v1.5" />
<meta charset="utf-8" />
</head>
<body>
<h1>Hello there, stranger.</h1>
<h2>About</h2>
<p>This is a log of things I learn, experiment with, or think about.</p>
<h2 id="1596221294"><a href="index.html#1596221294">π</a> 1596221294 - 20200731</h2>
<h3>Becoming a Software Saboteur: Creating Questionable If-Statements</h3>
<p>Let’s use if-statements to sabotage some software by creating bugs and unmaintainable code.</p>
<h4>Compounding Problems with Multiple-Abstractions-Per-Line-of-Code</h4>
<p>Understanding the value of “One Abstraction per Line of Code” is necessary for undoing it, and undoing it is an essential prerequisite for all our sabotage via if-statements.</p>
<p>Think of many boolean variables, function calls, and conditions within an if-statement clause in the same way as you think of “magic-numbers” within a program.
Instead of labeling the magic-numbers with a variable that has <em>a name signifying the <strong>intent</strong> of usage</em> of the number, we can have an unamed raw number somewhere in the code. The equivalent with boolean logic is to call functions, perform comparrisons, and put other boolean operations within an if-statement clause itself.</p>
<p>Clean-code strives to be legible as a primary goal, and to not mix multiple-abstractions on a single line of code <a href="#1596221294_1">[1]</a>.</p>
<p>In this contrived example…</p>
<pre><code>var shouldPressGasPedal bool = trafficLight.isGreen() && !breakPedal.isPressed()
if (shouldPressGasPedal) {
driver.press(gasPedal)
}
</code></pre>
<p>…each line of code concerns itself with one thing (abstraction):</p>
<ol>
<li>Labeling (naming) a condition for its meaning</li>
<li>Executing control-flow (with a pre-established named condition)</li>
<li>Execution of an action (directly related to the named condition)</li>
</ol>
<p>If someone were to change the <code>gasPedal</code> variable to <code>brakePedal</code>…</p>
<pre><code>var shouldPressGasPedal bool = trafficLight.isGreen() && !breakPedal.isPressed()
if (shouldPressGasPedal) {
driver.press(brakePedal)
}
</code></pre>
<p>…the error is far too easy to see, because the helpfully named <code>shouldPressGasPedal</code> variable expresses intent of the if-statement while being so close (on the screen) to the <code>brakePedal</code> variable.</p>
<p>So, if someone has kept abstractions separate to each line of code, let’s undo their work.
Since our goal is to maximize <em>any</em> extra potential for bugs and unmaintainablility, we will change the code to:</p>
<pre><code>if (trafficLight.isGreen() && !breakPedal.isPressed()) {
driver.press(gasPedal)
}
</code></pre>
<p>The above change forces the code-reviewer to expend extra brain-power (no matter how little) to derive the intended meaning from the if-statement clause. For the same reason, a missing operator like <code>!</code> would be harder to spot.</p>
<p>We can justify the change by saying we’re decreasing the total lines of code. We can also claim the program is more memory-efficient by removing an unnecessary variable. Hopefully the code-reviewer is oblivious to how extremely efficient compilers are at optimizing away any performance cost.</p>
<p>However, the <em>far</em> more important reason for sabotaging the code this way is it serves as a critical foundation: Multiple-abstractions in the if-statement clause perfectly sets us up for creating arrow-code, which itself enables us to devolve the code in many more ways.</p>
<h4>Shoot for Arrows</h4>
<p>A reliable tactic is to nest if-statements as deeply as possible.
Our goal is to make arrow-code <a href="#1596221294_2">[2]</a> so that the code-reviewer can’t hold in their head what is going on.</p>
<p>If an if-statement clause has compounded boolean expressions, break the boolean expressions apart into multiple if-statements.</p>
<p>For example, this sabotaged code from the previous section…</p>
<pre><code>if (!brakePedal.isPressed() && trafficLight.isGreen()) {
driver.press(gasPedal)
}
</code></pre>
<p>…can become:</p>
<pre><code>if (trafficLight.isGreen()) {
if (!brakePedal.isPressed()) {
driver.press(gasPedal)
}
}
</code></pre>
<p>This is a critical first-step to creating bugs and code that can’t be maintained, reasoned about, or even executable.</p>
<p>Don’t worry though, we’ll have opportunity to reintroduce complex boolean expressions momentarily.</p>
<h4>Complect for Success</h4>
<p>If we already have nested if-statements in multiple places for totally separate reasons, we want to see if there’s a shared if-statement between those nested chunks and combine them.</p>
<p>This accomplishes the goals of not “separating concerns” and complecting (adding complexity) by braiding together different “strands” of code written for unrelated purposes, but <em>incindentally</em> share duplicate lines of code.</p>
<p>*The real trick here is to take things that serve totally different purposes and erroneously mix them together because they <strong>look</strong> similar.*</p>
<p>We’ll even be able to argue good software-engineering by using “DRY / Don’t Repeat Yourself” as an excuse for complecting unrelated code together.</p>
<p>As a contrived example, the following code…</p>
<pre><code>if (trafficLight.isGreen()) {
if (!brakePedal.isPressed()) {
driver.press(gasPedal)
}
}
if (!brakePedal.isPressed()) {
if (trafficLight.isRed()) {
driver.press(brakePedal)
}
}
</code></pre>
<p>…can be changed to:</p>
<pre><code>if (trafficLight.isGreen()) {
if (!brakePedal.isPressed()) {
if (trafficLight.isRed()) {
driver.press(brakePedal)
} else {
driver.press(gasPedal)
}
}
}
</code></pre>
<p>An astute reader will notice that the inner-most if-statement body will never execute, since a traffic light can’t be red and green at the same time. However, this is still a good act of sabotage because the code-reviewer will be forced to <em>think</em> in order to notice, and being able to notice the dead-code requires implicit knowledge of a traffic-light. Outside of this example, where a more complicated or obscure object is used instead a contrived traffic-light, we’re forcing the code-reviewer to have full knowledge of (of a possibly difficult-to-understand) object in addition to reading carefully.</p>
<h4>Compounding Problems with Defining by Negation</h4>
<p>We can still make things worse. If we create compound boolean expressions within the if-statement clause, and invert boolean values where-ever possible, we can make the erroneous if-statement nesting even harder to spot.</p>
<pre><code>if (!trafficLight.isYellow() && !trafficLight.isRed()) {
if (!brakePedal.isPressed()) {
if (!trafficLight.isYellow() && !trafficLight.isGreen()) {
driver.press(brakePedal)
} else {
driver.press(gasPedal)
}
}
}
</code></pre>
<p>Better yet, we can use this as an opportunity to nest the if-statements even further to achieve both deeper arrow code and complect another “strand” in this braid of code-complexity. All we have to do is notice two if-statement clauses that are for completely different purposes but happen to have a little bit of the same code.</p>
<p>In this case, let’s extract <code>!trafficLight.isYellow()</code> out of two if-statement clauses into a new, outter-most if statement:</p>
<pre><code>
if (!trafficLight.isYellow()) {
if (!trafficLight.isRed()) {
if (!brakePedal.isPressed()) {
if (!trafficLight.isGreen()) {
driver.press(brakePedal)
} else {
driver.press(gasPedal)
}
}
}
}
</code></pre>
<p>We can also justify this nesting, once again citing “DRY / Don’t Repeat Yourself” as a reason.
Also, we can claim that this is more performant since we’re not evaluating executing the same function (<code>trafficLight.isYellow()</code>) more than once. (Hopefully the code-reviewer hasn’t heard of “optimize second” or the “rule of threes”.)</p>
<p>Finally, we can claim robustness, since all this extra if-statements <strong>must</strong> mean that we’re checking every possible scenario before deciding to press the gas pedal, right?</p>
<h4>Create Distance with Irrelevance</h4>
<p>The code-reviewer may notice how the inner-most if-statement body will never execute, since a traffic light can’t be green and red at the same time. We’ve hopefully made it harder to notice by creating distance (on the screen) in lines of code between <code>trafficLight.isGreen()</code> and <code>trafficLight.isRed()</code>. If we can add more boiler-plate, irrelavant code, or unnecessary comments to the if-statement blocks, the extra distance will make the dead-code even harder to notice.</p>
<p>A foolproof tool is creating comments that redundantly explain what is already literally codified with the code. There’s also the extra benefit of comments becoming easily misplaced, unapplicable, irrelevant if the code changes and the comments aren’t updated.</p>
<pre><code>if (!trafficLight.isYellow()) {
if (!trafficLight.isRed()) {
if (!brakePedal.isPressed()) {
// Never press a gas pedal if the break pedal is already pressed.
driver.press(gasPedal)
if (!trafficLight.isGreen()) {
driver.release(gasPedal)
driver.press(brakePedal)
}
}
}
}
</code></pre>
<h4>Finally, Obtain Review by the Encumbered</h4>
<p>With any luck during code-review from the team, the college-intern will be too pre-occupied studying for midterms, the recent-grad junior-engineer will still be hungover from an over-indulgent happy hour the night before, the senior-engineer will be extremely sleep deprived from their new-born baby crying all night, and the team-lead / manager will be so bogged down with meetings that they’ll be both too-pressed-for-time and so-far-removed from ever touching the code-base, that we’ll get away with sabotaging some software.</p>
<p><fn id="1596221294_1">1. <a href="https://markhneedham.com/blog/2009/06/12/coding-single-level-of-abstraction-principle/">Coding: Single Level of Abstraction Principle</a></p></fn>
<p><fn id="1596221294_2">2. <a href="http://wiki.c2.com/?ArrowAntiPattern">Arrow Anti-Pattern</a></p></fn>
<h2 id="1596038377"><a href="index.html#1596038377">π</a> 1596038377 - 20200729</h2>
<h3>Enemy of the State, Part 1</h3>
<p>For the following piece of Java code (where we’ll substitute 1-to-N lower-case letter variable and method names are used in lieu of “foo” or “bar”):</p>
<pre><code>// 1-to-N lower-case letter variable and method names are used in lieu of βfooβ or βbarβ.
void m() {
o.mm(
new Object(),
mmm(500, 2000)
);
}
</code></pre>
<p>A reviewer asked me, “Could we just allocate <code>new Object()</code> once and just keep passing the same one in?”</p>
<p>This is a good question, and the answer is counter-intuitive: we don’t want to re-use the same object instance over-and-over in this case.</p>
<p>We get told many times in school or out-dated Java books <a href="index.html#1596038377_1">[1]</a> to “avoid allocating” and that “<code>new</code> is expensive”, which simply isn’t true in all cases and leads to problems if followed rotely.</p>
<p>The reasoning is:</p>
<ul>
<li>Objects are cheap.</li>
<li>The garbage collector is pretty smart these days (and will optimize clean-up in these cases).</li>
<li>We assess the risks for if it is worth holding onto state (variables / objects) for more than one use orfor beyond the current scope.</li>
</ul>
<p>If there is a performance problem such that we are performance tuning, and allocating new objects turns out to be the bottleneck, we’ll prefer to hold onto some variables that exist in a broader scope and try to never touch the allocator (i.e. by using <code>new</code> only once per variable).</p>
<p>Otherwise, especially with any sort threading code, it is best to have “clean slates” i.e. new (and preferrably) immutable objects each time we are calling a method that needs them. Stale-state increases the chance of bugs, and amongst the worst bugs involving stale-state can occur when multiple threads are erroneously trying to read or operate off the same variable (which may require different states for different threads in the same moment of concurrent execution).</p>
<p>Beyond that, I personally have little patience for noisy repitition in lines of code, such as <code>ObjectName objectName = new ObjectName();</code>, so if I can get away with just <code>new ObjectName()</code>, I do. It reads a ‘lil cleaner.</p>
<p>In summary, we’ll have more readable code and avoid bugs by greedily using the <code>new</code> keyword in attempts to have variables (objects) that are clean-slate, single use, and restricted to the smallest scope possible in our code. In specific (and somewhat rare) cases, we may not do this for performance reasons, but in general, we’ll avoid bugs caused by stale-state in our code.</p>
<p><fn id="1596038377_1">1. <a href="https://www.oreilly.com/library/view/java-performance-tuning/0596000154/ch04s02.html">Performance Tuning in Java</a> 2nd edition was published in 2003 and may be considered out-dated. It states at the beginning of Chapter 10 that “objects are expensive to create”, which could have been better worded (and future-proofed) as “objects have a cost to create”. The point of the above log entry is to highlight how the cost is relative and can lower over time (let’s say with improvements to the garbage-collector, increased hardware resources, etc.) such that the value of clean-code via ephemeral variables may well exceed the (increasingly cheaper) cost of object creation, in addition to following rules of readability of “optimize second”.</p></fn>
<h2 id="1570731778"><a href="index.html#1570731778">π</a> 1570731778 - 20191010</h2>
<p>There’s a configuration used sometimes in collusion with git submodules, or if writing a Go module that depends on an additional Go package in a private repository (thus tripping up <code>go get</code>’s ability to automatically download the dependency):</p>
<pre><code>[url "[email protected]:"]
insteadOf = https://github.com/
</code></pre>
<p>This <del>underhanded kludge</del> makeshift bandage for the original problem is harmful, as it breaks other programs, such as <code>cargo</code>’s ability to download dependencies<a href="https://github.com/rust-lang/cargo/issues/3381#issuecomment-392297524">[1]</a>. Using this workaronud with the <code>go</code> tool just remanifests a similar (but worse) problem with <code>cargo</code>!</p>
<p>I had this configuration myself, due to working with a 3rd party “monolithic” repository that utterly broke its promise to be monolithic by having a single, major dependency on an extenal, private GitHub repository. A monolithic repository with a single external dependency is no longer a monolithic repository! My solution is that I (thankfully) do not have to work with those repositories anymore and can delete the problematic <code>git</code> configuration.</p>
<p>However, the “real” fix for the original problem is to have the discipline and organization to use a monolithic repository. You may have to do a bit more easy and simple work, albeit monotonous, vendoring your own dependencies, but it will benefit you and your projects (and those around you) in the long haul.</p>
<h2 id="1569180707"><a href="index.html#1569180707">π</a> 1569180707 - 20190922</h2>
<p>TIL that <code>7z e <filename.7z></code> extracts the an archive file, but puts all contents “flat” into the current directory. This means that an entire archive’s directory tree of files (the leaves) are extracted into the working directory, possibly presenting naming conflicts amongst themselves or the possibility of overwriting existing files in the current directory. Alternatively, to “eXtract with full paths” intact from the archive, we have to use <code>7z x <filename.7z></code>.</p>
<p>This is counter-intuitive, since <code>7z a <file>...</code> <em>archives</em> a given set of files and directories, with full paths, so one would expect that <code>7z e <archive-filename></code> to <em>extract</em> files as they were added. Instead, we must use the cute <code>7z x</code> subcommand to do the symmetrically opposite function of <code>7z a</code> while breaking the convention of “subcommand is named after first letter of the function it represents.”</p>
<p>I feel like whoever designed this <code>x</code> vs <code>e</code> subcommand interface is the type of folks that would also design a two-button toilet flusher (where the buttons are on the top, like how some are built), but instead of those buttons being “light” and “heavy” flush, one button flushes and the other button shoots water in your face.</p>
<p>As in, why would anyone ever want it to do that? And if someone did, why would the interface designer not make more clearly contrasting buttons (or an entirely different mechanism)? All in all, its subtle failures in interface design that will surely be worked around on subsequent uses, but is designed in a way that is not friendly to first-time users.</p>
<h2 id="1564172640"><a href="index.html#1564172640">π</a> 1564172640 - 20190726</h2>
<p>It is both amusing and alarming to me that, still in 2019, GNU <code>sed</code> 4.5 does not support Unicode code-points as a delimeter:</p>
<pre><code>$ echo 'frosty the snowman' | /bin/sed 'sβfrostyβjack frostβ'
/bin/sed: -e expression #1, char 2: delimiter character is not a single-byte character
</code></pre>
<p>Plan9 to the rescue, though:</p>
<pre><code>$ echo 'frosty the snowman' | ~/plan9/bin/sed 'sβfrostyβjack frostβ'
jack frost the snowman
</code></pre>
<h2 id="1559949792"><a href="index.html#1559949792">π</a> 1559949792 - 20190607</h2>
<p>I’m aware that most programmers would not agree with me, but I believe that <a href="http://wiki.c2.com/?DontRepeatYourself">DRY</a> is a lie.</p>
<h3>DRY is a lie, part 1: dependencies</h3>
<p>I believe that copying a little bit of code is better than a tiny <a href="https://en.wikipedia.org/wiki/Coupling_(computer_programming)">dependency</a> on a 3rd-party software library.</p>
<p>A lot of code is open source, so we can copy it in the first place, but by copying it we are forced to examine only the pieces that we’ll really use, and how those pieces work. I reason this is a good thing, since there isn’t necessarily quality control on any open source project, we could stand to not just blindly trust the code of the library, and we may be able to prune down to a minimal amount of code to solve the problem at hand.</p>
<p>Additionally, the more dependencies we have on 3rd-party software library, the slower our build-time (and development feedback loop while actually coding) is going to be. We’ll also maybe need a tool that handles fetching and managing the 3rd-party library, which will likely increase the complexity of the project, if not also slowing down build-times. We won’t be able to build the project with just its source code, since we’ll have to fetch the 3rd-party libraries from the internet (usually via a build tool) in order to build a program.</p>
<p>For development projects like Android applications, depending on a 3rd-party library (or a lot of them) has an even higher cost, due to apps being only able to have a total of 65,000 functions until more complex build procedures are required.</p>
<p>So, in a lot of cases, I find the trade-offs simply aren’t worth it. That doesn’t mean I won’t use a 3rd-party library, but I’ll think if there is something simple I can do myself, or something small and simple I can just copy into my project before using a 3rd-party library. I’ll see if I can directly vendor the 3rd-party library and include it in my project (if it is not liable to change, or I don’t want changes).</p>
<h3>DRY is a lie, part 2: repeating code</h3>
<p>Programmers are often taught to identify when blocks code start repeating, and to extract the code (possibly abstracting it in the process) into a reusable function that may be called in lieu of repating the code blocks.</p>
<p>In practice, I’ll do this, but only when enforcing a “Rule of 3’s”. If I am repeating the same code twice, I’ll copy it. If I need to repeat that code (or something similar) a third time, then I’ll extract the code into a named function. I find its often hard to see what pattern is in the code and how to best abstract it (if at all) until there are 3 repeating insances of it. When needing to repeat the code block only once, I believe it is simpler to just copy it and extract and abstract later if ever needed an additonal time.</p>
<h3>DRY is a lie, part 3: type systems</h3>
<p>I include type definitions with this “Rule of 3’s” practice as well, where I will not abstract to a more general type or class (via composition) until the the same data is embedded the same way in a total of other 3 types or classes.</p>
<p>I avoid inheritence wherever possible, as I believe having repeat fields (or composition as described above) is a lesser evil than creating a complex hiearchy that a reader must keep in their head, because I, the author, could not be bothered to type something twice and instead made a bunch of classes inheriting from eachother.</p>
<p>I will instead embed types (classes) into others as named fields, favoring composition over inheritence (and using interfaces instead to describe behavior).
When it comes to inheritence, I believe DRY is a lie as well, since repeating code or function definitions within classes is a chore, but much simpler than coupling a bunch of types together via inheritence and forcing other programmers to remember it all.</p>
<h3>Conclusion</h3>
<p>Extracting and abstracting code as to not repeat it is useful and necessary in some contexts, but not all, and we could stand to not immediately create a function, type, or class on the first reuse of any code or data. We’ll often get the abstraction wrong without a 3rd example of usage.</p>
<p>When solving a problem, we could stand to not immediately searching for and using a third party library, and instead weigh all our options and the trade offs. If a little bit of code can be written to solve the problem simply and correctly, which is preferred to copying in someone else’s solution to the problem, which is preferred to copying in someone else’s entire library that has a solution to the problem, which is preferred to depending on someone else’s library that has a solution but requires a more complex build process or internet connection.</p>
<p>These are heuristics, and not laws, as is “DRY,” so when I see the “DRY” mantra being treated as a law, that is the context in which “DRY is a lie.”</p>
<h2 id="1559777525"><a href="index.html#1559777525">π</a> 1559777525 - 20190605</h2>
<h3>A Structured Query Language Story</h3>
<p>A programmer used to optimize reports (“stored-procedures” in individual SQL files) for a finance company. A whole team of 4 used to write and maintain those SQL files and schema but were disbanded. After some years and years of random people spot-editing the SQL files without holistically understanding them or the schema, and this thing called “algorithmic trading” becoming more popular, the hundred or so stored-proceduces (“sprocs”) could not finish running overnight. So, the programmer would get dropped in to clean up particular reports when needed, having taken a databases elective in undergrad.</p>
<p>The slowdowns in performance were often caused by:</p>
<ul>
<li><code>where</code> clauses with many <code>join</code> statements (over 4 or 5, approaching 10)</li>
<li><code>join</code> statements on table columns that were not indexed</li>
<li>many subselect statements (sometimes nested) in <code>where</code> clauses</li>
</ul>
<p>Some take-aways from optimizing lots of those sprocs were:</p>
<ul>
<li>It is hard to know exactly where things are slowing down until you look at the “execution plan” output of the database engine, and see what is paging, etc.</li>
<li>Rethink the schema and table definitions. Sometimes new tables need to be created for data this is commonly joined together where clasues.</li>
<li>If the same joins are happening in subsequent queries, do the query once and store results in a cache table (if you can’t redefine the schema as per above).</li>
</ul>
<p>All in all, the programmer learned that database implementation details are magic, but optimizing SQL is not.</p>
<h2 id="1559320529"><a href="index.html#1559320529">π</a> 1559320529 - 20190531</h2>
<p>Comments are lies waiting to happen, but documentation is useful.</p>
<p>However, incorrect documentation can be useless, or arguably more harmful than not documentation at all.</p>
<p>Consider this documentation snippet from the AWS SNS Go SDK:</p>
<pre><code>// Input for Publish action.
type PublishInput struct {
// ...
// This struct definition is abridged by aoeu, with prior fields omitted.
// ...
// Either TopicArn or EndpointArn, but not both.
//
// If you don't specify a value for the TargetArn parameter, you must specify
// a value for the PhoneNumber or TopicArn parameters.
TargetArn *string `type:"string"`
// The topic you want to publish to.
//
// If you don't specify a value for the TopicArn parameter, you must specify
// a value for the PhoneNumber or TargetArn parameters.
TopicArn *string `type:"string"`
}
</code></pre>
<p>Either a “TopicArn” or an “EndpointArn,” but not both.</p>
<p>As it turns out, “EndpointArn” isn’t an actual field, and the comment probably meant to say,
“Either TopicArn or TargetArn must be set, but not both.” But maybe the field sohuld be renamed
from “TargenArn” to “EndpointArn” because the rest of the file seems to refer to that value with
fields named “EndpointArn.”</p>
<p>So what we have here is documentation that incorrectly names the actual field it is documenting.
That isn’t good, and actually led me to run around the API and file to see if I was missing something,
only to find I was misinformed by the documentation.</p>
<p>Documentation errors like this make programming harder, as does alternate solutions to the original problem,
such as maybe using one field for ARN (and having the SDK figure out what type of ARN it is), or a different
field used to specify what the ARN type is (let’s say with <code>const</code>s for the types declared with <code>iota</code>)
while simultaneously having having one field for the ARN value).
Nevermind the total disregard to an extremely fundamental Go idiom of using consistent capitalizaton for acronyms.</p>
<p>All of this in combination makes coding for AWS with Go harder than it needs to be.</p>
<h2 id="1559146238"><a href="index.html#1559146238">π</a> 1559146238 - 20190529</h2>
<p>I have often heard people say that it is faster to do many similar edits to some lines of code by hand.
Maybe they will record a squence of keys (a macro) via their text editor to help increase speed.
I prefer to use regular expressions to make edits to existing code.</p>
<p>I reason that many people could do many similar edits faster than I can by hand, but I often make mistakes
when typing prose (and prose-like code), and then pay more time later at compile-time or run-time and have to go fix the mistakes.
Also, a person can get a lot faster at finding and editing text via regular expressions by actually using regular expressions to find and edit the text. The speed and the ability to stream-of-conciousness type a complex regular expression correctly will never be obtained without practice.</p>
<p>I’ve even been asked to do edits like this in a programming interview in front of a real computer and editor, with the interviewer hinting at it is faster to make the edits by hand. That might be the case in one-off instances, or in an interview where it is easier to even typo a regular expression</p>
<p>With all of this in mind, I really like tiny, quick, regular-expression victories. The following is one that I did today, in seconds. (This write up took many times longer.)</p>
<p>Input:</p>
<pre><code> flag.StringVar(&args.inputFilepath, "in", "", "filepath to read report data from instead of SFTP download")
flag.StringVar(&args.outputFilepath, "out", "", "filepath to write report data to from SFTP download")
flag.BoolVar(&args.printSummary, "summarize", false, "Print output from main function that may be useful for debugging")
flag.BoolVar(&args.writeToDB, "store", true, "Apply found restrictions on users to database")
flag.BoolVar(&args.ignoreUnknownUsers, "dev", false, "Ignore unknown users on development server")
</code></pre>
<p>Regexp (first try, no backspacing):</p>
<pre><code> Edit .s/(flag.*)Var\(&args\.([a-zA-Z]+), (.*)/\2 = \1(\3/g
</code></pre>
<p>Output:</p>
<pre><code> inputFilepath = flag.String("in", "", "filepath to read report data from instead of SFTP download")
outputFilepath = flag.String("out", "", "filepath to write report data to from SFTP download")
printSummary = flag.Bool("summarize", false, "Print output from main function that may be useful for debugging")
writeToDB = flag.Bool("store", true, "Apply found restrictions on users to database")
ignoreUnknownUsers = flag.Bool("dev", false, "Ignore unknown users on development server")
</code></pre>
<h2 id="1540425237"><a href="index.html#1540425237">π</a> 1540425237 - 20181024</h2>
<p>Today, in regular expressions, we observe how to change all of one type of questionable lambda syntax to another questionable lambda syntax:</p>
<p><code>$ rg '\([a-z]+\) \-> [a-z]' -l | xargs sed -i '' -E 's/\(([a-z]+)\) -> ([a-z])/\1 -> \2/g'</code></p>
<p>Changes text like</p>
<pre><code>oneWayWouldBeBetter((foo) -> callback());
</code></pre>
<p>to</p>
<pre><code>oneWayWouldBeBetter(foo -> callback());
</code></pre>
<p>for an entire project.</p>
<h2 id="1540423346"><a href="index.html#1540423346">π</a> 1540423346 - 20181024</h2>
<p>I didn’t realize there were no less than 3 different syntax for the same semantic of declaring a lambda in Java 8 (and above)</p>
<p><code>set(this::callback); // no args</code><br />
<code>set(foo -> callback()); // one arg</code><br />
<code>set((foo, bar) -> callback()); // two args</code></p>
<p>And we can also throw in some varying ways of doing the same things:</p>
<p><code>set(()->callback()); // no args</code><br />
<code>set((Foo f, Bar b) -> callback()); // two args</code></p>
<p>…all as opposed to one way of doing it that handles all cases. Equally interesting as it is horrifying.</p>
<p>By horrifying, I mean that a major ingredient of Good software engineering is consistency, and here we have all these little possible inconsistencies baked into one language feature, each a thing to possibly trip up muscle memory when typing, or the eyes of the reader.</p>
<h2 id="1531345423"><a href="index.html#1531345423">π</a> 1531345423 - 20180711</h2>
<p>I was able to leverage git to find the name of a branch where I could vaguely remember when I wrote a bugfix, but not exactly what the bugfix was for, nor the name of the branch.</p>
<p>I suddenly had a need for a bugfix I had written in the process of reviewing of someone else’s code.<br />
(I needed to confirm that the solution I was going to suggest in the code review did indeed actually work.)</p>
<p>The other person’s code review was eventually closed, and I forgot about my bugfix branch, until the issue suddenly came up again, in another code review, by a different person!</p>
<p>All I could remember is that I had sketched out a fix for this bug before, on some branch, toward the end of 2017.<br />
Fortunately, I name my branches in the format of <code><github-username>.<type-of-change>.<name></code>, i.e. <code>aoeu.bugfix.redundant-user-prompt</code>, so I was able to leverage <code>git for-each-ref</code> to:</p>
<ul>
<li>print each git branch in the repo descending by commit date (via the <code>--sort</code> flag)</li>
<li>print the name and most recent commit date of each branch the repo (via the <code>--format</code> flag)</li>
<li>filter down to branches I wrote that were bugfixes in 2017 (via the <code>grep</code> command and my branch naming scheme)</li>
<li>filter down to only the last branches committed to in late 2017 (via <code>head</code> command)</li>
</ul>
<h4>Sorting all git branches descending by last commit date and printing the branch name:</h4>
<pre><code>git for-each-ref --sort=-committerdate refs/heads --format '%(committerdate) %(refname)' | grep aoeu.bugfix | grep 2017 | head -20
</code></pre>
<h2 id="1525816236"><a href="index.html#1525816236">π</a> 1525816236 - 20180508</h2>
<p>I could not install <a href="https://research.swtch.com/vgo">vgo</a> as part of its <a href="https://research.swtch.com/vgo-tour">tour</a>, ironically because my system didn’t meet the minimum version requirement of Go 1.10, and more specifically (and more ironically) because the Go 1.9 was a mere 4 days before a commit needed for <code>vgo</code>!</p>
<pre><code>$ go get -u golang.org/x/vgo
# golang.org/x/vgo/vendor/cmd/go/internal/modfetch/gitrepo
/opt/ir/src/golang.org/x/vgo/vendor/cmd/go/internal/modfetch/gitrepo/fetch.go:404:21: r.File[0].Modified undefined (type *zip.File has no field or method Modified)
$ go version
go version go1.9 darwin/amd64
$ cd $GOROOT; git log -1 --pretty='%cd %H %s'
Thu Aug 24 20:52:14 2017 +0000 c8aec4095e089ff6ac50d18e97c3f46561f14f48 [release-branch.go1.9] go1.9
$ git checkout master
$ git blame -L `egrep -n 'Modified\s+time.Time' $GOROOT/src/archive/zip/struct.go | cut -d: -f1`,+1 $GOROOT/src/archive/zip/struct.go
6e8894d5ffc (Joe Tsai 2017-08-28 12:07:58 -0700 119) Modified time.Time
</code></pre>
<h2 id="1525813299"><a href="index.html#1525813299">π</a> 1525813299 - 20180508</h2>
<p>I was able to get a tiny, tiny code change merged into <a href="https://github.com/google/gvisor">gVisor</a>.</p>
<p>Taking reading David Walsh’s <a href="https://davidwalsh.name/conquering-impostor-syndrome">article</a> about conquering Imposter Syndrome, I decided to try achieving a “little win.”</p>
<p>Later the same day, I was reading documentation in the newly published <a href="https://github.com/google/gvisor">gVisor source code</a> and saw a typo. I had to use Gerrit at work for years, so after a bit of configuring I was able to create <a href="https://gvisor-review.googlesource.com/c/gvisor/+/1820">a code review</a> that was later merged as a github <a href="https://github.com/google/gvisor/commit/4394b31dbbe276440891de0d8ee66bc5209400f1">pull request</a>.</p>
<h2 id="1523383234"><a href="index.html#1523383234">π</a> 1523383234 - 20180410</h2>
<p>My trusty ASUS 10.1 inch Chromebook Flip has been a solid machine for writing golang code and <a href="https://github.com/aoeu/gosh">my command line tools</a> on 30 minute train commute, and even DJing an entire hours-long set via crouton, XFCE, MIXXX, a FiiO USB DAC used simulatenously with the built-in audio card, and one of my MID controllers.</p>
<p>The screen chassis is now taped together from all the rough weather it has withstood. I thought I’d try upgrading with:</p>
<pre><code>$amsung 12.3" QHD Touchscreen Chromebook-Plus
$349.99
Sold by W00t, Inc.
Condition: Factory Reconditioned
Screen Size: 12.3"
</code></pre>
<p>I liked the USB-C ports, the stylus, the 4:3 screen ratio with really nice resolution and colors, and the all aluminum body.</p>
<p><a href="https://twitter.com/traverser/status/982617066388770816">I didn’t like</a> the “phantom input” on the touch-screen, and apparently I wasn’t the only one with this problem according to <a href="https://us.community.samsung.com/t5/Computers/Chromebook-plus-touchscree-issue/td-p/77098/page/4">10 pages of issues on the support forums</a>.</p>
<p>So, back from whence it came. Holding and typing on my ASUS Flip again, it somehow feels more sturdy and nicer to type anyway, all while being more portable and cheaper. It’d just be nice to have some faster USB ports and more RAM….</p>
<h2 id="1507682244"><a href="index.html#1507682244">π</a> 1507682244 - 20171010</h2>
<p>I was recently at a technology conference where there was <a href="https://chris.banes.me/dcnyc17">a talk</a> on Android apps, <a href="https://duckduckgo.com/?q=android+status+bar&t=ffab&iar=images&iax=1&ia=images&iai=http%3A%2F%2Ftechviral.com%2Fwp-content%2Fuploads%2F2015%2F12%2FAdd-Network-Speed-indicator-in-Android-Status-Bar.jpg">the Android status bar</a>, “no bezel” smartphones (like the <a href="http://phandroid.com/2017/07/31/essential-phone-status-bar/">PH-1</a>), and how these things collide into a user-facing problem for some Android apps.</p>
<p>The speaker cleary explained the “what” and the “why,” but not a complete example of “how” for the solution.</p>
<p>The catalyst of the problem is when an Android app:</p>
<ul>
<li>doesn’t have an <a href="https://developer.android.com/training/appbar/index.html">app bar</a>.</li>
<li>has a background-image (xor header image), that draws some fancy stuff behind a transparent status bar, and fills up the space where the app bar would normally be.</li>
<li>has a custom app bar (made only from core widgets like LinearLayout, TextView, and ImageView, possibly due to difficulties with the API-provided <a href="https://stackoverflow.com/search?q=app+bar+%5Bandroid%5D">app bar</a> / <a href="https://stackoverflow.com/search?q=action+bar+%5Bandroid%5D">action bar</a> and what can go wrong with using Compat and Support libraries, but worthy of a disparate argument for simplicity).</li>
</ul>
<p>The <a href="https://photos.app.goo.gl/qZyZ9xwKFya602xs1">explicitly discouraged soultion</a> is to hard-code the size of the status bar in layout files, even as an identified dimenion used across multiple layout files:</p>
<pre><code>> find . -name 'dimens.xml' | xargs grep status_bar
<dimen name="status_bar_height">24dp</dimen>
<dimen name="app_bar_height_plus_status_bar_height">80dp</dimen>
<dimen name="header_photo_height_plus_status_bar_height">224dp</dimen>
<dimen name="negative_status_bar_height">-24dp</dimen>
> # You aren't supposed to hardcode status bar values like this Android resource XML files.
</code></pre>
<p>The <a href="https://photos.app.goo.gl/VYcHBZcUESYTTYYb2">recommended solution</a> is to obtain the status bar height at runtime and apply it to the relevant view. If you have to do that in Java, here is a complete example:</p>
<pre><code>class TransparentStatusBarHaver extends Activity {
@Nullable View viewThatSitsBelowTheTransparentStatusBar;
public void onCreate(Bundle stuff) {
super.onCreate(stuff);
setContentView(R.layout.activity_with_transparent_status_bar);
viewThatSitsBelowTheTransparentStatusBar = findViewById(R.id.view_that_sits_below_transparent_status_bar);
}
// Set heights that compensate for a transparent status bar
// in onPostCreate(...) instead of onCreate(...) since descendant activity classes
// get a chance to call setContentView(...) in their own onCreate(...) method.
public void onPostCreate(Bundle stuff) {
super.onPostCreate(stuff);
if (viewThatSitsBelowTheTransparentStatusBar == null) {
return;
}
ViewCompat.setOnApplyWindowInsetsListener(viewThatSitsBelowTheTransparentStatusBar,
new android.support.v4.view.OnApplyWindowInsetsListener() {
@Override
public WindowInsetsCompat onApplyWindowInsets(
View view,
WindowInsetsCompat windowInsetsCompat) {
int statusBarHeightInPixels = windowInsetsCompat.getSystemWindowInsetTop();
int currentHeightOfViewInPixels = view.getLayoutParams().height;
view.getLayoutParams().height = statusBarHeightInPixels + currentHeightOfViewInPixels;
view.setLayoutParams(view.getLayoutParams());
view.setPadding(
view.getPaddingLeft(),
statusBarHeightInPixels,
view.getPaddingRight(),
view.getPaddingBottom()
);
return windowInsetsCompat;
}
}
);
}
}
</code></pre>
<p>I was at the original talk, squinted through the Kotlin pseudo-code, looked up the docs myself, and wrote the above example, and it is <strong>still</strong> hard to understand the above code (or why it exists) at a glance.<br />
So this solution gives us the “how,” but then obfuscates the “why” that was so well explained in the talk.</p>
<p>To help convey what is going on and why, I tried distilling the code by using named-methods and named-parameters to provide a little more clarity to the anonymous-classes, unexpectedly-named interfaces, and verbose Android API calls:</p>
<pre><code>class TransparentStatusBarHaver extends Activity {
@Nullable View viewThatSitsBelowTheTransparentStatusBar;
public void onCreate(Bundle stuff) {
super.onCreate(stuff);
setContentView(R.layout.activity_with_transparent_status_bar);
viewThatSitsBelowTheTransparentStatusBar = findViewById(R.id.view_that_sits_below_transparent_status_bar);
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
StatusBarMeasurer.addHeightForTransparentStatusBar(viewThatSitsBelowTheTransparentStatusBar);
}
}
public class StatusBarMeasurer implements OnApplyWindowInsetsListener {
static public void addHeightForTransparentStatusBar(final View viewBelowStatusBar) {
if (viewBelowStatusBar == null) {
return;
}
ViewCompat.setOnApplyWindowInsetsListener(viewBelowStatusBar, new StatusBarMeasurer());
}
@Override
public WindowInsetsCompat onApplyWindowInsets(View view, WindowInsetsCompat windowInsetsCompat) {
onStatusBarMeasured(view, windowInsetsCompat);
return windowInsetsCompat;
}
private void onStatusBarMeasured(View viewBelowStatusBar, WindowInsetsCompat windowInsetsCompat) {
int statusBarHeightInPixels = windowInsetsCompat.getSystemWindowInsetTop());
incrementHeight(viewBelowStatusBar, statusBarHeightInPixels);
incrementTopPadding(viewBelowStatusBar, statusBarHeightInPixels);
}
public static void incrementHeight(View v, int additionalHeightInPixels) {
int currentHeightInPixels = v.getLayoutParams().height;
v.getLayoutParams().height = currentHeightInPixels + additionalHeightInPixels;
v.setLayoutParams(v.getLayoutParams());
}
public static void incrementTopPadding(View v, int additionalPaddingInPixels) {
v.setLayoutParams(v.getLayoutParams());
v.setPadding(v.getPaddingLeft(), additionalPaddingInPixels, v.getPaddingRight(), v.getPaddingBottom());
}
}
</code></pre>
<p>That’s a bit easier for me to follow, but I do wonder:</p>
<ul>
<li>Why isn’t there an Android API call that just returns the status bar height?</li>
<li>Why does the programmer have to know about WindowInsets, support libraries, and WindowInsetsCompat shim-code to implement the suggested solution?</li>
<li>Why is it so easy for programmers to get bit by Android, status bars, transparent status bar, and unexpected side-effects in the first place?</li>
</ul>
<h2 id="1496155760"><a href="index.html#1496155760">π</a> 1496155760 - 20170530</h2>
<p>I recently rediscovered <a href="http://justinhileman.info/article/git-pretty/">this helpful and entertaining flow-chart diagram, titled <em>git pretty</em>,</a> that starts with: “So, you have a mess on your hands.”</p>
<h2 id="1487031425"><a href="index.html#1487031425">π</a> 1487031425 - 20170213</h2>
<p><a href="https://github.com/Benjamin-Dobell/Heimdall">Heimdall</a> has instructions to build with dependent libraries installed via <a href="https://brew.sh">homebrew</a>.
Heimdall can also be built with the the dependent libraries installed via <a href="https://www.macports.org">macports</a>, but with some <a href="https://en.wikipedia.org/wiki/Kludge">kludging</a>.</p>
<p>Assuming that macports installs libraries under ‘/opt/local/lib’ (e.g. the default for macports):</p>
<pre><code>$ git clone [email protected]:Benjamin-Dobell/Heimdall.git
$ cd Heimdall
$ tail OSX/README.txt | grep 'brew install' | sed 's/brew/port/g'
$ sudo port install libusb qt5 cmake
$ mkdir build
$ cd build
$ cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DQt5Widgets_DIR=`find /opt/local/lib -name 'Qt5Widgets'` ..
$ echo "A linker error will happen during `make` that looks like this:"
$ cat << EOF
[ 53%] Linking CXX executable ../bin/heimdall
ld: library not found for -lusb-1.0
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [bin/heimdall] Error 1
make[1]: *** [heimdall/CMakeFiles/heimdall.dir/all] Error 2
make: *** [all] Error 2
EOF
$ make
$ cat heimdall/CMakeFiles/heimdall.dir/link.txt | sed 's/\(-lusb-1.0\)/-L\/opt\/local\/lib \1/'
$ cd heimdall && /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ -std=gnu++11 -O3 -DNDEBUG -Wl,-search_paths_first -Wl,-headerpad_max_install_names CMakeFiles/heimdall.dir/source/Arguments.cpp.o CMakeFiles/heimdall.dir/source/BridgeManager.cpp.o CMakeFiles/heimdall.dir/source/ClosePcScreenAction.cpp.o CMakeFiles/heimdall.dir/source/DetectAction.cpp.o CMakeFiles/heimdall.dir/source/DownloadPitAction.cpp.o CMakeFiles/heimdall.dir/source/FlashAction.cpp.o CMakeFiles/heimdall.dir/source/HelpAction.cpp.o CMakeFiles/heimdall.dir/source/InfoAction.cpp.o CMakeFiles/heimdall.dir/source/Interface.cpp.o CMakeFiles/heimdall.dir/source/main.cpp.o CMakeFiles/heimdall.dir/source/PrintPitAction.cpp.o CMakeFiles/heimdall.dir/source/Utility.cpp.o CMakeFiles/heimdall.dir/source/VersionAction.cpp.o -o ../bin/heimdall ../libpit/libpit.a -L/opt/local/lib -lusb-1.0
$ ../bin/heimdall version
$ echo "Thus concludes the kludge." && \
cp ../bin/heimdall $SOME_DIRECTORY_IN_YOUR_PATH_WHERE_YOU_KEEP_BINARIES/heimdall
</code></pre>
<h2 id="1486765292"><a href="index.html#1486765292">π</a> 1486765292 - 20170210</h2>
<p>Searching for edits of a file, by name, through a range of git commits:</p>
<pre><code>#!/bin/sh
for arg in "$@"
do
case $arg in
-for=*)
filename="${arg#*=}"
;;
-from=*)
startSHA="${arg#*=}"
;;
-to=*)
endSHA="${arg#*=}"
;;
esac
done
test '' = "$endSHA" && endSHA="HEAD"
for sha in `git log --pretty="%H" $startSHA..$endSHA` ; do git diff-tree --no-commit-id --name-only -r $sha | grep "$filename" && echo "$filename was editied in commit $sha"; done
</code></pre>
<p>Usage:</p>
<pre><code>search-git-for-edits -of='some_image_file.png' -from=a93b5f746bdb1e0054dbb7e37fdfcd84a73d7f85 -to=HEAD
</code></pre>
<h2 id="1486426704"><a href="index.html#1486426704">π</a> 1486426704 - 20170206</h2>
<p>Debugging animations within an Android app can be tricky, especially if there is a sufficient “callback casserole” of asynchronous server requests, click listeners, and animation listeners all swirled together.</p>
<p>A trick that helped me debug how and when callback methods were getting called was just a one-liner log statement:</p>
<pre><code>// Placed in various click-listener callbacks, asyncronous server request callbacks, and animation listener callbacks:
android.util.Log.e("aoeu", Log.getStackTraceForString(new Exception));
</code></pre>
<p>Monitored with:</p>
<pre><code>adb logcat '*:E' | grep aoeu
</code></pre>
<p>While logging stack-traces doesn’t provide knowledge of what data was being input into methods, it was extremely useful to see how, in real-time, various callbacks were calling eachother without putting log statements in each method or stopping the world with a debugger.</p>
<h2 id="1485561815"><a href="index.html#1485561815">π</a> 1485561815 - 20170127</h2>
<p>At the moment, certain computers have USB-C ports while many Android devices do not.<br />
In attempts to not carry around <a href="https://en.wikipedia.org/wiki/USB-C">USB-C</a> to <a href="https://en.wikipedia.org/wiki/USB#Mini_and_micro_connectors">USB-Micro-B </a> converters, I thought that the <a href="https://en.wikipedia.org/wiki/Android_software_development#ADB">Android Debug Bridge</a> tool might be a practical replacement when run in a <a href="https://developer.android.com/studio/command-line/adb.html#wireless">wireless mode</a> that utilizes TCP/IP.</p>
<p>I was wrong.</p>
<p>The dance to boostrasp a computer to use Android Debug Bridge to communicate wirelessly to an Android device (starting out connected via a USB cable, but unplugged after) seemed straight-ahead enough.<br />
I found that arbitrary pauses in between <code>adb</code> commands were required in order to allow the Android Debug Bridge server to restart or reconfigure:</p>
<pre><code>#!/bin/sh
adb usb && \
sleep 2 && \
test `adb devices | wc -l` -gt 1 && \
TCPIP_PORT=5555 && \
sleep 2 && \
adb tcpip $TCPIP_PORT && \
sleep 2 && \
DEVICE_IP=$(adb shell ip -f inet addr show wlan0 | grep inet | sed 's/^.*\([0-9]\{3\}\.[0-9]\{3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\)\/24.*$/\1/') && \
adb connect $DEVICE_IP:$TCPIP_PORT
</code></pre>
<p>I then found that transferring a 21 megabyte file proved to be relatiely slow:</p>
<pre><code>$ time adb install -r molasses.apk
[100%] /data/local/tmp/molasses.apk
pkg: /data/local/tmp/molasses.apk
Success
real 3m40.721s
</code></pre>
<p>If doing the napkin-math correctly, that’s a transfer rate of approximately 0.763 megabits per second.</p>
<p>That’s also an order of magnitude (11 times) slower than installing the same file over USB:</p>
<pre><code>$ adb usb
restarting in USB mode
$ time adb install -r molasses.apk
[100%] /data/local/tmp/molasses.apk
pkg: /data/local/tmp/molasses.apk
Success
real 0m19.989s
</code></pre>
<p>Technically, the wireless router could be part of the slow-down, but I doubt it.<br />
So, why is <code>adb</code> over TCP/IP so slow?</p>
<h2 id="1485388140"><a href="index.html#1485388140">π</a> 1485388140 - 20170125</h2>
<p>Today I learned that certain built-in shell commands, such as <code>echo</code> and <code>export</code>, <a href="http://www.grymoire.com/Unix/Sh.html#uh-14">can be validly executed on the same line</a>, without a semi-colon separating the statements.
I found some resulting commands I tried out did not result in what I expected.</p>
<pre><code>sh-3.2$ NUMS=ONE
sh-3.2$ echo $NUMS
ONE
sh-3.2$ NUMS="$NUMS, TWO" export NUMS
sh-3.2$ echo $NUMS
ONE, TWO
sh-3.2$ NUMS="$NUMS, THREE" echo $NUMS
ONE, TWO
sh-3.2$ NUMS="$NUMS, THREE" export NUMS; echo $NUMS
ONE, TWO, THREE
sh-3.2$ NUMS="$NUMS, FOUR" echo $NUMS; export NUMS
ONE, TWO, THREE
sh-3.2$ echo $NUMS
ONE, TWO, THREE
sh-3.2$ NUMS="$NUMS, FOUR"; export NUMS
sh-3.2$ echo $NUMS
ONE, TWO, THREE, FOUR
</code></pre>
<p>Additionally, the PATH environment variable automatically exports when setting it to a new value within a shell script:</p>
<pre><code>$ cat path.sh
#!/bin/sh
overridePATH() {
PATH='export is not required.'
}
overridePATH
echo $PATH
$ ./path.sh
export is not required.
</code></pre>
<h2 id="1437014448"><a href="index.html#1437014448">π</a> 1437014448 - 20150715</h2>
<p>I wanted to install a gerrit server in order to do some code review for a friend, and thought an instance on a certain cloud hosting provider could be of service.</p>
<p>I ended up realizing that I was locked out of the server instance. I had ssh access disabled for the root user, so adding my public SSH key to the provider’s admin panel proved to be useless.</p>
<p>The provider features a web-browser-based VNC console, but with some limitations. The web-browser-based console can not handle copy-paste commands from the user’s machine. I wasn’t about to type my entire public RSA key out by hand. A workaround was needed:</p>
<ul>
<li>Reset root password on the remote server instance via an email authentication tool on the provider’s host administration web-application.</li>
<li>Log in as the root user on the remote server instance via the provider’s web-browser-based VNC console</li>
<li>Change root password (as forced by the remote server instance)</li>
<li><code># su - otheruser</code></li>
<li><code>$ mkdir ~/.ssh</code></li>
<li><code>$ chmod 700 ~/.ssh</code></li>
<li>On my local machine: <code>$ cat ~/.ssh/id_rsa.pub</code></li>
<li>Paste the contents of <code>id_rsa.pub</code> into a Github gist</li>
<li>Copy the raw URL of the Github gist</li>
<li>Paste the raw URL of the Github gist into <a href="http://tiny.cc`s">http://tiny.cc`s</a> web interface</li>
<li>Give the tiny.cc URL a reasonable name to type, like <a href="http://tiny.cc/publickeyfoo">http://tiny.cc/publickeyfoo</a></li>
<li>In the hosting provider’s web-browser-based VNC console: <code>$ wget -o ~/.ssh/authorized_keys http://tiny.cc/publickeyfoo</code></li>
<li><code>$ chmod 600 ~/.ssh/authorized_keys</code></li>
<li><code>$ exit</code> to return to the root user</li>
<li><code># sudo echo "PermitRootLogin no" >> /etc/ssh/ssh_config</code></li>
<li>On my local machine, <code>$ ssh [email protected]</code> (where example.com is the hostname for my remote server instance at the hosting provider).</li>
</ul>
<p>… And back in action. This would have been easier if the web-browser based VNC console wasn’t randomly inserting control keys or otherwise locking upwhen typing all the commands!</p>
<h2 id="1434415672"><a href="index.html#1434415672">π</a> 1434415672 - 20150615</h2>
<p>While peer reviewing an article involving Git packfiles,
I found interesting usage of SHA-1 hash values.</p>
<p>Git hashes a <code>.pack</code> packfile with SHA-1 and then uses the hash value for 3 things:</p>
<ul>
<li>The hash value is as a 20-byte trailer to the <code>.pack</code> file itself for later use as a checksum.</li>
<li>The hash value is used within the file name of the <code>.pack</code> file.</li>
<li>The hash value is used within the file name of the corresponding <code>.idx</code> file.</li>
</ul>
<p>I thought the usage in filenames was interesting.</p>
<p>I wrote a small shell script to demonstrate it all:</p>
<pre><code>
#!/bin/sh
main() {
cd $1/.git/objects/pack
hash_value_in_filename=`ls pack-*.pack | sed 's/pack-\(.*\).pack/\1/'`
hash_value_in_file=`tail -c 20 pack-*.pack | hexdump -ve '1/1 "%.2x"'`
hash_value_of_file=`cp pack-*.pack /tmp/$$.pack && \
chmod u+w /tmp/$$.pack && \
truncate --size=-20 /tmp/$$.pack && \
sha1sum /tmp/$$.pack | cut -d' ' -f1 && \
rm /tmp/$$.pack`
echo "File names in Git pack:"
if test $hash_value_of_file = $hash_value_in_filename ; then
ls -1 pack-${hash_value_in_file}.*
fi
echo "$hash_value_in_file : SHA-1 hash value within the .pack file."
echo "$hash_value_of_file : SHA-1 hash value of the .pack file (minus the 20 byte trailer that is the previous hash.)"
echo "$hash_value_in_filename : SHA-1 hash value in the filename itself."
cd - >/dev/null
}
exiterr() {
echo "usage: $0 directory_of_a_git_repository"
exit 1
}
if test $# -ne 1 ; then exiterr; fi
if test ! -d $1/.git ; then
echo "No git repository found in \"$1\""
exiterr
fi
if test ! -d $1/.git/objects/pack ; then
echo "No pack directory found in git repostiory \"$1\", run with a different repository."
exiterr
fi
main $@
</code></pre>
<h2 id="1433476141"><a href="index.html#1433476141">π</a> 1433476141 - 20150604</h2>
<p>If attempting to compile and configure an Apple IIe / Apple IIGS emulator for demo-running purposes,
something like the shell-script below will get things going for Linux on x86_64 processors.</p>
<p>h/t @DaveyPocket for mentioning demos and helping to compile and sort through the quirks of setting up the emulator.</p>
<pre><code>
#!/bin/sh
main() {
installDependencies() && \
getKentsEmulatedGS() && \
buildKentsEmulatedGS_x86-64 && \
getROMs() && \
configureKentsEmulatedGS && \
runEmulatorWithSound()
}
installDependencies() {
sudo apt-get install -y build-essentials xorg-dev pulseaudio
}
getKentsEmulatedGS() {
wget http://kegs.sourceforge.net/kegs.0.91.tar.gz
tar xzvf kegs.0.91.tar.gz
}
buildKentsEmulatedGS_x86-64() {
cd kegs.0.91
rm vars; ln -s vars_x86linux vars
sed --in-place '5s/march=.*$/march=amdfam10/'
make
cd ..
}
getROMs() {
wget http://google-for-apple-ii-gs-rom_images.za/ftp.apple.asimov.net/emulators/rom_images/appleiigs_rom01.zip
unzip appleiigs_rom01.zip
cp XGS.ROM ROM
wget http://www.ninjaforce.com/downloads/NFCDemoDrive.zip
unzip NFCDemoDrive.zip
}
configureKentsEmulatedGS() {
sed --in-place '9s/^s7d1 = .*$/s7d1 = NFCDemoDrive.2mg/
}
runEmulatorWithSound() {
padsp ./xkegs
}
runEmulatorWithoutSound() {
./xkegs --audio 0
}
</code></pre>
<h2 id="1432908829"><a href="index.html#1432908829">π</a> 1432908829 - 20150529</h2>
<p>I’ve compiled plan9port again recently, and ran into some errors caused by missing X libraries, both in Ubuntu and Debian.</p>
<p>There were other errors on Debian Jessie, but a mutual error on Ubuntu Precise was that the library header file X11/IntrinsicP.h could not be found.</p>
<p>The entire compilation and installation process from a Ubuntu Precise install would be something like the following, although I’ve not tested it and some steps may be missing:</p>
<pre><code>#!/bin/sh