Saturday, November 19, 2016

My take on software quality, common pitfalls, and the mindset for success.

Common Pitfalls

This article applies to all branches of software development, and is my view on software quality, based on 12 years of experience as a software engineer.  We will be looking at common pitfalls, and how they can be addressed by a particular line of thought or strategy. 
What makes software projects have poor quality and grind to a halt, or have costly production defects?  Based on industry feedback, some of the following symptoms are causes of software failure: 
  1. Insufficient attention to detail and care for the code.  (Patch on patch, fixing only immediate symptom, without understanding root cause). 
  2. Lack of proper object-oriented architecture (resulting in ever increasing complexity of code). 
  3. Copy and Pasted code (violation of DRY)
  4. Improper design (violation of SOLID)
  5. Poor coding practices (huge methods, too many conditional statements or "accidental complexity")
  6. Separation of concerns missing. (Grouping many duties into one method, class, object, event or variable. ). 
  7. Unclear definition of concern separation. (Not sure what is the single responsibility of each class, method, variable, object, etc) 
  8. Unclear / ambiguous naming of variables / objects.  Names not specific enough, resulting in need for comments. 
  9. Fear of refactoring.  Fear of making changes.   (Afraid because we are not sure what is broken after making a change). 
  10. Lack of or complete absence of unit tests, resulting in no way to cheaply have assurance of correct behaviour upon making changes. 
  11. Inability to "Step Back" and ask really difficult and uncomfortable questions.  (Should we even be doing this?  What's the benefit?)  - Tunnel Vision. 
  12. Lack of "Ownership" of the code.  Afraid to change.  Unwilling to figure out how it works.
  13. I'll remember to do it later.  It's fine for now. 
  14. I really want to learn this new thing, so i'll use it, even though it's doesn't quite fit. 
  15. Accidental complexity allowed to continue unchecked. We keep adding features without thinking about design and making the code easy to re-use and grow. 
  16. The "Not enough code" syndrome.  Now we all know that "less code is better", mainly for maintenance reasons.  But actually, a lot of the time, you need to have a lot of code in order to fully address the requirement, and do a good job implementing the feature you envisioned.  Things are often simple on the surface, but you need to have a great UX and cover all the edge cases.  So you might need to write a lot of code.  Just make sure to architect it in a way that makes it all separated by responsibility.  Don't compromise on that.  Ask yourself: "Does this software suck because we didn't fully flesh out how it should work?" 

Strategy for Success

So how do we not only avoid the above grim situation, but on the contrary: achieve the complete opposite?  We reverse each point above into its' positive counterpart: 
  1. Meticulous attention to detail in every line of code we write. (We should be proud and confident about our code.  We can easily speak about the decisions we made and their justifications. Not:  "it sorta works, i guess". ). 
  2. Think through the design of every feature first.  Even if its' a minor feature.  Examples:
    1. Do i put this in the view controller?
    2. Is this likely going to be reused later by someone?
    3. Can it be made completely generic?  What's the extra effort in doing so? 
    4. Does adding this increase the complexity of the class where we are adding this? (and thus it's $$$ maintainability)
    5. By adding my code, did i just make the object do more than 1 task?
  3. Is this task already done somewhere else?  Is it in multiple places?   Can i take it out of those various places and instead put it in one place, and reuse that?   
    1. Doing this for every feature you implement continuously improves the overall strength of the code base. 
    2. Notify other developers of these reusable resources:  building up your team's "Toolbox".    ("Hey, i made this category which makes sure things are done on the main thread, with one line of code!") 
  4. Refer to wikipedia, on SOLID definition.  (https://en.wikipedia.org/wiki/SOLID_(object-oriented_design))
    1. In Pull requests, the reviewer, can asses each of SOLID's properties, to check for violations.  Fix at PR stage. 
  5. Enforce the following guidelines:
    1. Methods can only be 20 lines of code or less. 
    2. Classes must be 700 lines of code or less.  (If exceeding this, start making component classes out of your class with Roll-Up objects, that can just be used with a few lines of code - Facade pattern). 
    3. Nesting (If, switch, loops, blocks), not more than 2 levels deep.  (3 levels deep or more = you must break it up into separate methods). 
    4. Single responsibility for every object.  Few exceptions are:  Facade class which manages other objects, but know little to nothing about how they work internally. 
    5. Rely on abstractions in areas which are likely to change.  (In other words: if something is likely to change, put an interface around it, with a simplified entry point to the functionality).  I believe abstracting everything is a waste of time though.  So the judgement call is:  What is most likely to change? 
  6. What is the primary responsibility of this class (every class)?  The answer should be provided in one short sentence, always. 
  7. We should first define what the different "Concerns" are, and then consciously place classes into those buckets.  
    1. For example, responsibility can be separated into into: 
      1. Networking
      2. Navigation
      3. Persistence
      4. Generic Views/Controls
      5. Business Specific Views/Controls (can reuse Generic Views internally) 
      6. View Controllers (screens comprised of components) 
      7. Components.  (More complex than just a view or control.  It's a business-specific UX piece that does a single job). 
      8. Utilities.  (Many categories here.  These are always generic and reusable.  Do not know about business rules, that are likely to change). 
      9. Configuration
      10. Styling (Style sheet)
      11. Localization
      12. Accessibility
      13. Analytics
      14. Validation
      15. Alert / Dialog utilities
      16. Resource / media access  (really easy way to access images from network or local)
  8. "Take that comment and make it a method".  
    1. Then put the code into that method.  
    2. Voila = self-documenting code. 
    3. It's OK to have long method names (within reason).  
    4. If the name is too long, then is it doing more than one thing??
  9. The more you do refactoring as you implant features, the easier it will become.  Just like any skill - it's acquired over time.  I believe refactoring should be constant, as development continues. 
  10. Let's say you have 600 unit tests.  You can run them overnight on all OS versions, example: iOS 8.0, .1, .2, .3, iOS 9.0, .1, .2, .3. iOS 10, etc...   You will uncover edge cases on specific iOS versions using these tests.  You would have to have an entire QA department, and QA manager distributing work for them, to do this manually.  The cost would be 100 times or 1000 times more. 
    1. There definitely is a trade-off overhead in managing the tests, and setting up the CI for the first time.  But the act of managing the tests does give you extra insight into the state of the code.  (Reality check - what did i just break?, or how can the architecture be improved?). 
  11. The best code is No-Code  (guaranteed bug-free!!).  If you can avoid implementing something, just make the decision not to, and justify it objectively.  Some business requirements go away by themselves.  This is because assumptions get dispelled, and stakeholder input causes initial claims to be invalidated, making some requirements obsolete.  Example:  Your customer later tells you: "We actually can't have this feature because it violates privacy regulation number N".   
  12. "I just have to implement this one feature", i will just do it.   I can first check whether it's done similarly somewhere else.  I can ask another developer about it first.  Maybe someone in the department already delved into a similar task.  I shouldn't be afraid of making larger changes than what I planned.  Refactoring can improve the maintainability of the code. 
  13. Fact: The cost to fix bugs grows exponentially the later they are detected.  Example:
    1. Cost to fix in dev: $10
    2. Cost to fix in QA: $100
    3. Cost to fix in UAT: $1000
    4. Cost to fix in production $10000 or more.

      It's also better to leave the code in the best state possible, so other developers don't have the cost overhead of asking about what's going on.
  14. Using tech just because you want to put it on your resume is selfish, because you can just implement it simpler using standard tools, but using SOLID.  "A new co-op student should be able to figure it out".  
  15. Keep making easy to use facades in the code, abstracting away complexity.  Keep refactoring the code until it fits into the following set of guidelines: 
    1. Methods can not be longer than 20 lines of code. 
    2. Classes can not be longer than 700 lines of code. 
    3. Nesting of If statements, loops or scope levels can not be more than 2 levels deep. 
  16. Perhaps the implementation could be improved.  Sometimes this includes a lot of effort, R&D, or sheer brute force coding, but as long as the code is structured properly, it's OK to have a lot of code.  (Just think of a piece of software like MS Office, and how much code it has).  
Learn how to create your own Programming Language here!!

Monday, March 7, 2016

What does Playing an Instrument and Computer Programming have in common


I am a guitar player and a computer programmer.

I enjoy designing and coding software, as well as improvising on the guitar, particularly in the jazz, rock and fusion styles.  I've been thinking a bit about how music and programming actually have a lot in common. These 10 things are just the aspects that jump out at me, and may not necessarily work for you.

  1. Math at the Core: Computer programming uses math concepts to improve efficiency of code, such as when you're looking for an algorithm that executes in less time for your particular scenario, uses less memory, or CPU cycles.   Music theory uses basic arithmetic to define intervals between notes, that correspond to various tension levels you want to express.  Math in this case is used as a form of self expression.  Even if you are not aware of what a certain set of notes is expressed in mathematically, that math relationship is always there in anything that you play or listen to.  Same applies to software, which always winds up as ones and zeroes at the finest level.  

  2. Patterns and a Taxonomy to learn: Computer programming has logical patterns to organize and categorize the concepts you know:  classes, interfaces, design patterns, variables, enums, structs, methods, wrappers, adapters, pointers, variables, messages, delegates, weak references, data formats, algorithms.  Music theory uses chords, scales, triads, arpeggios, chord progressions / regressions, tonal centers, modal playing, shape thinking, contours, rhythmic variations, dynamics, phrase repetition, call and response, tension, release, mixture of voices, rhythmic displacement, harmonics, and feel to achieve the desired effect.  Both sides utilize these structural tools, each serving a distinct, specific purpose.  They are all, however, just a means to an end.  Being familiar with as many as possible of these is definitely beneficial for both trades.

  3. A Problem, and Solution: Computer programming has problems and unknowns. There are many ways to solve a problem, and an infinite combination of steps to get there.   Music has a chord progression that you may need to fill or arrange.  Or you could be trying to fulfill an idea which is just a melody in your head.  How you fulfill it, is completely up to you.  In both trades you often end up solving a problem that nobody cares about, but you have learned something in the process.

  4. A Scale of Clear Right/Wrong to completely Subjective.  Computer programming has common "right" and "wrong" ways of doing things.  Some choices are considered wrong, such as gluing SQL strings together, containing user input.  Music has some things that are very "wrong" too, such as playing a Flat 9 over a major chord repeatedly....  But Captain Beefheart would disagree.  Analysis is needed to  understand why a solution is considered "correct" and also that a musical passage is "tasteful" or of "high quality".  These conclusions are based on your personal line of reasoning, preconceptions, and requirements depending on your situation. Finally there is a Scale: A clear right and wrong on one end, and highly subjective decisions on the other.  We all decide differently where to put any given topic on that scale, although many common schools of though exist.

  5. Varying standards for Purity and Aesthetic. In Computer programming there is a certain aesthetic to your code. This includes: how clean and efficient it is, and how prone it is to breaking in the future. In music, you can also distill a melody or arrangement to its most essential parts, and subtract redundant pieces, until you're left with something that's "just right".  Some people are much more strict with this aesthetic than others.  How "cleanly" various roles are performed by different software elements can be correlated to how "cleanly" instrument tracks in a piece of music do their job.

  6. Knowing limits, breaking rules and common conventions. In computer programming, you may choose to break rules on purpose.  For example, you might DE-normalize a database table, building very specific indexes, so that very specific Select statements are quick to run, because you do not have to do any joins or contend with processes.  In music, especially jazz, you break rules all the time in order to create tension.  In more popular styles, you keep changing the well known rendition to keep things interesting for yourself - the musician, as well as the listener. This often involves infusing diverse influences into the rendition. 

  7. Exponential growth in variety. Computer programming has a proliferation of technologies which seem to be exponentially multiplying with the help of the internet.   The number of songs created, new music styles and cultural musical expressions is also exponentially growing.  The challenge for both is keeping up with the trends, and choosing what to even keep up with.

  8. Human Interaction is at the core. Computer programming has people you need to work with.  Some of them are very opinionated, overbearing or overly defensive.  The music industry has very similar types of people that you often have to work with.  Both trades, in my opinion, are as much about people skills as they are about the craft.  This human element applies at every stage:  From designers to customers.  From players to listeners. 
  9. Design determines what you can do.  How you design a piece of software often dictates what your limitations, possibilities and outcomes are in the future.  This applies to music, when you have a rough idea of the style of song you want to compose, the chord progression and the rhythm you have chosen.  It is generally uncommon to have a bunch of completely different, disjointed music styles, rhythms and chord progressions follow one another in the same song.  The "design" of the song must follow some specific train of though, so it can be understood.   The same applies to Software.
     
  10. Conventions, Rebellions and Inspiration. Every time traditional thinking is successfully challenged, we all enjoy the breakthrough.  Whether it's a hugely successful commercial success or a very niche following, we all love it when things are done differently on purpose.  If I can wire up 20 raspberry pies to uniquely control my house, or learn about Pat Martino's unique approach to using Minor Scales, I would be excited and inspired by the innovation factor, and the future possibilities.


Learn how to create your own Programming Language here!!

Beer in the Fridge at work

It makes me really happy to join a technology company and find beer in the fridge, people playing ping pong, sleep in sleeping pods, frying up BBQ at lunch, and playing basketball.  Not because these things are inherently fun.  But because, it's a message from management that says the following:

1. We hire such a high caliber of employee, that they would never consider abusing the perks we've given them.

2. Congratulations on finally getting to the top 10% of the best places to work.

3. People here are smart on many levels, not just book smart. They realize the value of maintaining a flexible mind and body.

4. We are all like minded in our pursuit of excellence.  We are so productive that we have plenty of time left over to enjoy the perks, after succeeding at our jobs. 

5. The company is successful financially, and would stop at nothing to satisfy and retain its employees.

This of course results in people giving back more, and feeding this cycle.

The Mobile Startup: Episode 5: Some thoughts about tech, and work.

Knowing that You're Bad! I think that if you have never thought of yourself as a bad engineer before, then you are probably a Bad e...