Showing posts with label Software Design. Show all posts
Showing posts with label Software Design. Show all posts

The perils of 'minimizing' language in software development

I believe that a large part of the reason that the vast majority of software projects end up over budget and finish well past schedule is that all too often, both developers and product/project managers use minimizing language for things that turn out to not be anywhere near as minimal or as straightforward and simple as minimizing language makes them sound. 


Focus on keeping the main thing the main thing


When discussing software development, especially when discussing the estimation of time required to complete work items, whenever you speak or hear a statement that contains the phrases, "it's just", "it's only", "it's simple", ''that's just boilerplate", "it's already baked in", "that's just [insert a design pattern while completely omitting the context, data structures and design logic the pattern will be applied to]", or in the Year of our Lord 2025: "ChatGPT will answer that"- run.

Run for the hills and do not return. I'm kidding. But do be very alert to phrases like these because they indicate a potential significant piece of your project that is being glossed over because someone has thought about it abstractly, but not in concrete (code implementation) terms.

This can be developers who are either over-confident and/or feel pressured to give low estimates so that the project schedule does not seem imperiled.



This can be managers who just haven't stepped into the code or discussed the logic enough with the developers to understand the complexity behind a series of words that describe a conceptual software design.

Under-promise and always account for unknowns which will lead to unforeseen roadblocks, detours and changes. If all goes according to plan (and it never does), you over-deliver on your over-estimates. If not, you have may have given yourself enough buffer to still meet the planned schedule and will have successfully accounted for the inevitable unknown.

If you are already on a schedule that is unrealistic and bound to not be met by the deadline, then all you can do is change scope (cut or delay features). If you insist on keeping all the planned features, and have the luxury of time, then you can only increase the time (lengthen the delivery schedule to a future date).

You can certainty try to keep the same calendar date for a release deadline and "just" throw more developers and managers at the project, hoping they can all work round the clock and in parallel to increase productivity, but this never works. Domain knowledge and a cadence of solid productivity and cooperation across teams takes a significant period of time for new hires to learn.

As a quote attributed to Warren Buffet says, "You can't produce a baby in one month by getting nine women pregnant."


And I repeat: Focus on keeping the main thing the main thing


When designing and project planning any significantly complex piece of software, all parties involved (the "stakeholders") must understand that a software project is not fixed- project schedules, planned features, and the human resources to implement the features are going to change.

Many thought that the move from top-heavy waterfall/SDLC-based approaches to Agile would solve this problem. But unfortunately, when Agile refuses to actually be "agile", the waterfall becomes an unnavigable white water rapid stream that is only slightly more conducive to building great things within a certain scheduled space of business time.

And in general, God bless a true Agile craftsmanship approach and all the time-tested statistical process control concepts it is based upon, but our software industry's hyper-reliance on "estimating" and "measuring" things that can unexpectedly and rapidly evolve (and oftentimes measuring the wrong things) does not jive with realistic long-term software planning objectives and almost to a "hyper-time-boxed project"- leads to the worst of all outcomes in the software business: mismanaged (or specifically "missed") expectations. Managment of expectations is everything.

Deliver the most critical parts of a customer's needs first and deliver them as a flawless piece of beautiful software. Working software- especially the end-to-end functioning of your application's most critical workflow- is paramount; everything else should follow from that and never get in its way. 

You can iterate, make changes and add features later on.

Focus on outcomes over processes; lest you sink into the bog of minimizing language metastasized into maximally time-consuming (sometimes completely unnecessary) work items. And a project that seems to never get delivered or is (worse, because first impressions are everything...) delivered rife with show-stopping bugs.


Dichotomies

Apropos of nothing I thought about some interesting dichotomies and wanted to share my perspective. It is interesting how often there are effectively 2 sides to a coin.


Religious Faith/Religious Dogma - Some folks live the "spirit" of the Word and resist structure vs. others, who follow strict adherence to "the letter" of the Word.

Subjective/Objective - You have here opinion and feeling (the supernatural) vs. facts and laws of nature.

Romantic/Classical - similar to the Subjective/Objective dichotomy (see also, "Zen and the Art of Motorcycle Maintenance").

Liberal/Conservative - The ideology of inclusion and change vs. the ideology of exclusion and stasis.

Conglomerate/Individual Co. - Whereas many corporations sought to obtain economies of scale through M&A in 80s, 90s and 00s, General Electric proved- (sold GE Capital, spun off GE Healthcare, GE Aviation and GE Power into 3 individual new companies)- that the conglomerate model doesn't always stand the test of time.

Thin client/Fat client - It makes no sense to be all one or all the other (an overburdened SPA app or an inflexible server-side only app). But we keep moving between one (thin client terminals in the 70s and 80s) and the other (fat client Home PCs in the 90s and 00s). And we've moved back to thin client again with Azure, AWS and GPC and the omnipresence of SaaS. But at the same time, fat-client SPA apps are as popular as ever... I guess we have fat client UIs and thin client APIs.

Imperative/Declarative code - Instructions that read like a book vs. instructions that read like a mathematical proof.

Monolithic app/Microservices - a very heavy Swiss-Army knife vs. a bunch of lightweight kitchen knives.

Software/Hardware - Recipes vs. the raw food itself.

Socialism/Capitalism - The idea that everyone is the same and should be reduced to (or propped up by) exactly such vs. the idea that everyone is incompatibly unique and should be uniquely catered to and provided maximum personal freedoms that can- like assault weapons and ammunition- come at the expense of the greater community.

Urban/Rural - Those from the densely populated cities and suburbs vs. those from the sparsely populated country towns.

Introvert/Extrovert - He or she who expends a great deal of energy socializing and finds solace in silence vs. he or she who is energized by interpersonal social connection and is not comfortable alone for extended periods of time.

Centralization/Decentralization- Putting the heart of a system at the center with dependent, often necessarily-generic/homogenized nodes vs. putting the heart on the nodes themselves, at the expense of (losing) ease of simultaneous node (state) synchronization and a "single source of truth/golden records".



DevOps as Culture

DevOps is an emerging IT role but also a culture; and changing culture does not happen overnight

  • Elevate empowerment and give courage to people to "raise hand" and volunteer to fix things. Even if they are wrong- interest in areas outside one's primary role is good for the entire DevOps culture.
  • Shared accountability - no blame game between developers, PMs, testers, QA, etc.
  • Do not want to have to be dependent on "lone genius" or "firefighter"- need to share and transfer knowledge.
  • Offer time to learn. Encourage hacking for new features and for hardening security and find bugs.
  • Embrace failures in retrospectives to prevent repeated mistakes on future work.
  • Provide the right incentives to motivatve the values you want to reward: reward delivery of quality vs. fire fighting.
  • Understand "value streams" (esp. value stream bottleneck and how can we optimize all constraints) to know where to spend time accordingly.
  • Focus on CONSTRAINTS.
  • Avoid Configuration Drift- Config changes should cascade to all environments (QA, DEV, TEST, STAGE, PROD).
  • Automate the Path to Production.
  • Use pull-based systems so that people integrate each others changes and learn how everything works in unison/concert.
  • People should not fear for their jobs- Systems Admin becomes more important not less so, in DevOps
  • DevOps is how you work not just what you buy or what tech you are using.
  • Total adoption happens in stages/iterations.
  • Traditional Project and Documentation mindset is outmoded, outdated, and disconnected from a living IT mission.
  • Lack of DevOps leads to waste and waiting (waiting for ppl with the right skills to work on things vs. having team that can easily shift contexts or frameworks/languages).
  • SHARE KNOWLEDGE AND EMPOWER COLLEAGUES TO DO MULTIPLE TASKS AND UNDERSTAND SOME OR ALL ASPECTS OF MULTIPLE RESPONSIBILITIES OF THE SOFTWARE PROCESS CHAIN.


Newtonsoft JSON .NET Nuget Nugget

Most API payloads are in XML or JSON; it is best to know both of these data structures, and how to serialize/deserialize them

The JSON parsing utilities found in Newtonsoft.Json are very. very useful and should be common knowledge for any .NET developer who works with API data or anything producing or derived from JSON (JavaScript Object Notation).

In general, to use Newtonsoft.Json you simply need to create a .NET class hierarchy that mimics the structure and hierarchy of the target JSON. Once that is setup, serializing in-memory objects to JSON and deserializing the JSON back to in-memory objects is a breeze.

You achieve this by normal class hierarchy and making List<> of child objects, array properties, etc. Newtonsoft's 'JsonProperty' class property decorator maps JSON properties and the builtin serialization and deserialization methods facilitate working between JSON strings and the in-memory objects they represent.

The C# source code below demonstrates serialization from a SQL Server 2017 SSRS API v2 JSON response and then serializing that object back into JSON.

Source Code:

 using System;  
 using Microsoft.VisualStudio.TestTools.UnitTesting;  
 using Newtonsoft.Json;  
 using System.Collections.Generic;  
 using System.Net.Http;  
 using System.Threading.Tasks;  
 namespace DemoTests  
 {  
   [TestClass]  
   public class DemoTestJSON  
   {  
     [TestMethod]  
     public async Task TestDeserializeJSON()  
     {  
       HttpClient client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true });  
       client.BaseAddress = new Uri("http://localhost/reports/api/v2.0/reports");  
       var response = await client.GetAsync(client.BaseAddress);  
       var deserial = JsonConvert.DeserializeObject<APIGenericItemsResponse>(await response.Content.ReadAsStringAsync());       
       TestSerializeJSON(deserial);  
       Assert.IsNotNull(deserial);  
     }  
     [TestMethod]  
     public void TestSerializeJSON(APIGenericItemsResponse genericObject)  
     {      
       string serial = JsonConvert.SerializeObject(genericObject);  
       Assert.IsNotNull(null);  
     }  
   }  
   public class APIGenericItemsResponse  
   {  
     [JsonProperty("@odata.context")]  
     public string Context { get; set; }  
     [JsonProperty("value")]  
     public List<GenericItem> GenericItem { get; set; }  
   }  
   public class GenericItem  
   {  
     [JsonProperty("Id")]  
     public string Id { get; set; }  
     [JsonProperty("Name")]  
     public string Name { get; set; }  
     [JsonProperty("Path")]  
     public string Path { get; set; }  
   }  
 }  


SSRS API v2 /Reports JSON Response:




JSON Deserialization with Newtonsoft.Json:
The deserial variable holds an in-memory .NET object of type APIGenericResponse, derived (deserialized) from the SSRS API JSON response




JSON Serialization with Newtonsoft.Json:

The serial variable is simply the serialization APIGenericItemsResponse object serialized into a JSON string


Reference: https://www.newtonsoft.com/json/help/html/Introduction.htm

Visualize Hashing and Salt as Part of Password Encryption Process

The image below is a simplified and easy-to-understand illustration of how hashing and salting work. The main takeaway from this post- multiple users can have the same password, but will all have different salt values, thus making their hash result value different, and when you authenticate, you authenticate by the hash result value of your passwords, which is virtually always going to be unique for each user record:

Simple, no?

Even in the case of 2 users having the same hash result, the usernames will/should not be the same, so you still have distinct accounts, because UserID is also checked in the authentication process.

Companies increasingly (and for good data privacy reasons) do not even store the clear text textbox value you enter when you sign up for and then log into Fb, Google, Amazon, etc- they check your entered password's hash result against the hash result they have for your user/account record either from when you registered or last changed your password.

Good answer to the question you may come across, "what is the difference between salt and an IV (initialization vector)?" (TL;DR: not all IV's are salt, but salt is a kind of IV): https://security.stackexchange.com/questions/6058/is-real-salt-the-same-as-initialization-vectors


SOLID

"These principles, when combined together, make it easy for a programmer to develop software that are easy to maintain and extend." -Robert 'Uncle Bob' Martin

S Single-Responsibility - objects should only serve one purpose

O Open-Closed - types should be open to extending capabilities, closed to base changes

L Liskov Substitution - subtypes of base types should produce objects compatible with base

I Interface Segregation - client types do not have to depend on unused interface methods

DDependency Inversion - rely on abstract templates, not prescriptive/restrictive concretes



Reference: https://scotch.io/bar-talk/s-o-l-i-d-the-first-five-principles-of-object-oriented-design

Patterns Simpl: Iterator

Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.

The essence of this pattern is that when implemented correctly, you can easily iterate through a collection of complex objects in a uniform manner (ie. IEnumerator, IEnumerable in .NET) without having to know the details of the type of object in the collection.





Reference: https://www.google.com/searchq=iterator+pattern+defined&oq=iterator+pattern+defined