-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
1269 lines (746 loc) · 135 KB
/
atom.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
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
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Jenko</title>
<link href="https://jenko.me/atom.xml" rel="self"/>
<link href="https://jenko.me"/>
<updated>2022-11-21T12:28:06+00:00</updated>
<id>https://jenko.me</id>
<author>
<name>Ian Jenkins</name>
<email>[email protected]</email>
</author>
<entry>
<title>Hacktoberfest checking out</title>
<link href="https://jenko.me/hacktoberfest/2022/11/21/hacktoberfest-checking-out"/>
<updated>2022-11-21T00:00:00+00:00</updated>
<id>https://jenko.me/hacktoberfest/2022/11/21/hacktoberfest-checking-out</id>
<content type="html">
<p>The first <a href="https://hacktoberfest.com/">hacktoberfest</a> I took part in was 2015, you can <a href="https://www.boxuk.com/insight/archived-hacktoberfest-2015/">read more about my experience on the blog of where I used to work</a>. It was pretty novel back then and it felt like every pull request was a very minor step in the progress of open source. One thing that was missing was an easy way to check your progress so you could see how close you actually were to claiming a free t-shirt. That’s what gave me the idea to create a little checker app. It wasn’t complicated, just a small node app that used the Github API to look up how many PRs a specific username had created during the qualifying period of October. Back then, the rules were pretty simple, open 4 PRs on Github in October and you’ve qualified. Spammers and scammers weren’t so much around back then, so all the additional checks that are required nowadays weren’t needed back then.</p>
<p><img src="https://github.com/jenkoian/hacktoberfest-checker/raw/version2016/hacktoberfest-checker-2016.png" alt="The initial basic design" /></p>
<p>It got a little bit of interest from others taking part and I think it’s fair to say for a small part of that 2015 edition at least it was <em>the</em> way of checking your hacktoberfest progress. It was quite rewarding and exciting to lead a popular (popular being relative here, for me it was popular, I’m sure others it would barely be on their radar) open source project. One of the best aspects was seeing comments like <a href="https://github.com/jenkoian/hacktoberfest-checker/pull/7#issuecomment-148894994">this one</a>.</p>
<p><img src="https://user-images.githubusercontent.com/131355/203045926-4b555987-9332-44cd-a549-42e60882f06e.png" alt="" /></p>
<p>Year after year I updated the app with a fresh look and feel to match the underlying theme and I tried to introduce some new bit of technology each year, even if just a new CSS or JS framework so I could try and learn something new in the process. What started as an extremely simple node app with some basic front end JS and CSS is now a fully fledged <a href="https://reactjs.org/">React</a> app usig <a href="https://tailwindcss.com/">Tailwind CSS</a>. The React rewrite is particularly worth calling out, as I had expressed an interested in rewriting the app in React and <a href="https://github.com/jenkoian/hacktoberfest-checker/pull/333">someone submitted the most incredible PR</a> essentially doing all the work for me! It was great because it meant I could read through and understand the changes without undertaking the daunting task of having to start a big rewrite with no knowledge of React. Building upon this over the years has left me with a slightly above zero understanding of React, which is great.</p>
<p>The app started as an app hosted on the free tier on <a href="https://www.heroku.com/">Heroku</a>, this changed after a few years after I realised I was hosting this on a Digital Ocean competitor for an initiative organised by Digital Ocean. I reached out to them and they were only happy to give me some free credits to move over to <a href="https://www.digitalocean.com/">Digital Ocean</a>. The free credits ran out a year or two after than initial edition and although I’m sure they would have been more than happy to replenish them, I didn’t want go back cap in hand so have been paying the hosting for the last couple of years.</p>
<p>The cost isn’t a big deal, a bit annoying given the economic state of the world at the moment, but it’s not a massive amount. However, it’s the maintenance, support and frankly the motivation of keeping the app running that has led me to decide that…</p>
<p><strong>The hacktoberfest checker has come to the end of it’s life</strong></p>
<p>It’s only a month a year, but when it came around this year I was actually dreading having to give up some of my free time to dedicate to it. It’s not even that big of an upkeep, but still enough for it to become a distraction I could do without.</p>
<p>The other aspect to this is that the app is more or less superfluous now anyway, worse than that it’s not even accurate anymore. Digital Ocean has since built <a href="https://hacktoberfest.com/profile/">it’s own progress checker</a> and due to the spammers and scammers mentioned earlier have added more and more complexity to the rules, most of which we’ve added support for now, but some are extremely difficult/impossible, like Digital Ocean maintains a private list of repositories/users that are banned, also PRs have to be approved by Digital Ocean after a grace period which could be different for each PR, there’s also a maintainers reward which seems to be manually picked by Digital Ocean which we obviousy can’t add support for.</p>
<p>So although it was rewarding at first, the fact there is now a better and more accurate alternative, the fact I don’t look forward to October coming and the fact I could save a bit of money, means that now is a good time. The repository on Github has over 700 stars, by far the most I’ve ever had on any other repository I’ve open sourced, to which I’m extremely grateful for and I’m chuffed that it helped a few people get into open source. The website will be offline, probably by the time you are reading this and I’ll archive the repository.</p>
<p>Cheers!</p>
</content>
</entry>
<entry>
<title>I do WordPress now</title>
<link href="https://jenko.me/wordpress/2021/09/22/i-do-wordpress-now"/>
<updated>2021-09-22T00:00:00+01:00</updated>
<id>https://jenko.me/wordpress/2021/09/22/i-do-wordpress-now</id>
<content type="html">
<div class="standfirst">
<p>I do a lot, pretty much all my work in WordPress these days. This post talks about how that came about, what it’s like working with WordPress from a code point of view and the ecosystem. I discuss on things like the use of globals, composer support as well as things I really like, such as WP-CLI. I also touch on the community and finally on the direction I think WordPress is going and my thoughts on that.</p>
<p>If you want a really succinct tl;dr it’s probably, I do WordPress and well, I like it.</p>
</div>
<p>From approximately 2012 - 2018 I was working predominantly, if not exclusively with <a href="https://symfony.com/">Symfony</a>. When we were pitching for a new e-commerce project in 2018 it therefore felt natural to reach for Symfony. I had used <a href="https://sylius.com/">Sylius</a> a bit, and had high opinions of it, as did the people I spoke to about it too. Even if we went with a platform such as <a href="https://www.shopify.co.uk/">Shopify</a>, the APIs are so rich and Symfony’s tools for dealing with APIs so rich that this felt like not a problem too. Anyway, the pitch went really well and the client told us they were selecting us as their development partner for the project. Great news.</p>
<blockquote>
<p>We want you to use WooCommerce.</p>
</blockquote>
<p>We had looked into <a href="https://woocommerce.com/">WooCommerce</a> as part of our analysis, but we had made the recommendation of Shopify and was fully expecting to go down that route. So WooCommerce it is! Since that point, I’ve pivoted pretty strongly to working predominantly, if not exclusively with WordPress. If you’re interested in more of the story of the project described above, you can check out the <a href="https://speakerdeck.com/jenkoian/from-zero-to-vip">talk I did at Bristol WP a few years ago</a>. For the remainder of this post though I want to talk about my experiences with WordPress over the last few years.</p>
<h2 id="community">Community</h2>
<p>When first turning my focus to WordPress, I wanted to try and get a feel for the community a little bit. Luckily, there was a <a href="https://www.meetup.com/Cardiff-WordPress-Meetup/">local meet up</a> happening mere days after discovering that I’d be working more with WordPress, so along me and a colleague went.</p>
<p>It was a small, yet vibrant meet-up, what immediately stood out to me was how rich in diversity it was, not just in ethnicity and gender but also in age and ability. From professional developers who made their career in developing on WordPress to those less technical who just use WordPress to run their small business. It was certainly different to the tech meet-ups I’d attended previously and it was, well, lovely.</p>
<p>From there I attended another fairly local, but slightly bigger meet up, <a href="https://wpbristol.co.uk/">Bristol WordPress People</a>. Similar diversity, similar loveliness, really good food, like really good food. Sustainably sourced, all dietary needs met, you name it. So, a community that values..</p>
<ul>
<li>Diversity</li>
<li>Sustainability</li>
<li>Equity</li>
<li>Good Food</li>
</ul>
<p>Well, sign me up.</p>
<h3 id="wordcamp-europe">WordCamp Europe</h3>
<p>It would be remiss of me to talk about the WordPress community with out talking about an experience that I’ll remember for the rest of my life. In June of 2019 I attended my first WordCamp. <a href="https://europe.wordcamp.org/2019/">WordCamp Europe 2019 in Berlin</a>.</p>
<p>I remember for years hearing about how WordCamps (and DrupalCons IIRC) are like these uber versions of conferences I’ve long been attending (Symfony Live’s and PHP Conferences mostly) but it wasn’t until experiencing one that I really knew what they meant. It was honestly incredible. I reckon even if you had little interest in WordPress you’d have a smashing time. Tons of sponsors offering activities and freebies, loads of people creating a nice atmosphere, lovely food, yoga classes, heck it even had a free creche!</p>
<figure>
<img alt="Me with John Blackbourn @ WCEU 19" src="/assets/img/wceu19.jpg" />
<figcaption>Me hanging out with <a href="https://twitter.com/johnbillion" target="_blank">John Blackbourn</a> @ WCEU19</figcaption>
</figure>
<p>The community knows how to party too, with the end of the event culminating in live entertainment and a big (80s themed) disco. So, reflecting on my points about the community again, we have:</p>
<ul>
<li>Diversity</li>
<li>Sustainability</li>
<li>Equity</li>
<li>Good Food</li>
<li>Knows how to party</li>
</ul>
<p>Which funnily enough, would be my manifesto, should I ever move into politics.</p>
<h2 id="the-codes">The Codes</h2>
<p>So I have to be honest, and I’m sure it comes of no surprise my impression coming into WordPress was that code quality was quite low. I was determined to keep an open mind and to keep any ego / elitism at the door though, which I think I have done, but I still think there are some observations to make. I’m going to touch on those now, I’m sure it’s nothing new to anyone who works with WordPress and I’ll touch on why this is likely the case later on too.</p>
<h3 id="the-bad">The Bad</h3>
<p>In a way I think WordPress is likely a victim of its own success. Built in an era where PHP was used <a href="https://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/">as a fractal of bad design</a> it got so popular that it likely kept building and growing to the point it’s at today where it powers like 40% of the web or something. Over that time I think it’s fair to say it accrued quite a bit of technical debt without much in the way of payback.</p>
<p>Let’s just take a look at some of the things I found hard to deal with.</p>
<h4 id="globalseverywhere">Globals…everywhere</h4>
<p>I remember when I was first getting in to PHP (circa 2006) and one of the first things I learnt was to avoid globals like the plague. I wasn’t too sure why at the time if I’m honest but I’ve come to learn why over the years, among the many reasons is how hard it is to write tests, but more on that later.</p>
<h4 id="plugins">Plugins</h4>
<p>Plugins play a pivotal role in the world of WordPress, this isn’t necessarily a bad thing, but there are lots of them out there, and plenty of bad ones. I’m probably going to have this in the ‘The Good’ section (spoiler) but it’s here as well, purely due to the risk of a plugin completely breaking your site at any point, largely due to…</p>
<h4 id="hooksageddon">Hooksageddon</h4>
<p>WordPress has an extremely powerful extension system called hooks. There are two main types of hooks, filters and actions.</p>
<figure class="highlight"><pre><code class="language-php" data-lang="php"><span></span><span class="x">&lt;p&gt;Hello </span><span class="cp">&lt;?php</span> <span class="k">echo</span> <span class="nx">apply_filters</span><span class="p">(</span> <span class="s1">&#39;welcome_message_second_word&#39;</span><span class="p">,</span> <span class="s1">&#39;world&#39;</span> <span class="p">);</span> <span class="cp">?&gt;</span><span class="x">&lt;/p&gt;</span></code></pre></figure>
<p>The above will output <code>Hello world</code> … or will it :notsureif:</p>
<p>As there’s a hook (filter) around <code>world</code> it means any plugin/theme/project developer can change this value, e.g.:</p>
<figure class="highlight"><pre><code class="language-php" data-lang="php"><span></span><span class="cp">&lt;?php</span>
<span class="nx">add_filter</span><span class="p">(</span> <span class="s1">&#39;welcome_message_second_word&#39;</span><span class="p">,</span> <span class="nx">fn</span><span class="p">(</span> <span class="nx">string</span> <span class="nv">$second_word</span> <span class="p">)</span> <span class="o">=&gt;</span> <span class="s1">&#39;universe&#39;</span> <span class="p">);</span></code></pre></figure>
<p>So it will now say <code>Hello universe</code> … or will it :notsureif:</p>
<p>Unless of course a plugin uses the same hook with a higher priority. You can get around of course by changing your priority, or by adding some logic to only change it if the argument is a certain value or something, but, the point is, it can seem a little … wild, that at any point values can be changed multiple times by multiple plugins.</p>
<p>So that was a filter example, let’s have a look at an action:</p>
<figure class="highlight"><pre><code class="language-php" data-lang="php"><span></span><span class="x">&lt;p&gt;Hello world&lt;/p&gt;</span>
<span class="cp">&lt;?php</span> <span class="nx">do_action</span><span class="p">(</span> <span class="s1">&#39;post_welcome_message_printed&#39;</span> <span class="p">);</span> <span class="cp">?&gt;</span><span class="x"></span></code></pre></figure>
<p>Actions are more or less events, in the example above we’re essentially raising an event <code>post_welcome_message_printed</code> which plugins/themes/project developers can use to do … whatever they like - output a post welcome message template (maybe a gif or something), or send an email or, do some logging or whatever they want really.</p>
<p>Similar concerns to the filter just slightly different in that it isn’t necessarily <em>changing</em> a value, just performing an action.</p>
<h4 id="wp-query">WP Query</h4>
<p>Perhaps a little un-nuanced but <code>WP_Query</code> is horrific, I mean I’m sure it’s highly optimised and efficient and all that jazz, but just look at it 😱</p>
<p><a href="https://github.com/WordPress/WordPress/blob/25daf03a8ea95cf47b9f25ab40336a1f6501cff4/wp-includes/class-wp-query.php">https://github.com/WordPress/WordPress/blob/25daf03a8ea95cf47b9f25ab40336a1f6501cff4/wp-includes/class-wp-query.php</a></p>
<p>If you look at <code>get_posts</code> specifically, then <a href="https://tomjn.com/2013/08/12/wp_queryget_posts/">this post from Tom J Nowell sums it up beautifully</a>.</p>
<h4 id="random-other-stuff">Random other stuff</h4>
<ul>
<li>Lack of namespaces which leads to best practices such as <a href="https://developer.wordpress.org/plugins/plugin-basics/best-practices/#prefix-everything">https://developer.wordpress.org/plugins/plugin-basics/best-practices/#prefix-everything</a> (you can use namespaces I hasten to add, just that they aren’t completely ubiquitous)</li>
<li>Lack of types which leads to functions returning things like <code>string|int|false</code> etc.</li>
<li>Lack of unified autoloading which leads to loads of <code>require_once</code> calls or custom autoloaders all over the place</li>
<li>Debugging can be difficult - particularly as you start stepping into hooks and things</li>
</ul>
<p>There’s probably other things too but I think you get the point.</p>
<h3 id="the-good">The Good</h3>
<h4 id="extendability">Extendability</h4>
<p>Ok, so the hook system can be problematic but it’s kinda cool you can customise almost anything! You have the power to turn WordPress into anything you want it to be, I think this is part of the reason WordPress has become so successful, particularly for agencies.</p>
<h4 id="plugins-1">Plugins</h4>
<p>Related to the extendability, but there are plugins for almost anything, again you need to be <em>really</em> careful to pick good ones, but you can really enhance the offering through plugins. <a href="https://multilingualpress.org/">Multilingualpress</a> is a good example here, you get some really nice tools for providing a multilingual multisite with a relatively low footprint.</p>
<h4 id="massive-suite-of-functions">Massive suite of functions</h4>
<p>There is a huge number of utility and likewise functions in WordPress which come in really handy. One example that springs to mind is the HTTP functions, I saw <a href="https://deliciousbrains.com/wordpress-http-api-requests/">a good blog post on these recently over on DeliciousBrains</a>.</p>
<p>There are definitely others too, but this is a pretty neat example.</p>
<h2 id="the-ecosystem">The Ecosystem</h2>
<p>WordPress is optimised for its users, not just the CMS but the entire ecosystem is user led, again another reason it’s likely so popular. This does make it challenging for a developer like me, particularly coming from Symfony which is very developer focussed.</p>
<p>The WordPress ecosystem is focussed on empowering users of all abilities get up and running with a CMS or E-Commerce store, or whatever they want through ease of use. You want <a href="https://buddypress.org/">a social media platform built on WordPress</a>? Sure, just upload this zip file!</p>
<p>Things which I’d come to take for granted to working with Symfony were no longer readily available. Let’s dig into some of that now.</p>
<h3 id="git--github">Git / Github</h3>
<p>I love using Git and GitHub, it just feels so natural and easy to me. WordPress uses … Subversion and Trac, I used to use this too, a long time ago, and it was great at the time but things have moved on. There’s a strong element of ‘it works for them so why change?’ Going on, but I truly believe the WordPress ecosystem would gain so much if they moved wholesale to Git / GitHub.</p>
<p>I should point out that WordPress <em>is</em> on Github, you can submit a pull request however it won’t get merged:</p>
<blockquote>
<p><strong>Note:</strong> Pull requests on GitHub will <strong>not</strong> be merged. Code changes are still required to be made to the SVN repository by trusted long term contributors granted commit access.
<a href="https://make.wordpress.org/core/handbook/contribute/git/github-pull-requests-for-code-review/">https://make.wordpress.org/core/handbook/contribute/git/github-pull-requests-for-code-review/</a></p>
</blockquote>
<p>I don’t know how many contributors prefer GitHub over SVN but the fact they even have this an option suggests to me contributors at least would like to use Git/GitHub.</p>
<p>The existing “SVN but you can use Github, but only kinda” is just convoluted, it makes it hard work to contribute, where do you even begin? Do you need to learn SVN? Why are there so many hoops compared to almost every other open source project out there?</p>
<p>I realise I’m fairly fresh to WordPress and maybe the current setup is like an old pair of slippers to the current core contributors, but this is my opinion looking at it with (fairly) fresh eyes.</p>
<h3 id="coding-standards">Coding standards</h3>
<p>In a similar vein to the point above where WordPress seems to be different to the vast amount of other similar projects, this too rings true for the coding standards in WordPress. Again, I think they would benefit so much from adopting the standards adopted by the wider community.</p>
<p>The wider PHP community has adopted PSR-1 and PSR-2 (now superseded by PSR-12) coding standards quite widely and for quite a while now, it just makes sense for WordPress to do the same? Or at least base their own standards from these, or at least just PSR-1. I’m not too familiar with the history but it seems it <a href="https://core.trac.wordpress.org/ticket/23357">was discussed years ago</a>, it made sense not to adopt given the support for PHP included 5.2 back then but I wonder if now given PHP 5.6 is the minimum supported version it might make sense?</p>
<p>It’s not too big a deal I guess, you quickly get used to tabs and extra spacing around brackets and stuff, but it just strikes me as yet another barrier for new contributors. Again though, the vast majority of existing contributors may not want to lose those comfy slippers, and I get that.</p>
<h3 id="composer">Composer</h3>
<p><a href="https://getcomposer.org/">Composer</a> is by far the best thing to ever happen to PHP, heck, I’d argue it’s the best package manager there is. WordPress doesn’t have native support for composer, which again I think is a shame. There are some <em>excellent</em> community tools out there though.</p>
<p><a href="https://wpackagist.org/">WordPress Packagist</a> mirrors all the plugins and themes listed on the WordPress directory and exposes them to composer through a custom packagist repository. It truly is fantastic, absolute hats off to <a href="https://outlandish.com/">Outlandish</a>, the company behind it. In the age of <a href="https://poststatus.com/acquisitions/">mass WordPress acquisitions</a> I’m amazed Automattic haven’t acquired it.</p>
<p>WPackagist makes it possible to install plugins and themes just as you would any composer package. WordPress plugins often come in premium flavours though which aren’t listed on the public directory and thus aren’t listed on WPackagist. Some of them (such as Yoast) offer up <a href="https://yoast.com/help/how-to-install-yoast-plugins-using-composer/">custom repositories you can use for composer</a>, but others do not. In this scenario, you have a few options such as <a href="https://github.com/Rarst/release-belt">https://github.com/Rarst/release-belt</a> or <a href="https://github.com/cedaro/satispress">https://github.com/cedaro/satispress</a> for example or you can set just include the plugins in your repository if all else fails.</p>
<h3 id="dependency-injection">Dependency Injection</h3>
<p>Coming from a Symfony background it was a bit of a shock to the system not having a <a href="https://symfony.com/doc/current/components/dependency_injection.html">Dependency Injection Container</a> (DIC) at my disposal, everything in Symfony comes through the container pretty much. Singletons, where again much like globals you’re taught pretty early on ‘are bad mmmkay’ are quite common.</p>
<p>It is possible to use Dependency Injection (DI) and a DIC of course, as we have done on our <a href="https://github.com/boxuk/wp-project-skeleton/blob/main/docs/dev/custom-code.md#dependency-injection">project skeleton we use in work</a>, but as per composer and other things, it requires additional effort.</p>
<h3 id="testing">Testing</h3>
<p>Unit Testing WordPress is hard work, mostly due to the way it relies so heavily on globals. The best way I’ve found around this is to wrap things heavily, so you can use DI for core functions and things and replace those with mocks in your tests. There is <a href="https://github.com/10up/wp_mock">WP_Mock</a> too if you prefer to use a mocking framework.</p>
<p>Should we even bother unit testing? Possibly not, I like this quote from <a href="https://www.alainschlesser.com/">Alain Schlesser</a> in the <a href="https://poststatus.com/">Post Status</a> slack recently</p>
<blockquote>
<p>WordPress is like the toxic material you only can interact with through these protective barrier glasses with built-in gloves</p>
</blockquote>
<p>So you probably want to unit test your custom code but find a way to decouple that from WordPress as much as possible so you don’t end up covered in toxic material.</p>
<p>For those times where you want to test that your code is interacting with the WordPress bits ok, that’s where you’d want to move into integration testing.</p>
<p>There are some good libraries here. <a href="https://github.com/wp-phpunit/wp-phpunit">WP PHPUnit</a> is good for providing factories and things to create data within your test, as well as to help with general test setup (installing WordPress etc.).</p>
<p>Beyond PHPUnit, you have <a href="https://docs.behat.org/en/latest/">behat</a> which is used a fair bit in the community, <a href="https://github.com/wp-cli/wp-cli-tests">particularly by WP-CLI</a>.</p>
<p>If you want to do more browser based testing, to ensure clicking buttons and things actually does what it’s supposed to, you should be able to use most/any UI testing framework, in work we’ve had some success with <a href="https://robotframework.org/">Robot Framework</a> but more WordPress centric tools I’ve heard good things about include <a href="https://github.com/bigbite/wp-cypress">WP Cypress</a> and <a href="https://github.com/lucatume/wp-browser">Codeception with WP Browser</a></p>
<h3 id="wp-cli">WP-CLI</h3>
<p>I’m not sure how long ago WordPress got WP-CLI but it is excellent. I’ve not dug too much into the internals, but I know using it is always a pleasure, it’s easy to extend and the (behat based) testing setup and tools are brilliant as well.</p>
<p>I’ve no idea how the WP-CLI was incepted and then executed but whoever was behind it deserves a lot of praise.</p>
<h3 id="wp-rest-api">WP Rest API</h3>
<p>Similar to the WP-CLI, I’ve no idea when the Rest API aspect of WP was added, but again it’s excellent. The endpoints make sense, supports the necessary verbs as you might expect, is nicely queryable where it should be and is really easy to extend and customise. Once again, bravo.</p>
<h3 id="other-notable-things">Other notable things</h3>
<p>Some other notable ecosystem things I thought worth mentioning.</p>
<h4 id="dictator">Dictator</h4>
<p>Perhaps I’m biased because we use it heavily and have taken on the maintenance and development through our own fork, but I really think <a href="https://github.com/boxuk/dictator">Dictator</a> is a nifty library. One thing I’m hoping to add at some point is the ability to run it in <code>pre_filter_</code> mode, so instead of replacing database values with the configuration set in the YAML file it will create the necessary <code>pre_filter_*</code> hooks instead.</p>
<h4 id="flagpole">Flagpole</h4>
<p>It’s a small little library just run by one guy, but <a href="https://github.com/jamesrwilliams/flagpole">flagpole</a> is an excellent little feature flagging library in WordPress, we use it heavily at work and would recommend.</p>
<h4 id="wp-cli-fixtures">WP-CLI Fixtures</h4>
<p>We used to run Alice fixtures in our Symfony projects in work, and we can do the same in WordPress thanks to a neat little WP-CLI package called <a href="https://github.com/nlemoine/wp-cli-fixtures">wp-cli-fixtures</a>. There are other solutions similar to this such as <a href="https://en-gb.wordpress.org/plugins/fakerpress/">FakerPress</a> but I prefer YAML files for this sort of thing.</p>
<h2 id="bringing-php-to-a-javascript-fight">Bringing PHP to a Javascript fight?</h2>
<p>Almost everything I’ve talked about up until this point has been focussed on ‘classic’ WordPress or PHP centric WordPress, however there is a slow turning wheel that suggests that the future of WordPress is beyond PHP.</p>
<p>I think it started in 2015 where Matt Mullenweg suggested the community should <a href="https://www.youtube.com/watch?v=KrZx4IY1IgU">“Learn Javascript Deeply”</a>. Over 5 years since then, WordPress now has the <a href="https://github.com/WordPress/gutenberg">block editor</a> built in <a href="https://reactjs.org/">React</a>, with <a href="https://fullsiteediting.com/">Full Site Editing</a> just getting rolled out, which expands the use case of the block editor even further. The other big thing happening in WordPress right now is <a href="https://www.gatsbyjs.com/docs/glossary/headless-wordpress/">Headless WordPress</a>, with a <a href="https://github.com/wpengine/faustjs">number</a> <a href="https://frontity.org/">of</a> headless frameworks and approaches being pushed, all of which are Javascript based.</p>
<p>There’s so much in WordPress that I can’t see PHP being eradicated from WordPress too soon, but it does feel like they are <a href="https://www.boxuk.com/insight/minimal-disruption-maximum-gains-applying-the-strangler-pattern-to-legacy-software/">strangling</a> away classic WordPress and honestly, I can’t say I blame them.</p>
<p>I started off this post hinting at the massive amounts of tech debt that existed in WordPress and I’ve often <a href="https://www.boxuk.com/insight/archived-from-legacy-to-new-the-anfield-approach/">gone on about the virtues of strangling a legacy application</a> that it makes sense? That’s not easy for me to say either given that I’m a PHP developer mostly. I’ve not used either the block editor or headless WordPress enough at this point to give a full opinion on either, but learning React has long been on my to-do list, so maybe this will provide the opportunity? Having said that, I would like to see a headless WordPress approach which isn’t Javascript based. I would like to see an approach using something like <a href="https://hotwired.dev/">Hotwire</a> or <a href="https://htmx.org/">HTMX</a> with a PHP backend. It makes me wonder if something like that would make it easier to use the wider plugin ecosystem in a headless setup. Again though, I’ve not used either of those technologies enough to give a firm opinion. I do think it’s all very exciting though.</p>
<h2 id="summary">Summary</h2>
<p>Well this post was way longer than I expected, sorry about that. I realise I’ve ripped at WordPress a bit in places, but I hope that’s not the stand out element of this post. I was trying to be constructive in any criticism and I completely understand why the situation with a lot of these things is like it is. If anything, I want the summary of this post to be that, I like WordPress, I enjoy the community, I enjoy the power it enables in delighting the clients I work with, I enjoy the challenge of trying to bring best practice into it, I’m intrigued with the future direction, I’m hopeful I can eventually improve my React skills through the block editor and/or headless approaches.</p>
<p>I feel like I’ve barely scratched the surface in what I’ve learnt from day zero until now of working with WordPress. On the face of it, I can understand why developers might be put off, but peel back some of the layers and I think you’d be surprised, there are good people doing good things in WordPress and there’s no reason that couldn’t be you. Oh and attend a WordCamp (when safe to do so) it will blow you away.</p>
</content>
</entry>
<entry>
<title>The Developer CV</title>
<link href="https://jenko.me/opinion/2018/08/24/the-developer-cv"/>
<updated>2018-08-24T00:00:00+01:00</updated>
<id>https://jenko.me/opinion/2018/08/24/the-developer-cv</id>
<content type="html">
<div class="standfirst">
<p>I put myself off writing this post for a long time due to fear as coming across a bit ostentatious (isn’t it ironic that the word ostentatious is itself very ostentatious, anyway..) however, <a href="https://medium.com/@dominicwhite/i-hire-software-developers-your-resume-is-the-reason-youre-not-getting-interviews-dc7b2520a2f1">I came across this medium post</a> recently and as it aligns quite closely to my own thoughts I thought I may as well publish. Hopefully, someone will find it useful, if it just comes across as me being picky then fair enough.</p>
</div>
<p>I’ve been reviewing developer CVs a fair bit over the last few years, due to a recent recruitment drive, even more so over the past week or two. I don’t work for a big silicon valley tech giant or anything like that, but there are some little things which I see time and time again which I’d like to just pass comment on, I guess you could call them ‘tips’ but I dunno, just things I’ve noticed.</p>
<h2 id="length--girth">Length &amp; Girth</h2>
<p>This isn’t anything new, I’m sure I got told this in year 11 careers advice class but there is absolutely no reason whatsoever to have a CV more than 1 page. 2 pages at an absolute push, anything more than 2, the person reading that CV is already resenting you.</p>
<p>At the risk of coming across harsh, nobody cares that you got an A at GCSE French and worked one summer in Tesco Express. Keep it relevant, read the job ad and show off what skills you have in order to do that job.</p>
<p>You don’t need to list every job you’ve ever done, only the last (most relevant few) even then you don’t need to list everything about each job. Maybe go into a bit of detail about your current/previous role but roles before that, just list the achievements.</p>
<h2 id="get-the-order-right">Get the order right</h2>
<p>I’ve seen so many CVs that start off with qualifications at the top (in chronological order) followed by experience, then finally touching on skills. This is completely backward to me. You want to start the CV with the headlines, the things that are going to have the person at the other end take notice and want to finish reading your CV. Go skills first, read the job ad. If the ad suggets it is looking for developers with experience in Symfony, start off your CV showing off everything you know about Symfony and surrounding ecosystem.</p>
<h2 id="go-easy-on-the-buzzwords">Go easy on the buzzwords</h2>
<p>If you’re reading a CV and the person has done nothing more than list a bunch of technologies/buzzwords, you’re gonna think they’ve just put it on the CV for the sake of it, if I see a big list of tech with little to no explanation of any it’s an immediate red flag for me. What is much much better is a small set of relevant technologies with an explanation next to each one as to how you used that tech to solve a problem.</p>
<h2 id="keep-it-simple">Keep it simple</h2>
<p>Black text on white is absolutely fine, preferred even. You don’t need to make your CV look like a website, it doesn’t need colour, those things are merely a distraction (possibly different if you’re going for a design role?).</p>
<p>Some people include a picture of themselves, if you can do it in a subtle way without causing a distraction then fine, but I don’t think it’s particularly necessary to include a pic.</p>
<p>Oh and for the love of god don’t submit a CV in a proprietary format, this includes Microsoft Word. Just use PDF if in any doubt.</p>
<h2 id="my-ideal-cv">My ideal CV</h2>
<p>Prob easier if you just see what I think would be my ideal CV:</p>
<hr />
<script src="https://gist.github.com/jenkoian/c2b0809aa2abd11d8bf5ced6adf837ea.js"></script>
</content>
</entry>
<entry>
<title>From Gaufrette to Flysystem and back again</title>
<link href="https://jenko.me/legacy/2017/03/07/from-gaufrette-to-flysystem-and-back-again"/>
<updated>2017-03-07T00:00:00+00:00</updated>
<id>https://jenko.me/legacy/2017/03/07/from-gaufrette-to-flysystem-and-back-again</id>
<content type="html">
<p>When I saw <a href="https://github.com/KnpLabs/Gaufrette/pull/390">Gaufrette added a Flysystem adapter</a> (a year ago to this day!)
it somewhat captured my imagination and it seemed only right that <a href="https://github.com/jenkoian/flysystem-gaufrette">Flysystem should have a Gaufrette adapter</a> and the two
file-system abstraction layers could work completely bi-directional.</p>
<p>It was mostly a bit of fun, although I could potentially see a use case even if that use case hadn’t crept up on me yet.
<strong>Until now!</strong></p>
<p>I recently worked on a legacy project which made use of <a href="https://github.com/KnpLabs/Gaufrette">Gaufrette</a> and we were taking <a href="https://twitter.com/ziobrando/status/675305573127208960">my favourite approach to tackling legacy</a>.
We were working completely on new code and writing adapters to old stuff which handled a lot of the existing heavy
lifting. So, in the case of file-system abstraction we were writing an adapter to the old Gaufrette stuff,
but due to a few reasons we were also keen on trying to make use of <a href="https://github.com/thephpleague/flysystem">Flysystem</a>.
Then I remembered, this silly little library I had created!</p>
<p><em>“You mean we could work with Flysystem whilst not having to rewrite all of these touch points with Gaufrette”</em></p>
<p>We were using Symfony, so actually used <a href="https://github.com/1up-lab/OneupFlysystemBundle">this bundle</a> to hook up Flysystem but essentially it just worked like this:</p>
<script src="https://gist.github.com/jenkoian/b2c40bc307d30a4e398935382fb67812.js"></script>
<p>Pretty neat!</p>
<p>Obviously, having two file-system abstraction layers is a bit pointless, so eventually it would be nice to completely
move away from Gaufrette, but as a nice compromise to ease over the transition this came in really handy.</p>
<p>So if you’re in a similar boat and want to transition from Gaufrette to Flysystem give my silly little library a try.</p>
<p>Finally, I’m not advocating that Flysystem is better than Gaufrette or anything, just that our needs for this particular
project meant Flysystem was a better fit. They are equally as good as one another and I’m sure in some scenarios Gaufrette
might have the edge. Indeed, if you wish to transition in the other direction you can always use the <a href="https://github.com/KnpLabs/Gaufrette/blob/master/doc/adapters/flysystem.md">Gaufrette Flysystem adapter</a> :).</p>
</content>
</entry>
<entry>
<title>Retro fitting Symfony Security into a Legacy App</title>
<link href="https://jenko.me/legacy/2016/03/21/retro-fitting-symfony-security-into-a-legacy-app"/>
<updated>2016-03-21T00:00:00+00:00</updated>
<id>https://jenko.me/legacy/2016/03/21/retro-fitting-symfony-security-into-a-legacy-app</id>
<content type="html">
<p>In <a href="http://jenko.me/legacy/2016/02/03/an-escape-route-from-legacy-with-stackphp-and-the-symfony-microkernel/">my last blog post</a> I talked about how I had escaped legacy by leveraging the Symfony MicroKernel as well as the new Guard authentication component. Once this was all in place, my next task was to migrate the legacy, home-baked, role based access control to Symfony, so I could make extended use of <a href="http://symfony.com/doc/current/book/security.html">Symfony’s fantastic Security component</a>.</p>
<h2 id="roles--permissions">Roles &amp; Permissions</h2>
<p>Having evaluated the current state of play with regards roles and permissions, I had determined that something akin to the following was at play:</p>
<table>
<thead>
<tr>
<th> </th>
<th style="text-align: center">Add Content</th>
<th style="text-align: center">Moderate Content</th>
<th style="text-align: center">Edit User</th>
</tr>
</thead>
<tbody>
<tr>
<td>ROLE_EDITOR</td>
<td style="text-align: center">x</td>
<td style="text-align: center"> </td>
<td style="text-align: center"> </td>
</tr>
<tr>
<td>ROLE_MODERATOR</td>
<td style="text-align: center"> </td>
<td style="text-align: center">x</td>
<td style="text-align: center"> </td>
</tr>
<tr>
<td>ROLE_ADMIN</td>
<td style="text-align: center"> </td>
<td style="text-align: center"> </td>
<td style="text-align: center">x</td>
</tr>
</tbody>
</table>
<p>Now I knew which roles and permissions I needed to set up, there was going to be two ways in which I needed to protect the app.</p>
<ul>
<li>
<p>Routes - stop users from seeing content should they navigate to a URL that is protected.</p>
</li>
<li>
<p>Template - stop buttons etc… displaying if the user doesn’t have permissions to perform the action the button performs.</p>
</li>
</ul>
<h2 id="route-protection">Route protection</h2>
<p>Securing routes in Symfony is actually quite easy. Just some basic configuration and that’s pretty much it!</p>
<script src="https://gist.github.com/jenkoian/3f38b15298517f99e07b.js"></script>
<p>However, in my scenario it wasn’t quite this easy. I needed to give the client a simple way to be able to tweak the permissions each role has. So for example, editors may be given the ability to moderate content at some point. In most applications you’d probably say, just give the editor the moderator role in that case, but due to the legacy nature and the fact there are many roles and permissions, simply giving a user an extra role, although possible, may be ill-advised. Therefore, the access control in my scenario needed to be something like the following:</p>
<script src="https://gist.github.com/jenkoian/098695ae18feb8a5c67d.js"></script>
<p>In other words, I needed the permissions to be mapped to the routes rather than the role.</p>
<p>To achieve this I needed to use a custom RequestMatcher as described in this <a href="http://php-and-symfony.matthiasnoback.nl/2012/07/symfony2-security-using-advanced-request-matchers-to-activate-firewalls/">excellent blog post from Matthias Noback</a>. For this to work I simply set up a static map of permissions to roles, I used a php array, but could just as easily be yaml, xml, whatever.</p>
<script src="https://gist.github.com/jenkoian/5fda9fad505e12186bb5.js"></script>
<p>My <code>RequestMatcher</code> then looked something like:</p>
<script src="https://gist.github.com/jenkoian/e5c4d717b2cdb1d8bd97.js"></script>
<p>Then as Noback points out, this all gets configured via a compiler pass:</p>
<script src="https://gist.github.com/jenkoian/bf5ff2c80179b0583285.js"></script>
<p>With that in place the next thing to do was to write a custom <code>PermissionUrlVoter</code> to vote on whether the user can access the route or not. As we’re not using roles anymore, the core <code>RoleVoter</code> will abstain from the vote so we need to make sure we have something in it’s place. Here is my custom voter:</p>
<script src="https://gist.github.com/jenkoian/3d7810e8fba57006994b.js"></script>
<p><code>getConfigurationRoleMap()</code> basically extracts roles form a configuration file. The configuration file in question, looks something like:</p>
<script src="https://gist.github.com/jenkoian/aa182c799aec96f30bed.js"></script>
<p>This allows the client to easily see which permissions apply to which role(s) and, if you throw in a basic page with an <a href="https://ace.c9.io/">ace-editor</a> on, make changes to.</p>
<p>So all done on route protection right? Well, pretty much. As I have my Symfony application sat alongside the legacy application using <a href="http://stackphp.com/">Stack</a>, it basically attempts to hit the route in the Symfony app, if it encounters a <code>NotFoundException</code> falls back to the legacy application. The problem with this is that Symfony will forgo the security stuff completely if the route simply doesn’t exist in the Symfony app. The solution for this was relatively straight forward. Define a ‘catch all’ route in the Symfony app so that each request will get through the Symfony routing and into the Security system. It will of course throw a <code>NotFoundException</code> eventually when it realises there is no controller set up for the route.</p>
<script src="https://gist.github.com/jenkoian/53ed3a789380d2b94015.js"></script>
<p>This should go beneath any routes you currently have set up in the Symfony app so they continue to work as expected.</p>
<h2 id="template-protection">Template protection</h2>
<p>For the template protection, Symfony has a wonderful Twig extension which allows you to easily wrap things you want to protect, for example:</p>
<script src="https://gist.github.com/jenkoian/ffe15e8d271e6b7877e1.js"></script>
<p>In our Symfony application we can use this, with the caveat being that again we want to check permissions rather than roles, e.g.:</p>
<script src="https://gist.github.com/jenkoian/b61c7a2dd30fd9381dd9.js"></script>
<p>For this to work we require another custom voter:</p>
<script src="https://gist.github.com/jenkoian/8f251a75ee55549a4b6f.js"></script>
<p>This basically checks the users’ role, checks it against the configuration file and votes accordingly.</p>
<p>So now we have working template protection in the Symfony app, but how about the legacy app? Well, unfortunately it isn’t using Twig so we can’t use the nice Twig extension, nor does it know anything about the Symfony application at all, so we can’t easily grab things out of the container or anything.</p>
<p>My solution was to create a static facade into the Symfony security bit that does the <code>is_granted</code> check. For this to work, I ended up having to use the (sorry mum) global keyword to expose the kernel to the legacy app.</p>
<script src="https://gist.github.com/jenkoian/948437a9a5fa56824627.js"></script>
<p>This allows us to use the following in the legacy code ‘templates’ and well just about anywhere we need to check permissions really:</p>
<script src="https://gist.github.com/jenkoian/869a5e9848921a127801.js"></script>
<h2 id="thats-it">That’s it!</h2>
<p>That’s pretty much it as to how I started using the extremely powerful Symfony security in the legacy application I’m working with. The roles and permissions are currently set and updated via a configuration file. The next step though, now that we have all our security features in the Symfony ecosystem would be to look to have some kind of ACL editor.</p>
<h3 id="testing">Testing</h3>
<p>One last thing I wanted to touch on is testing.</p>
<p><a href="http://symfony.com/doc/current/cookbook/security/voters.html">Symfony voters</a> are quite easy to test, I’d recommend looking into <a href="https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/RoleVoterTest.php">how some of the core voters are tested</a> if interested in this. Ideally though, you’d have some functional tests which tested the routes that are protected before the security was migrated to the Symfony stuff, i.e. go to this page with this user and make sure you get a 403 response then try with this user and make sure you get a 200 response.</p>
<p>Another neat thing you could do is use <a href="https://github.com/daylerees/scientist">Scientist</a> to perform ‘experiments’ of this new security code against the existing ‘controlled’ code. This would allow you to ‘trial’ this new security code in production before rolling it out for real. It has things such as journals and reports to allow you to see how your new approach is working out, whether it’s performing in unexpected ways for instance or if it’s performing slower than it’s counterpart.</p>
</content>
</entry>
<entry>
<title>An escape route from legacy with StackPHP and the Symfony MicroKernel</title>
<link href="https://jenko.me/legacy/2016/02/03/an-escape-route-from-legacy-with-stackphp-and-the-symfony-microkernel"/>
<updated>2016-02-03T00:00:00+00:00</updated>
<id>https://jenko.me/legacy/2016/02/03/an-escape-route-from-legacy-with-stackphp-and-the-symfony-microkernel</id>
<content type="html">
<p><em class="prologue">I came to, slightly dazed, I was cold and confused, where am I? I tried to take in my surroundings, reams of commented out code to my left, singletons to my right. I don’t know how I got here, but I knew at that point. I was. I was in legacy hell.</em></p>
<p>Although developers generally want to always be working with the latest and greatest, the new shiny if you will, it can’t always be fresh daisies and green fields, every now and again, in fact, probably more often than not, developers have to deal with legacy code, i.e. code written in the past, either by an (<em>obviously inferior</em>) dev, or even worse themselves.</p>
<p>Yep, legacy is some what of an occupational hazard. So when I had recently taken ownership of a particularly iniquitous legacy codebase, I wanted to steer clear of it as much as I could, poke it with a stick, give it snide looks, that kind of thing. So this is how I managed to work with modern tech whilst fighting this thankless battle.</p>
<h2 id="using-stackphp-to-separate-the-old-from-the-new">Using StackPHP to separate the old from the new</h2>
<p><a href="http://stackphp.com/">StackPHP</a> is a convention for composing middlewares in PHP. It works with Symfony’s HttpKernelInterface and basically allows you to apply decorators to your application. This idea has become so popular in the PHP community that a <a href="http://www.php-fig.org/psr/psr-7/">PSR standard has been adopted</a> with one of the aims to make it easier to build standardised middlewares.</p>
<p>We can make use of this approach to easily split requests between a legacy codebase and something more modern, like a Symfony app. Carlos Buenosvinos wrote a brilliant blog post about this which is required reading if this post is proving of any interest: <a href="http://carlosbuenosvinos.com/migrating-progressively-to-symfony-without-pain-with-stackphp/">http://carlosbuenosvinos.com/migrating-progressively-to-symfony-without-pain-with-stackphp/</a></p>
<script src="https://gist.github.com/jenkoian/641dcca3e47fc321825e.js"></script>
<h2 id="where-the-microkernel-fits-in">Where the MicroKernel fits in</h2>
<p>The legacy codebase I was dealing with was already large and convoluted with many directories and sub-directories. Adding in an app, a web, a src and whatever other directories seemed overkill and counter intuitive. I know that’s a minor detail and I could have just put them in a separate directory under the root and all probably would have been fine, but even so I wanted to bring in Symfony with the lowest foot print I could.</p>
<p>Despite always being able to be used as a micro framework, Symfony formally introduced <a href="http://symfony.com/blog/new-in-symfony-2-8-symfony-as-a-microframework">‘Symfony as a Microframework’</a> with a new MicroKernel trait which allows you create an entire Symfony application from a single class. This fitted my use case perfectly, as it meant I could have a fully functional Symfony with minimal number of files. What was also really nice was that it could grow along with the development of the app. As I start to do more and more work in the Symfony part of the application the more of the framework I can use and the more files and directories I can create.</p>
<script src="https://gist.github.com/jenkoian/6e00d8a8569ce4afa99f.js"></script>
<p>So now I have this lightweight, small footprint Symfony app I needed it to fit in with the legacy app. To the user it should be transparent. On the whole this wasn’t too difficult, the main structure of the page was just HTML which I could just copy into some simple twig templates. The layout did have a few complicated bits though. Firstly, a global language switcher.</p>
<h2 id="changing-the-locale-across-the-entire-app">Changing the locale across the entire app</h2>
<p>As the existing legacy app already had a mechanism for setting and changing locale, we needed to hook into that in order to set the locale for our Symfony app. This was fairly trivial via a listener.</p>
<script src="https://gist.github.com/jenkoian/f79c6984eba54271d7b4.js"></script>
<p>It’s worth noting here the importance of creating interface and adapters for everything we do with regards the legacy app (and in general really). By doing so we can quite easily swap out the implementation to something newer when we no longer need to support the legacy app. It’s also a great way of ensuring we can add tests without relying on legacy classes. It’s a good refactoring technique too, in his <a href="http://www.amazon.co.uk/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052">seminal book on legacy</a>, Michael Feathers refers to this as the ‘Extract Interface’ technique.</p>
<h2 id="authenticating-the-user-across-the-entire-app">Authenticating the user across the entire app</h2>
<p>The last thing I needed to do was handle authentication. It needed to work seamlessly across both the legacy side of the application and the Symfony application.</p>
<p>The <a href="http://symfony.com/doc/current/book/security.html">security component</a> within Symfony is super flexible but can be a complicated beast. Fortunately, some work was recently undertaken to simplify it a little and a new component called <a href="http://symfony.com/blog/new-in-symfony-2-8-guard-authentication-component">‘Guard’</a> was created to help.</p>
<p>There is an excellent cookbook entry on <a href="http://symfony.com/doc/current/cookbook/security/guard-authentication.html">‘How to Create a Custom Authentication System with Guard’</a> which gave me everything I needed. I was basically treating the legacy authentication system like a third party API in this case. It boils down to creating the following: A User class, a UserProvider class, and an Authenticator class. All is covered in excellent detail in the cookbook entry and the <a href="http://api.symfony.com/3.0/Symfony/Component/Security/Guard/GuardAuthenticatorInterface.html">docblock of the GuardAuthenticatorInterface</a>. Here’s mine.</p>
<script src="https://gist.github.com/jenkoian/731628f51b1ea89002e9.js"></script>
<script src="https://gist.github.com/jenkoian/e66744a3af7125e5670f.js"></script>
<script src="https://gist.github.com/jenkoian/9dacbc175bf6fd163096.js"></script>
<p>Most of it is self explanatory and explained well in the documentation. One thing to note for my use case is the following.</p>
<script src="https://gist.github.com/jenkoian/33e87298a93f5eb17f02.js"></script>
<p>This is a simple method which maps roles from the existing authentication system to the new User class used by Symfony. This will ensure the user in Symfony land has the appropriate roles set and means you can make use of Symfony features such as <a href="http://symfony.com/doc/current/cookbook/security/voters.html">Voters</a> and what not. It means you can do things like <code>if is_granted(‘ROLE_MODERATOR’)</code> and also use the access control stuff which you can see in the security config in AppKernel.</p>
<p>So now we have all the elements for the Guard authentication it’s time to hook it all together with some basic config. Here is mine:</p>
<script src="https://gist.github.com/jenkoian/e8a6d4f908c314e8c3f7.js"></script>
<p>As you can see we have access to all the powerful features of the Symfony security component with only a few small classes and crucially, without making any changes to the existing codebase or functionality.</p>
<h2 id="summing-up">Summing up</h2>
<p>When faced with the original daunting task of taking on, maintaining and adding new features to this spaghetti bolognese of legacy code I was worried. Having used some OOP techniques and with help from a few nice PHP and Symfony libraries, I feel not only less worried about the future of this project but also enthused and, dare I say, excited to work on it.</p>
<p>Finally, I saw a tweet just before starting this piece of work which summed up perfectly what I was hoping to achieve and I think sums up this blog post perfectly as well.</p>
<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">How do you make greenfield project with legacy? 1. pretend you&#39;re greenfield 2. write an adapter.</p>&mdash; Alberto Brandolini (@ziobrando) <a href="https://twitter.com/ziobrando/status/675305573127208960">December 11, 2015</a></blockquote>
<script async="" src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
</content>
</entry>
<entry>
<title>Memoirs of a UDiffer</title>
<link href="https://jenko.me/opinion/2015/09/17/memoirs-of-a-udiffer"/>
<updated>2015-09-17T00:00:00+01:00</updated>
<id>https://jenko.me/opinion/2015/09/17/memoirs-of-a-udiffer</id>
<content type="html">
<p>This evening will see the 34th(?) and final <a href="http://unifieddiff.co.uk">Unified Diff</a>. Unified Diff, or UDiff as us old timers call it, has been a staple part of my life for the past 3 and a bit years so I wanted to take a bit of time to write up some of my experiences/memoirs of this time. An Ode to UDiff if you will.</p>
<p>Unified Diff is a local tech meetup in my home (ish) city of Cardiff (gerrit?). It was started by 5 of the smartest guys I’ve ever had the pleasure of working with. In size order: <a href="http://twitter.com/handybitesize">Carey</a>, <a href="http://twitter.com/gavd_uk">Gavin</a>, <a href="http://twitter.com/craigmarvelley">Craig</a>, <a href="http://twitter.com/rodnaph">Rhodri</a>, <a href="http://twitter.com/woogoose">Warren</a>.</p>
<p>I somehow managed to worm my way in to make it a 6some, which was kind of an honour. I didn’t want to take such an event for granted so tried to help out as much as I could with the website and filming and what not, and for them to recognise that and get me on board meant a lot.</p>
<h2 id="the-early-years">The Early Years</h2>
<p>Back in 2012, a tech meet up in Cardiff was badly needed, other than the smaller niche meet ups like <a href="http://swlug.org.uk/">SWLUG</a> and <a href="http://www.cardiffrb.com/">Cardiff RB</a> there wasn’t really anything to serve the wider tech community. UDiff aimed to fill that void.</p>
<p>The first couple of meet ups were fantastic. We chose a small O’Neills bar, which worked out quite well. In fact I think, for me at least, this was the golden generation of UDiff, I really enjoyed the ‘bar camp’ feel of them which I don’t think we managed to recreate elsewhere. It allowed people to relax, have a drink, get some food if they wished. It also had a good screen and was a perfect size.</p>
<iframe class="iframe-video" src="//player.vimeo.com/video/36267777?title=0&amp;byline=0&amp;portrait=0" width="600" height="400" scrolling="no" frameborder="0"> </iframe>
<p>There were many good talks throughout the O’Neills days, from interesting panel discussions with legends like <a href="http://twitter.com/stuherbert">Stu Herbert</a> and <a href="http://twitter.com/penllawen">Richard Gaywood</a>, to grand reveals of MySpace projects that never materialised.</p>
<p>The other thing about O’Neills is that it gave me my first experience of public speaking. I had came up with a (somewhat silly) talk idea on a long car journey.</p>
<p>I had started looking into front end tools a little bit having been solely interested in server side stuff previously so thought I’d give a quick run down of what the in tools were at the time. Nothing too technical just a nice little overview of tools and techniques that were previously completely new to me.</p>
<p>I wanted to inject a bit of personality into a pretty dull topic so I came up with the title ‘Frontend Awesome SHit Any Nerd can Use’ or ‘FASHANU’ if you will. It basically allowed me to sprinkle in a bunch of <a href="https://en.wikipedia.org/wiki/John_Fashanu">John Fashanu</a> facts and anecdotes to keep the audience from falling asleep. What I thought would be really fun was if I could actually get John to turn up (!?) as a surprise guest and although I knew it was a long shot I thought I’d give it a go anyway. Here is the email exchange between me and his agent in it’s entirety (with some redacting):</p>
<script src="https://gist.github.com/jenkoian/b99a7a12527a89dbf9dd.js"> </script>
<p>So no luck with John Fashanu but the talk went well even though I had a cold and my boss decided to turn up and crank my nerves up to 11 just before hand.</p>
<iframe class="iframe-video" src="//player.vimeo.com/video/42411606?title=0&amp;byline=0&amp;portrait=0" width="600" height="400" scrolling="no" frameborder="0"> </iframe>
<h2 id="the-awkward-adolescence">The Awkward Adolescence</h2>
<p>After Warren and Carey managed to get us barred from O’Neills (and a speaker pulling out of talking because the whole experience ruined his zen) we embarked on our teenage phase by meandering around a few venues.</p>
<p>There were a few flash in the pan venues such as the Promised Land, which was decent but a little small and required Rod to haul a projector half way across Cardiff. Followed by Fire Island (now the <a href="http://www.urbantaphouse.co.uk/">Urban Tap House</a>) which I think held a few events. My good friend <a href="http://twitter.com/a_thieriot">Aurélien</a> talking about <a href="http://www.scala-lang.org/">Scala</a> in the pitch black is a fond memory as is my second go at public speaking when I talked about Breaking Bad, I mean <a href="http://jenko.me/breaking-bugs">Bugs</a>.</p>
<iframe class="iframe-video" src="//player.vimeo.com/video/83349876?title=0&amp;byline=0&amp;portrait=0" width="600" height="400" scrolling="no" frameborder="0"> </iframe>
<p>We then settled on <a href="http://www.porterscardiff.com/">Porters</a> for a time, which was pretty good. They had a small cinema-esque room which worked well, but the the venue wasn’t free and was a small walk outside of the city centre. There were some brilliant talks there though, <a href="https://vimeo.com/83487514">one that sticks in the memory</a> is <a href="http://twitter.com/daylerees">Dayle Rees’</a> introduction to <a href="http://laravel.com">Laravel</a> with a live (not actually live) link up with it’s creator <a href="http://twitter.com/taylorotwell">Taylor Otwell</a>.</p>
<p><img src="http://localhost:4000/assets/img/600_306200662.jpeg" alt="Cinema Room in Porters" /></p>
<h2 id="settling-down">Settling down</h2>
<p>The tail end of 2013 saw the opening of a great new collaborative open space for creatives in Cardiff called <a href="http://foundershub.co.uk">Founders Hub</a>. It had a small stage area with projector, PA and good lighting. It was basically the perfect venue for us. This was to become our home for the next year and a bit.</p>
<p>UDiff &amp; Founders Hub felt like a match made in heaven. We were all geeks talking geeky stuff together in a place decked out for geeks (there were floppy disks blue tacked to the walls for Pete’s sake!). Attendances here were good, <a href="http://twitter.com/craiginwales">Craig</a> and <a href="http://twitter.com/amienlockwood">Amie</a>, the owners of Founders Hub, often kindly ran a small bar and the space was great for chatting to people and getting to know one another.</p>
<p><img src="http://localhost:4000/assets/img/600_377102622.jpeg" alt="UDiff @ Founders Hub" /></p>
<p>There were some great talks here on a wide range of topics from <a href="https://vimeo.com/106176421">3D printing</a> to <a href="https://vimeo.com/99744479">SEO</a> to the incredibly successful ‘AWS night’. If I had to pick a favourite talk from this era it was probably <a href="https://vimeo.com/90738845">James Cryer’ talk on ‘Janky’</a> as it opened my eyes up to stuff I didn’t really know about yet.</p>
<p>Everything at Founders Hub felt right, it was all just so easy and we had settled in to it as our natural home. It was therefore a big shame when Founders Hub announced they were closing at the end of April 2015. Not only a great shame for us but for the creative/tech industry in Cardiff as a whole. We must give thanks to Craig and Amie though for everything they did for us and hope their new ventures are working out well.</p>
<h2 id="the-twilight-years">The Twilight Years</h2>
<p>With Founders Hub gone, the future of UDiff was up for discussion and although we came close to calling it a day then, we decided to keep it going and we got lucky with a <a href="http://www.acornpeople.com/">local recruitment company</a> offering us a space to run the meet ups with free food and drink. We had been nervous of including recruiters in the past due to the ‘from the community, for the community’ vibe we were going for but we were ensured that there would be minimal sales speak or ‘networking’ and to be fair they were true to their word.</p>
<p>Although a good size, the venue at Acorn wasn’t perfect. The projector wasn’t brilliant and we struggled a bit with the lighting, particularly as it was Summer. However, the food and drinks provided were brilliant and I’m sure helped get people involved. Also, there were some really strong talks. In fact looking back I don’t think there were any weak ones, they were all really really strong and I’m struggling to pick a favourite but I think <a href="https://vimeo.com/133746104">Warren’s talk on Monads</a> stands out to me, mainly because I really liked his ego-free explanation of it all.</p>
<iframe class="iframe-video" src="//player.vimeo.com/video/133746104?title=0&amp;byline=0&amp;portrait=0" width="600" height="400" scrolling="no" frameborder="0"> </iframe>
<p>We also got to experiment with using <a href="https://www.periscope.tv/">Periscope</a> for live streaming the events at Acorn and it was fun and worked well. Whether people actually tuned in and got much out of it I’m not sure, but it was certainly fun to do and see people pop up on my phone.</p>
<h2 id="the-quizzes">The Quizzes</h2>
<p>A small aside here to talk about one of my favourite bits of UDiff history, the Christmas Quizzes. They were absolutely brilliant fun and if anyone runs a local meet up I highly suggest you do a quiz at some point. We tended to arrange ours for our Christmas meet up and had such rounds as ‘O’Rly - name the O’reilly book from it’s redacted cover’, ’Guess the legend - guess the famous computer scientist from a picture of them’, ‘Tweet or false - whether tweets from famous computer people were real or fake’ as well as the obligatory regex section. If UDiff does come back in any fashion, I really hope we are able to do some more quizzes.</p>
<h2 id="favourites">Favourites</h2>
<h3 id="favourite-talk">Favourite talk</h3>
<p><a href="https://vimeo.com/36714130">Gav D’s clean code talk</a>. A must watch for anyone interested in becoming a programmer IMO.</p>
<iframe class="iframe-video" src="//player.vimeo.com/video/36714130?title=0&amp;byline=0&amp;portrait=0" width="600" height="400" scrolling="no" frameborder="0"> </iframe>
<h3 id="favourite-venue">Favourite venue</h3>
<p>O’Neills. The whole bar camp feel was great.</p>
<h3 id="favourite-speaker">Favourite speaker</h3>
<p><a href="http://twitter.com/penllawen">Richard Gaywood</a>. Spoke confidently and really knew his stuff.</p>
<h3 id="favourite-moment">Favourite moment</h3>
<p><a href="http://twitter.com/a_thieriot">Aurélien</a> talking about Scala in the dark. Unfortunately not recorded :(</p>
<h2 id="see-you-later">See you later</h2>
<p>To sum up, UDiff has been brilliant over the 3 (nearly 4) years it has been running. It has felt like mission accomplished in many respects as there are now loads more tech meet ups in Cardiff which I like to think UDiff at least influenced.</p>
<p>The timing of all this seems apt. All the guys organising are in a much different place to where they were when all this started, people have got married, had babies and so on. It’s a lot harder to find the time and energy basically.</p>
<p>However, I think we’re going out on a high and you never know, there could be a come back. With that in mind, I’ll end this with how Craig so succinctly put it in our email thread about this decision:</p>
<p>“Let’s just do an indefinite hiatus like all the best bands do.”</p>
<p><img src="http://localhost:4000/assets/img/600_276671772.jpeg" alt="Craig &amp; Rod" /></p>
</content>
</entry>
<entry>
<title>Building a house with DDD</title>
<link href="https://jenko.me/ddd/2015/01/23/building-a-house-with-ddd"/>
<updated>2015-01-23T00:00:00+00:00</updated>
<id>https://jenko.me/ddd/2015/01/23/building-a-house-with-ddd</id>
<content type="html"><p>For the past, I dunno, year or so, I’ve been reading a lot about <a href="http://en.wikipedia.org/wiki/Domain-driven_design">Domain Driven Design (DDD)</a> and even got to try it out on some projects. There are a number of resources which helped me out with this journey, but there are two stand out resources which really got me into it.</p>
<p>The first was <a href="https://www.youtube.com/watch?v=ajhqScWECMo">Ross Tuck’s excellent talk about Models &amp; Service Layers</a>, if you haven’t watched it yet, then definitely, definitely do. This got me thinking about the tactical parts of DDD such as commands, handlers and <a href="http://martinfowler.com/bliki/CQRS.html">CQRS</a>.</p>
<p>Having opened up a journey into trying out this new approach, reading <a href="http://www.amazon.co.uk/Implementing-Domain-Driven-Design-Vaughn-Vernon/dp/0321834577">red</a> and <a href="http://www.amazon.co.uk/gp/product/0321125215/ref=pd_lpo_sbs_dp_ss_1/277-9653975-7643565">blue</a> books and basically being stoked about it all, along came an article from <a href="http://everzet.com/">Everzet</a> called <a href="http://everzet.com/post/99045129766/introducing-modelling-by-example">‘Introducing Modelling by Example’</a> which took my understanding one step further and helped me understand how BDD fits in with all this.</p>
<p>Everything seemed to be clicking into place and so I wanted to try it all out. See if this approach worked for me. So I came up with a silly example project to ‘Build a house with DDD’ - note: the title could easily have been ‘Build a house with Modelling by Example’ or ‘Build a house with BDD’ or even ‘Build a house with TDD’ (<a href="http://vimeo.com/68375232">as BDD is what TDD is supposed to be right</a>).</p>
<h2 id="so-here-is-how-i-built-a-house-using-ddd">So here is how I built a house using DDD</h2>
<p><em>Note: I thought it’d be cool to do this commit by commit, gives a nice view of how each change was made etc. Unfortunately I only thought of this half way through writing it, so I am basically now the king of rebasing. Anyway, after I did this I came across <a href="https://github.com/MarcelloDuarte/pick-my-talks">a similar project created by Everzet which takes a similar approach</a>, it’s probably a better example of Modelling by Example (it was his thing after all!), although it doesn’t cover Command Handling etc. it’s <strong>definitely</strong> worth checking out.</em></p>
<p><a href="https://github.com/jenkoian/ddd-house/commit/ba1160626505e1f3a5df963bfa974178e6fc391d">Version0</a></p>
<p>Here I set up a fresh Symfony install and added some libraries I thought I would be going to use via composer. With hindsight, this is completely the wrong approach. I started with the framework here because that’s what I had been used to doing, but I actually don’t need the framework until much later in the process. So the lesson here, don’t do this. Don’t set up the framework until you are ready to, if you are using a
framework at all of course. Start with your domain.</p>
<p><a href="https://github.com/jenkoian/ddd-house/commit/f5a95111f479785454cf6cf5b765ca20cb61475b">Version1</a></p>
<p>Ignore the change to AppKernel which was again me thinking of the framework when I shouldn’t have been.</p>
<p>I’ve added my first feature file. It contains some examples of how the feature ‘navigating the house’ would work. Looking back, I’m now thinking this should be broken up. So, enter the house is a feature and the scenarios should contain examples of that. Overall though, you get the idea.</p>
<p>This file is the kind of thing that would derive from the conversation with the client. No code, just language.</p>
<p><a href="https://github.com/jenkoian/ddd-house/commit/f3fc5150db91a0ad1be9d56eb8b0af72a48f0026">Version2</a></p>
<p>The change to the behat.yml file is me just trying to tidy up, you can ignore that.</p>
<p>The changing of “outside the house” to “in the front garden” is just an example of me consolidating the language for consistency. I don’t think this is always appropriate, the language is always primary. However, in some cases I think it can actually help the language to be more consistent on some things.</p>
<p>Finally, I’ve added a context file which implements <code>SnippetAcceptingContext</code> which means it can be used to generate
some step definitions for me.</p>
<p>Once this is done, I run <code>bin/behat —append-snippets</code> to fill the context file with some template step definitions.</p>
<p><a href="https://github.com/jenkoian/ddd-house/commit/9abb0ec5c8d7918537ba84ed28b999798414aab4">Version3</a></p>
<p>Here I start designing my model. The use of <a href="http://verraes.net/2014/06/named-constructors-in-php/">Named Constructors</a> really helps here. It allows me to think purely about the domain at the interface level. This, for me, is where the true power
of Modelling by Example is. It’s BDD and indeed TDD in its truest form.</p>
<p>The fundamental thing to look at, is the language of the model and how it maps so directly the conversation with the client <code>$this-&gt;house-&gt;enterRoom($room)</code> etc. It’s DDD at play, and is a big step forward to the <code>$this-&gt;house-&gt;setRoom($room)</code> I may have done in the past.</p>
<p>It also helps point out gaps in the initial story, considerations that haven’t come up previously and thus making your model more resilient.</p>
<p><a href="https://github.com/jenkoian/ddd-house/commit/5661411bc0a6f5a0b942f9922150b045709be1c3">Version4</a></p>
<p>This is the point where I move in a level to actually writing the domain models designed from <a href="http://behat.org">behat</a>. Here I use <a href="http://phpspec.net">PHPSpec</a> to aid me in the creation of these models. The benefits of this is that it re-enforces that approach of designing through the interface, but it also ensures mistakes are caught and even more, it basically writes the models for you, with it’s excellent interactive spec runner.</p>
<p>Finally (no pun intended) you may spot the use of final in front of the class names. I had seen this been used but wasn’t really sure why, until I heard <a href="https://www.youtube.com/watch?v=UIDlOV40xCY&amp;list=PLo7mBDsRHu123EqX-kXnE2tLYXtdbVuzf#t=2871">Everzet’s explanation of it at Symfony Live London 2014</a> and
subsequently the <a href="http://ocramius.github.io/blog/when-to-declare-classes-final/">excellent blog post by Ocramius on when to use final</a>. I now see why using final is a great idea and it has even subsequently altered how I think when designing classes.</p>
<p><a href="https://github.com/jenkoian/ddd-house/commit/3dab522b244512d6fbfad70d27d947819d9c16b2">Version5</a></p>
<p>Some further refactoring of the models basically following the Red -&gt; Green -&gt; Refactor loop at this point. Abstract Rooms and Gardens with Location. Why not just use Location altogether? Perhaps, but wanted to maintain the language. You don’t enter a Location as such, you enter a room or the garden.</p>
<p><a href="https://github.com/jenkoian/ddd-house/commit/bc7dc0840e634ab22475aee1d5b97a7ad5221427">Version6</a></p>
<p>Further refactoring, add a way of entering rooms.</p>
<p><a href="https://github.com/jenkoian/ddd-house/commit/f68fd0975ead6a6a1177732491ed3d29ba021880">Version7</a></p>
<p>I thought it would be neat to be able to enter a room from just a room name, as well as a Room object.</p>
<p><a href="https://github.com/jenkoian/ddd-house/commit/d125b4a7f5e2ab55ce0910c7c4bd1d240d336f68">Version8</a></p>
<p>Adding a way of exiting a room. Notice it’s very similar to entering a room but it’s important that the language is maintained. We can tidy up the code re-use later, although as a side note I like <a href="http://verraes.net/2014/08/dry-is-about-knowledge/">Mathias Verraes’ definition of DRY</a>.</p>
<p><a href="https://github.com/jenkoian/ddd-house/commit/1cd52fe156bfd5a93118aac5348988d08142d028">Version9</a></p>
<p>A minor change to the behat context to ensure room can be entered through their name.</p>
<p><a href="https://github.com/jenkoian/ddd-house/commit/56319d09ada9b9a08fe682d697a3973bf36d6bb2">Version10</a></p>
<p>Here we add our first Value Object, Dimensions. Again, using PHPSpec as the crutch to aid the design. Dimensions is defined as a Value Object because it has no identity and is considered equal based on attributes of the class, in this case: width &amp; height. Dimensions can be set on a location.</p>
<p>I found <a href="http://richardmiller.co.uk/2014/11/06/value-objects/">Richard Millers post on Value Objects</a> good if you require more information about them have a read.</p>
<p><a href="https://github.com/jenkoian/ddd-house/commit/a81431f281b154644c0f899afb64ace67b74d50d">Version11</a></p>
<p>What happens if we try and enter a room which doesn’t exist? Let’s add an exception for this.</p>
<p>It’s important to note at this point that at all work between versions I’m running <code>bin/behat</code> and <code>bin/phpspec run</code> constantly and fixing any errors or discrepancies that may arise and using this whole process to shape the domain models.</p>
<p><a href="https://github.com/jenkoian/ddd-house/commit/802936f09a1c85c06c7b5b572f45d4e76b0b6b69">Version12</a></p>
<p>Adding steps for checking dimensions and exits are available. These weren’t explicit in our initial conversation but through working through the model and subsequent (ok fake in this case) conversations with the client it’s now apparent that dimensions and exits are part of this model. In true DDD style, making the implicit, explicit.</p>
<p><a href="https://github.com/jenkoian/ddd-house/commit/50fce972753cab2f914a4569762bb4ba99d25b35">Version13</a></p>
<p>Just removing a no longer required method. Red -&gt; Green -&gt; REFACTOR.</p>
<p><a href="https://github.com/jenkoian/ddd-house/commit/2712efbf1e3719b0295c3cc547176ad405beb262">Version14</a></p>
<p>Just me tidying up the behat file. In this contrived example we aren’t going to be doing anything special with potential buyers, so we can just get rid of this explicit context for now.</p>
<p><a href="https://github.com/jenkoian/ddd-house/commit/83cbbd8651af8514211d0c6198b9512e10cb5211">Version15</a></p>
<p>One thing that was bothering me was how to exit a room. I didn’t want to have circular references for example. So here I have a property of the previous location so we know where we’ve come from and a way of exiting to a room (notice we’ve tidied up that duplicated code from earlier too).</p>
<p><a href="https://github.com/jenkoian/ddd-house/commit/2355c7582e8260d7cb03401bfad48fcc30174fe6">Version16</a></p>
<p>Allowing our Locations to have exits.</p>
<h2 id="a-raspberry-pi-without-the-ports">A Raspberry Pi without the ports</h2>
<p>Before I move on to the more tactical parts of DDD, let’s stop and think about what we’ve just done. At this point I’d consider the domain model to be quite complete. Of course it could evolve with further conversations with the client, but from what we know of the domain thus far, I think it’s pretty complete.</p>
<h3 id="so-what-do-we-have">So what do we have?</h3>
<ul>
<li>A working domain model</li>
<li>Created from the ubiquitous language</li>
<li>High level behat stories and lower level PHPSpec tests proving it works</li>
<li>We’ve not touched any framework code</li>
<li>We’ve kept code to a minimum</li>
<li>We’re completely decoupled</li>
</ul>
<p>We essentially have a <em>Raspberry Pi without any ports</em>.</p>
<p><img src="http://localhost:4000/assets/img/pi_bare.jpg" alt="Raspberry Pi without any ports" /></p>
<p>If you think about <a href="http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html">the clean architecture</a> diagram below, we have our middle layer.</p>
<p><img src="http://localhost:4000/assets/img/CleanArchitecture.jpg" alt="Clean architecture" /></p>
<p>It’s time now to work out from the middle into the other layers. So let’s add some ports onto our Raspberry Pi so we can connect it to something to make it useful.</p>
<p><a href="https://github.com/jenkoian/ddd-house/commit/60f9b70ab227785a5e503a4ed88c7da01d98adc9">Version17</a></p>
<p>I’ve simply added two commands for entering rooms and exiting rooms at this point. These are two lightweight DTOs that will be used as a means of transferring messages from our framework into our domain.</p>
<p><a href="https://github.com/jenkoian/ddd-house/commit/e4ace656623d57cb78b6c8e5dc9b870b33ef4186">Version18</a></p>
<p>A long with commands, I’ve identified an event, <code>EnteredRoomEvent</code>. This would ordinarily be done through some kind of event storming session with the client.</p>
<p><a href="https://github.com/jenkoian/ddd-house/commit/0952bb45115bb90786b0b685a0ce04de41cf7091">Version19</a></p>
<p>So as you may have noticed I’ve been avoiding persistence throughout this. It’s a small, simple, contrived example which I didn’t want to muddy by adding any means of persistence. I realise this perhaps removes validity to the example, but I don’t really care. This is more about how to model a domain with a modelling by example approach, as opposed to the intricacies of database persistence with DDD.</p>
<p>However, I did want a tidier way of dealing with the state of the House. Building the house in the constructor every time wasn’t ideal. So I came up with this idea of a factory. Because we all know houses come from factories right? In essence it’s more of a singleton, which works for me here. I’m still building the house on every request, but at least this does it in a clear and re-usable manner. It also doesn’t get me bogged down in persistence when it’s not my primary aim here.</p>
<p>The final thing to note is that I added some basic handlers to handle the commands I created earlier. These are likely to change but are fine for the time being.</p>
<p><a href="https://github.com/jenkoian/ddd-house/commit/b8ebbea1bf200e399661f252acc4aee9ff7d2da9">Version20</a></p>
<p>Adding a Symfony bundle and some basic infrastructure.</p>
<p>Where I say in Version0 I shouldn’t have been adding the framework, it’s in this commit where I should have been.</p>
<p>Few things to point out here. Firstly, the lightweight controllers. They do little more than take the request, set up the command and pass it off to the handler.</p>
<p>When I first started this, I was very much of the mindset:
decouple from the framework, controllers as services etc. I agree massively with decouple from the framework with regards the domain and even the ports layer (commands/handlers) but, <a href="http://thatpodcast.io/episodes/episode-10-the-one-with-the-best-practices/">similar to what Dave mentions in ‘that podcast’ episode 10</a>, I’ve come a little full circle in the controllers as services and using DI to completely
decouple your controllers. I now feel, it doesn’t really matter. So long as your controllers are really light, it doesn’t really matter if they’re tightly coupled, because essentially they don’t matter. They are merely passing messages from framework to domain. The second point to note is that you can see from the images and twig templates how advanced my UI is going to be :).</p>
<p><a href="https://github.com/jenkoian/ddd-house/commit/73bb68c1d9fe6a9d125191b3e535af3fb1165c09">Version21</a></p>
<p>Adding exits and dimensions to rooms for a fuller experience.</p>
<p><a href="https://github.com/jenkoian/ddd-house/commit/2c2ec90ebf0d55b5bf30366df99a1dfd31e14077">Version22</a></p>
<p>The main thing I did in this commit was to add an event dispatcher. I throw a domain event in my model when entering a room and needed the dispatcher in place to support that.</p>
<p>As I am using Symfony it made sense to me to use the Symfony event dispatcher. However, it is a bit of a pain because it expects an event to have a name and to be of type <code>Symfony\Component\EventDispatcher\Event</code>. As I was trying to follow the clean architecture and have no outer dependencies I didn’t want to have my event extend <code>Symfony\Component\EventDispatcher\Event</code>.</p>
<p>Therefore, I needed to create an adapter. Going back to the Raspberry Pi analogy made in a previous version. I needed a Serial to USB adapter, or something like that. I’m starting to add some ports on to my Pi.</p>
<p><img src="http://localhost:4000/assets/img/pi_ports.jpg" alt="Raspberry Pi with ports" /></p>
<p>I also wanted to use my own Dispatcher interface, because what if I wanted to stop using the Symfony dispatcher and replace it with something else? I want to be able to continue using the same interface but just add a new adapter and change my DI. I want to be decoupled.</p>
<p>You can see how I achieved this from the code within this commit. Finally, I added a <code>HandlerInterface</code> so that I can swap out handlers using DI should I need to also.</p>
<p><a href="https://github.com/jenkoian/ddd-house/commit/dcb675d273260b6a9e0af7948a26945ca2605a01">Version23</a></p>
<p>Adding an event subscriber to log when a room is entered.</p>
<p>I again used the adapter approach and created my own interface for logging/event subscribing. I then have an adapter for example using PSRLogger which is easily replaceable should I need to.</p>
<p><a href="https://github.com/jenkoian/ddd-house/commit/4fdc5ed94368ef1656ea80e6fde634a58020cc04">Version24</a></p>
<p>To show off the benefits of decoupling domain from the framework I wanted to show an example of how the domain could be used outside the browser, so I thought it’d be cool to set up a quick CLI example.</p>
<p>Symfony makes it trivial to add CLI programs, and you can see from this commit how exactly it works. Essentially it’s the same deal as controllers. Request in -&gt; Create command -&gt; Pass off
to Handler.</p>
<p><img src="http://localhost:4000/assets/img/dddhouse-cli.gif" alt="CLI version of the house" /></p>
<p><a href="https://github.com/jenkoian/ddd-house/commit/a9ca03a9d882cf03d1e8ca48f17f9780a62ec1f5">Version25</a></p>
<p>Adding a command bus and separate out command handling from domain.</p>
<p>If you’re unsure what a command bus is or does, <a href="http://shawnmc.cool/command-bus">I’d recommend Shawn McCools excellent post on them</a>.</p>
<p>After initially considering <a href="https://github.com/tabbi89/CommanderBundle">CommanderBundle</a> I eventually opted for <a href="https://github.com/SimpleBus">SimpleBus</a> because I liked the simplicity and have a lot of respect for it’s maintainer Mathias. I did have <a href="https://github.com/SimpleBus/CommandBus/pull/2">some misgivings over the use of a type hint for commands</a>, but generally it suited what I needed to do well, it also forced me to create an explicit CommandHandling layer, which I think works quite well. It’s been completely changed in version 2 now anyway, and is <a href="https://github.com/SimpleBus/MessageBus">more of a generic ‘MessageBus’ now</a>.</p>
<p>There are quite a few command buses that have popped up recently, I created <a href="https://github.com/jenkoian/CommandBusCommandBus">CommandBusCommandBus</a> as a case in point. To be honest with you though, the command bus is a really simple concept and you may even be better off just rolling your own if you don’t need anything fancy. The main reason I went with Simple Bus was because it <a href="https://github.com/SimpleBus/SymfonyBridge">hooked into Symfony quite nicely</a>.</p>
<p>Anyway the point is I wanted to introduce a command bus to make my example complete.</p>
<p>Here you can see how I’ve moved all the command handling bits to the CommandHandling layer (or ports layer as I’ve heard Ian Cooper describe it) I spoke about above. It just means that rather than passing command to handlers directly, I can just ‘throw’ them on to the command bus now. This has the advantages of being able to decorate the command bus to be able to perform additional tasks against commands should I want to; I can make the command bus handle commands asynchronously should I choose; plus other niceties that arise when delegating message handling in this way.</p>
<h2 id="and-were-done">…and we’re done!</h2>
<p>You can check out the crib on heroku: <a href="http://dddhouse.herokuapp.com">http://dddhouse.herokuapp.com</a></p>
<p>You may have guessed from the code but that is indeed the Home Alone house.</p>
<p>Ok, it’s not going to win any design awards, but with a bit of imagination you can perhaps picture some interactive JS whizzy interface which allows you to hover over doors and enter rooms in a fun way.</p>
<h2 id="so-lets-recap-what-weve-done">So let’s recap what we’ve done</h2>
<ul>
<li>Created our core domain using Modelling by Example/BDD/TDD</li>
<li>Worked our way out from the middle</li>
<li>Identified our use cases (commands)</li>
<li>Created our infrastructure</li>
<li>Added ports into our domain</li>
<li>Created adapters to plug our infrastructure into our domain</li>
<li>Created a working application</li>
</ul>
<p>We’ve gone from components to a Raspberry Pi logic board, to a Raspberry Pi with Ports, to a Raspberry Pi with a case - the next step would be to a Raspberry Pi with a fancy case (the JS whizzy version I alluded to above).</p>
<p><img src="http://localhost:4000/assets/img/pi_cycle.png" alt="Raspberry Pi Cycle" /></p>
<h2 id="where-do-we-go-from-here">Where do we go from here?</h2>
<p>One thing I haven’t tackled yet is end-to-end testing, or acceptance testing.</p>
<p>For a while, at work, I’ve often thought we were missing a trick in how QA is integrated with development. In that, it isn’t really. It all feels a little ‘thrown over the wall’. Although, I’ve not done anything with regards this at the time of writing I have a few ideas off the back of this as to how to integrate them closer. I’ll use another post to go in to details, but I’m thinking QA could be involved in the initial feature writing (Given/When/Then). Then when it comes to acceptance testing, they write their automated scripts using <a href="http://watir.com/">Watir</a> (what they currently use anyway) and <a href="http://cukes.info/">Cucumber</a> but re-using the feature files developed for creating our domain.</p>
<p>So I’m quite keen to give that a go, maybe using the house as a nice example application, or perhaps starting a new internal application. Either way, I’m quite stoked about the possibilities.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Theoretically I was a big fan of this approach and practically it hasn’t altered my view. My domain seems so much more concise, and uses the ubiquitous language in a substantial way. It’s made a number of concepts click for me. Take TDD for example, I’d often liked the idea but didn’t truly understand it. I’d taken a test first approach before, but wasn’t that sold on it. However, this subtle difference in approach to TDD has unlocked it’s power for me. I now think, through a combination of <a href="http://vimeo.com/68375232">the excellent talk by Ian Cooper</a>, and this Modelling by Example approach that I ‘get TDD’. It’s about design, not about testing.</p>
<p>What I have learned through taking this approach is how DDD can really work for me. Not just the tactical parts either. I feel I now have a better understanding of how to turn conversations directly into code; How to design aggregates around entities and value objects and how to use ports and adapters to ensure decoupling.</p>
<p>Ok, my example is small and contrived but it’s been enough to expose me to a practical use of these approaches. I’m left with little doubt that this could work on larger projects and have indeed started using it on larger, albeit internal at the moment, projects and have to say it brings everything together quite nicely.</p>
<p>A silver bullet I’m sure this is not, but I can imagine this kind of thing to work in lots of scenarios. It reduces complexity to the point I can see paths forward in projects where before I may have been scratching my head.</p>
<p>Finally, the other brilliant thing about all this is the excellent community behind it. The PHP community has really embraced DDD and has really been pushing some of the ideas, but also people like Ian Cooper and Greg Young from the .NET world have become a huge source of inspiration for me.</p>
</content>
</entry>
<entry>
<title>Some thoughts on Agile</title>
<link href="https://jenko.me/opinion/2014/08/08/some-thoughts-on-agile"/>
<updated>2014-08-08T00:00:00+01:00</updated>
<id>https://jenko.me/opinion/2014/08/08/some-thoughts-on-agile</id>
<content type="html"><p>I would in no way describe myself as an evangelist of Agile practices, I’m not a certified scrum master and I’ve never had any formal training or anything on Agile practices. However, over the last few years the company I’ve worked for has adopted an agile methodology and so I’ve had no choice but to have had some experience with Agile. Here are some of my thoughts on ‘Agile’, or working with ‘Agility’ or whatever the hell you wanna call it.</p>
<h2 id="kanban-and-scrum">Kanban and Scrum</h2>
<p>It took me ages to work out what these terms exactly meant. I’m still not 100% sure, but this is my take.</p>
<p>Kanban I see as basically trello. You work from left to right in a production line type approach. So you’d still have user stories and possibly story points, although I don’t think it’s as important in Kanban and you’d basically move the stories or tickets through the pipe line, from (typically) to-do to done, via some variation of in-progress, merged and ready for testing. I basically see Kanban as a lightweight version of Scrum.</p>
<p>Scrum for me is the fuller version of Kanban. So you still have the board and the production line approach, but you split work up into sprints, work towards a velocity and plan and demo with the product owner in order to maintain focus on what the product will turn out like. Oh, you have daily ‘scrums’ which are basically stand ups where everyone gets updated. People put a lot of emphasis on this, but for me it’s a minor detail. It just makes sense to catch up daily to update each other?</p>
<p>It’s this Scrum approach I’m going to be talking most about in the rest of this post.</p>
<h2 id="user-stories-are-king">User Stories are king</h2>
<p>In my experience, the user stories are <em>the</em> most important part of the entire process. Without good user stories it makes it really difficult to estimate, get a good idea of velocity and deliver features ready to demonstrate.</p>
<p>User stories are difficult. When you read one, a good one, it will not appear that way. It will appear as almost too simplistic. Getting to that point however, can be very hard.</p>
<h3 id="what-makes-a-good-user-story">What makes a good user story?</h3>
<p>This is in my opinion what makes a user story a good one.</p>
<ul>
<li>Describes exactly what the feature should do.</li>
<li>Should have no hard dependencies.</li>
<li>Should have a list of Acceptance Criteria (AC).</li>
<li>Should be short and concise.</li>
</ul>
<p>Let’s go into a bit more detail, with some example user stories.</p>
<p>A bad example:</p>
<p><em>As a User I want to see notifications.</em></p>
<p>A good example:</p>
<p><em>As a logged in User, when I am on my dashboard I want to see a list of notifications at the top of the page.</em></p>
<p>Let’s break down this example.</p>
<p><em>As a logged in User</em></p>
<p>We specify that the User needs to be logged in at this point. If you have various Roles in your application it would make sense to include that in the story also, e.g. <em>As a logged in Editor</em>.</p>
<p><em>when I am on my dashboard</em></p>
<p>Now, this isn’t perfect. The reason being that this indicates a dependency. What is dashboard? You are assuming in your story that there is a dashboard in place, and thus you can’t work on this story until a dashboard has been created.</p>
<p>I think this kind of dependency, which I’d call a ‘soft’ dependency is inevitable. You will undoubtedly come up against situations like this. I think there are two things we can do to help here.</p>