Pezely’s Posits

Observations from decades in the software industry
via Main Street, Wall Street, Silicon Valley and beyond
blending computer science, psychology and philosophy

Originally released: September 2006

Updated: 2007, 2009, 2013, 2014, 2016, 2017 and 2018

  1. When pitching or presenting a new idea, keep it brief: under a minute or two. Tell them enough so that they ask for more. If they don’t, go elsewhere. Maybe revise your message as well.
  2. When delivering your message, make it all about them. Begin with why. Explain how this satisfies a need they have, perhaps one they might not yet understand. Describe in terms already familiar to them.
  3. As soon as you’re about to say “I can’t,” stop and restate your position in terms of cost. That is, consider “I could, however, these are the costs...” or trade-offs. Some are opportunity costs. Maybe it requires more people, more time, more budget, more research than currently available. Such constraints can be overcome when the goal is important enough.
  4. Corollary to inverting “I can’t” is saying no without saying “No,” such as in delicate social or political situations. By presenting sufficient facts in context and allowing the other party to consider this solution space, allow them the choice and grace of withdrawing their request. However, always account for improbable but still possible outcome that, yes, they wish to proceed.
  5. Conceptually, add or change only one thing at a time in a release, else confuse your customers or collaborators.
  6. Make rapid, iterative releases— a.k.a., “release early, release often”— even if only for internal purposes such as a candidate for official deployment.
  7. Many good writers advise show, don’t tell, and so with software: construct enough to illustrate the most unique elements first as proof-of-concept.
  8. With a proof-of-concept, emphasize proof with sufficient test coverage for the tricky bits. Using functional programming (or at least being free from side-effects) can help get you there faster, more efficiently and with precision of correctness on par with a mathematical proof.
  9. Write the hardest parts first. Some explain this as, “if you’re going to fail, do it quickly,” so you may then more intelligently begin again with wisdom gained from that experience or move on to what’s next.
  10. The best program is one you don’t have to write: put a shell script around an existing app, fork an existing library, delegate, etc.
  11. Writing software is creating a universe with its own intrinsic nature, so respect that, explore it, and maybe you’ll discover something new.
  12. There are people appropriate to start something new, to bring it to maturity, to be caregiver for its continued existence, but rarely is it the same group of people fulfilling each of those roles over time. Experience all of them to understand where your talents lend themselves best.
  13. Being entrepreneurial doesn’t require you to be CEO. Instead, everyone in an early stage upstart organization must equally understand efficiencies and trade-offs required to attain the next level, and that is the true wisdom of being entrepreneurial.
  14. You are continually, simultaneously both student and teacher— at the same moment.
  15. Anger or any other strong emotion is a signal that there’s something in that situation you’d do well to stop and objectively learn.
  16. Openly share knowledge and ways of understanding, and discover that when you’re the one in need, the right answer is easily available.
  17. If you weren’t there, refrain from criticizing decisions or outcome, but do suggests paths for improvement in a nonjudgmental way.
  18. The difference between criticism versus critique is that the latter is actionable. Always offer the constructive version.
  19. Be skeptical, not cynical. But when you play the role of skeptic, this doesn’t mean reject anything outside of consensus. Genuine skeptics weigh all available information objectively, consider it thoroughly, and offer qualified opinions on the matter at hand. See also: critique.
  20. Nothing exists in isolation: technology, skills, business plans, people, etc., are so interconnected that you’d do well to consider this a law of nature, and enjoy discovering those connections!
  21. On ideas: Give it all you’ve got and more. Hold nothing back, then more will flow.
  22. Of body: be good to your body (the meat), and it’ll be good to you. Take eye breaks. Remember to breathe. Minimize stimulants. Go for short walks periodically in addition to after lunch and in mid-afternoon.
  23. Just because it’s new, doesn’t mean it’s better— just less accumulated entropy.
  24. As with natural languages, studying programming languages that are new to you improves versatility because each potentially offers something unique, a different way of expressing and emphasizing an area for which you would do well to focus.
  25. True genius is being humble enough to admit not knowing and the clarity of asking meaningful questions.
  26. Reinventing the wheel isn’t necessarily bad, just usually excessive.
  27. But when reinventing that wheel, start with a fresh look at the physics too.
  28. A software system that is complicated isn’t the same as having complexity. A trivial program could be written as unreadable spaghetti code, yet massive systems have maintained elegance of design while addressing challenges previously believed impossible.
  29. Criteria are distinctly different than requirements, and both are necessary. Well-defined criteria offer high-level, abstract concepts for understanding the actual problems and recognizing the correct solution. Well-written requirements are concrete terms that are unambiguous and clearly articulate when a particular feature may be declared as done.
  30. State-machines nearly always exist within software systems, so take time to design these carefully (else be implicit, poorly documented and leading to much confusion when using or maintaining the system).
  31. Fundamentally, there is no such thing as schemaless databases or data storage. Schema always exists yet can be implicit, poorly conceived and undocumented. If tempted to omit the formalism— such as for accommodating dirty data— instead consider late-binding of data types at run-time.
  32. Complexity may be shifted from one layer or component to another but never really goes away.
  33. However, complexity may be consolidated (rather than duplicating the same bit of functionality throughout the system).
  34. Also consider complexity of new staff having to learn your system, and factor this into your design criteria.
  35. Let computers do the multi-tasking, but if you must: one may perhaps wear three “hats” yet only if all tasks are inter-related such as dev, ops and tech writing; or leadership, strategy and management; but not management, dev and support.
  36. For agility in software systems, favour dataflow over workflow within the system itself: advancing through the pipeline with small incremental transformations that minimize or eliminate side-effects.
  37. Understand dataflow to be like a river following its natural course or like the architect/builder who paved paths between structures on a new college campus only after observing direction and width of wear patterns in the grass.
  38. Accommodating dataflow is like a waterwheel driving a mill on the riverbank and otherwise leaves majority of the environment undisturbed; whereas, enforcing workflow is like a dam which either requires significantly more effort to facilitate salmon returning to spawn or shortsightedly ignores its impact on anything else.
  39. Frameworks strictly enforce workflow and should be avoided unless your scenario exactly matches those predetermined patterns.
  40. On the other hand— like books at a lending library— software libraries may be used how you see fit: read the book backwards or read only one page. Invoke functions in whatever sequence applies to your unique conditions.
  41. Frameworks may facilitate reaching 50% or even 70% completion very quickly but rarely attaining 90%. However, functional libraries tend to accommodate recombining, such that a little more investment during early stages greatly increases chances of reaching 100% and generally enables going far beyond initial criteria.
  42. Avoid using the database as your point of integration (or primary API), because this will constrain the entire system to semantics of that database engine; instead, put the database behind an event system, cache or queue which in turn dispatches the database as an abstraction layer.
  43. When considering a rewrite or performance enhancement that might bring merely 2x or 5x improvement, make this the lowest priority because it might be a waste of time compared to waiting for next generation of equivalent hardware or upgrading to another architecture that offers wider concurrency, better parallelism, or less contention.
  44. For performance improvements, focus only on those that would yield 10x, 100x, or 1000x returns.
  45. Designing a custom system isn’t the same as inventing, so arguments citing “not invented here” syndrome would be invalid in this case.
  46. Learn about arguments from fallacy so as to liberate yourself beyond manipulation, allowing healthy conversation and honest debate.
  47. Study the trivium, so then society may catch-up to recent ancestors with “only a fourth grade education.”
  48. Design for people, not some abstraction of “user.”
  49. “Bend the tool, not the human” is a fundamental principle of usability design. (For contrast, some video games are more about mastery of controls than navigating scene, setting, story or sequence/plot.)
  50. With “user experience” (UX) design, be principled about separating each of a product’s function, feature and format. The function of a product represents the broader utility to a person such as “searching the internet,” yet this uses a different sense than a software developer commonly references. Each feature addresses an abstraction as a unit: for instance, how a query is triggered such as voice rather than typing keywords. Another feature covers the way a person transitions from set of results to an individual item by tap/click versus swipe gesture. Then format deals with presentation; for example, results get displayed using lists, charts and cluster graphs.
  51. For systems internals, conceptually isolate memory, function and communication. This helps eliminate common mistakes (such as using a database as central point of integration, which will hinder expansion and scaling).
  52. Going all the way to first principles, it’s important to recognize a program in terms of its most fundamental components: input, output and work— or something goes in, something comes out, and do something in the middle. Articulating a system in these simple terms can appear as sage guidance in the midst of confusion.
  53. Account for future iterations by always including name and version number in shared data structures, communications protocols, file headers and API calls for at least identifying what this blob of bits represents. As a bonus for anything passing over a network, include a value for sanity-checking network byte order such that this value is a minimum of 32 bits for TCP/IP or UDP yet at least as long as the longest data type used: probably 64 bits in early Twenty-First Century.
  54. When functioning as a change agent, respect that not everyone may want the change that you bring or want to change from the status quo. As preemptive measure, it’s beneficial for yourself and those directly impacted if you first have buy-in from the highest levels of the respective organization. Get it in writing, if possible.
  55. Sometimes you might find “It’s easier to beg forgiveness than to ask permission,” but do so only as a last resort.
  56. Instead, find ways to build bridges to people: learn their language, discover their symbols, master their concepts, go deep into their world, and then discover for yourself that change begins from within.
  57. Like a good teacher, an effective manager is one who helps the individual and entire staff ask the right questions as well as find individual answers to those questions that would be appropriate for each.
  58. Effective management removes obstacles, carefully articulates criteria at a business level versus technical, facilitates healthy discussion within and across groups, and it enforces boundaries such as transforming things like “feature creep” into new or changed requirements.
  59. Every organization should have its thought leader as one who places the proverbial stake in the sand and points in a singular direction by which everyone else can be unified as their common goal.
  60. Leadership principles should be either actionable or provide clarity of thought, and these are best worded in the imperative as affirming statements. (Where possible, refrain from expressing what not to do.)
  61. A healthy organization is one built upon mutual respect and consideration.
  62. Respect each individual’s contribution by giving them sufficient autonomy based upon relevant skills and experience.
  63. Finding a healthy balance between tenured staff and new blood may be indicated by degree to which a long time employee leaving creates disruption versus the degree to which on-boarding someone new requires indoctrination and “paying your dues.” These may be measured by duration, effort required by additional staff and levels of autonomy during the transition.
  64. Sure, you don’t need to use Lisp or Rust (especially if you’re the competition).
  65. Stick around long enough, and history becomes part of your past.
  66. Give yourself time to unplug: just be and allow your higher self to come through.
  67. “... Know when to leave.”

By following your own intuition, everything flows from there.

The items above when applied within the context of designing software systems, build upon Dave Mills’ network engineering principles.

Copyright © 2006, 2007, 2009, 2014, 2016, 2017, 2018 Daniel Joseph Pezely.
May be licensed via Creative Commons Attribution.