Thursday, May 30, 2019

JavaScript: Crack for coders.

I've been cutting code for a long time. I was educated in Assembler, Pascal, and C/C++. I couldn't find local work doing that so I taught myself Access, Visual Basic, T-SQL, PL-SQL, Delphi, Java, Visual C++, and C# (WinForms, WebForms, MVC, Web API, WPF, and Silverlight). It wasn't until I really started to dive into JavaScript that programming started to feel "different".

With JavaScript you get this giggly-type high when you're sitting there in your editor with a dev server running on the other screen tinkering away and the code "just works". You can incrementally build up your application with "happy little accidents" just like a Bob Ross painting. WebPack and Babel automatically wrangled the vast conflicting standards for modules, ES versions, and such into something that actually runs on most browsers. React's virtual DOM makes screen updates snappy, MobX is managing your shared state without stringing together a range of call-backs and Promises. And there is so much out there to play with and experiment. Tens of thousands of popular packages on npm waiting to be discovered.

But those highs are separated by often lingering sessions testing your Google-fu trying to find current, relevant clues on just why the hell your particular code isn't working, or how to get that one library you'd really like to use to import properly into your ES6 code without requiring you to eject your Create-React-App application. You get to grit your teeth with irritations like when someone managing moment.js decided that add(number, period) made more sense than add(period, number) while all of the examples you'd been using had it still the other way around. Individually, these problems seem trivial, but they really add up quick when you're just trying to get over that last little hurdle between here and your next high.


JavaScript development is quite literally Crack for coders.

Monday, May 20, 2019

YAGNI, KISS, and DRY. An uneasy relationship.

As a software developer, I am totally sold on S.O.L.I.D. principles when it comes to writing the best software. Developers can get pedantic about one or more of these principles, but in general following them is simple and it's pretty easy to justify their value in a code base. Where things get a bit more awkward is when discussing three other principles that like to hang out in coding circles:

YAGNI - You Ain't Gonna Need It
KISS - Keep It Stupidly Simple
DRY - Don't Repeat Yourself

YAGNI, he's the Inquisitor. In every project there are the requirements that the stakeholders want, and then there are the assumptions that developers and non-stakeholders come up with in anticipation of what they think stakeholders will want.YAGNI sees through these assumptions and expects every feature to justify it's existence.

KISS is the lazy one in the relationship. KISS doesn't like things complicated, and prefers to do the simplest thing because it's less work, and when it has to come back to an area of a project later on, it wants to be sure that it's able to easily understand and pick the code back up.  KISS gets along smashingly with YAGNI because the simplest, easiest thing is not having to write anything at all.

DRY on the other hand is like the smart-assed, opinionated one in a relationship. DRY wants to make sure everything is as optimal as possible. DRY likes YAGNI, and doesn't get along with KISS and often creates friction in the relationship to push KISS away. The friction comes when KISS advocates doing the "simplest" thing and that results in duplication. DRY sees duplication and starts screaming bloody murder.

Now how do you deal with these three in a project? People have tried taking sides, asking which one trumps the other. The truth is that all three are equally important, but I feel that timing is the problem when it comes to dealing with KISS and DRY.  When teams introduce DRY too early in the project you get into fights with KISS, and can end up repeating your effort even if your intention wasn't to repeat code.

YAGNI needs to be involved in every stage of a project. Simply do not ever commit to building anything that doesn't need to be built. That's an easy one.

KISS needs to be involved in the early stages of a project or set of features. Let KISS work freely with YAGNI and aim to make code "work".  KISS helps you vet out ideas in the simplest way and ensure that the logic is easy to understand and easy to later optimize.

DRY should be introduced into the project no sooner that when features are proven and you're ready to optimize the code. DRY is an excellent voice for optimization, but I don't believe it is a good voice to listen to early within a project because it leads to premature optimization.

Within a code base, the more code you have, the more work there is to maintain the code and the more places there are for bugs to hide. With this in mind, DRY would seem to be a pretty important element to listen to when writing code. While this is true there is one important distinction when it comes to code duplication. Code should be consolidated only where the behavior of that code is identical. Not similar, but identical.  This is where DRY trips things up too early in a project. In the early stages of a project, code is highly fluid as developers work out how best to meet requirements that are often still being fleshed out. There is often a lot of similar code that can be identified, or code that you "expect" to be commonly used so DRY is whispering to centralize it, don't repeat yourself!

The problem is that when you listen to DRY too early you can violate YAGNI unintentionally by composing structure you don't need yet, and make code more complex than it needs to be. If you optimize "similar" code too early you either end up with conditional code to handle the cases where the behaviour is similar but not identical, or you work to try and break down the functionality so atomically that you can separate out the identical parts. (Think functional programming) This can often make code a lot more complex than it needs to be too early in the development leading to a lot more effort as new functionality is introduced. You either struggle to fit with the pre-defined pattern and restrictions, or end up working around it entirely, violating DRY.

Another risk of listening to DRY too early is when it steers development heavily towards inheritance rather than composition. Often I've seen projects that focus too heavily and too early on DRY start to architect systems around multiple levels of inheritance and generics to try and produce minimalist code. The code invariably proves to be complex and difficult to work with. Features become quite expensive to work with because they cause use cases that don't "fit" with previous preconceptions of how related code was written to be re-used. This leads to complex re-write efforts or work-arounds.

Some people argue that we should listen to DRY over KISS because DRY enforces the Single Responsibility Principle from S.O.L.I.D.  I disagree with this in many situations because DRY can violate SRP where consolidated code can now have two or more reasons to change.  Take generics for example. A generic class should represent identical functionality across multiple types. That is fine, however you can commonly find a situation where a new type could benefit from the generic except...   And that "except" now poses a big problem. A generic class/method violates SRP because it's reason for change is governed by every class that leverages it. So long as the needs of those classes is identical we can ignore the potential implications against SRP, but as soon as those needs diverge we either violate SRP, violate DRY with nearly duplicate code or further complicate the code to try and keep every principle happy. Functional code conforms to SRP because it does one thing, and does it well. However, when you aren't working in a purely functional domain, consolidated code serving a part of multiple business cases now potentially has more than one reason to change. Clinging to DRY can, and will make your development more costly as you struggle to ensure new requirements conform.

Personally, I listen to YAGNI and KISS in the early stages of developing features within a project, then start listening to DRY once the features are reasonably established. DRY and KISS are always going to butt heads, and I tend to take KISS's side in any argument if I feel like that area of the code may continue to get attention or that DRY will risk making the code too complex to conveniently improve or change down the track.  I'll choose simple code that serves one purpose and may be similar to other code serving another purpose over complex code that satisfies an urge not to see duplication, but serves multiple interests that can often diverge.


Wednesday, April 10, 2019

The stale danish


One Monday, while walking to the office you pass a little bakery with a window display. A beautiful looking danish catches your eye. The crust looks so light and fluffy, a generous dollop of jam in the middle, and the drizzle of icing sugar. So tempting, but you promised yourself to cut back on the snacks, and continue your way to the office.

Each morning, you walk past that same bakery and see a danish sitting there, just beckoning you... Finally, Friday morning comes around and you see that gorgeous danish waiting there. "I can't take it any more!" you scream to yourself and you give in, walk into the bakery and buy the danish. After the guilt melts away holding that beautiful danish, you take a bite... It's long since gone stale, having been sitting there since Monday.

The stale danish is how I view the Internet, and the marvelous source of information we, as software developers have come to rely on it for. When technology is new, the Internet provides a flury of information and experiences that the global software development community collectively accumulates. However, much of the time, that information isn't versioned, and often sources like blog posts & walk-throughs aren't even dated. As the technology matures, finding the information you need to solve a particular problem becomes a treasure hunt to find a fresh danish in a sea of stale ones. Working with JavaScript frameworks like React and it's supporting libraries like Redux in particular has proven extremely challenging time and time again. Every undated bit of information needs to be taken with a grain of salt, and it's compounded by the fact that with JavaScript, there are always a number of variations to do what should be relatively standard stuff, all conforming to different interpretations of "best practices".

Even normal consumers of information are getting tricked by the stale danishes floating around the web. Technologies like Google street view in particular are marvelous, but they require constant updates because as the world around us changes, the maps and camera images quickly become out of date. Using these services to assist with landmarks can be fraught with danger as you're looking for an intersection after a car dealership or restaurant that relocated six months ago. At least Google had the common sense to put dates on their imagery.

The stale danish is the one key reason that I would much, much rather work in the back end with technologies like .Net, Entity Framework, and SQL, than working in the front end with JavaScript libraries. I love working in the front end, solving usability issues and presenting users with useful views to data and features they need. I enjoy MVC, WPF, and had enjoyed Silverlight largely because the pace of change was a lot slower, and there were a handful of sources to find directly relevant information about the technologies and how to effectively use them.

JavaScript, and open source in general is far more volatile. While you may argue this makes it more responsive so that problems get solve more quickly, the real trouble is that everyone's perception of a problem is different, so there are a lot of "solutions" out there that are screaming on the web for validation. As a software developer, projects need to have a completion date so you do need to choose from those available options at the time, and commit to them. Having relevant and accurate information at hand through the life of the project is essential for when challenges do crop up. Ripping out X to replace it with Y isn't an option, and often the breaking changes from X v0.8 to X v0.9 prohibit the idea of upgrading, so when searching for possible answers and work-arounds to problems, it would be a wonderful if more articles and posts were versioned, or at least had a "Baked On" date listed.