Thursday, July 27, 2023

13 years old girl

Ella turned 13 today. It's a bit weird to celebrate on the "Tisha Be'av" fast, but it happens.
Now officially we have a teenager in house. Actually the feeling is we're in a rollercoaster with debris flying around. Everyday there are shoutings, communication is in vowels, in some cases it turns to mono syllable like Grr or mmm. The only place where we have some sense of quietness is on the sea - sailing.
While Ella is running headstrong into the maturing problems, our homeland is running headstrong into oblivion. A teenager needs guidance, we're trying to help her with her struggles, Shirley by trying to over shout, but Ella knows it's for her.
Israel on the other hand doesn't listen, it feels like the cow who kicks the bucket before milking. The entire world is signaling "you're doing it wrong", Uncle Sam doesn't use the politically correct terms anymore, every expert has already said it's a disaster, but we're still running forward.
To tell the truth, I'm not sure Ella's 14th birthday will be in this country. We might end up as refugees in another country. Refugees with full citizenship and rights, but still refugees because our first home will be gone. 
I hate to say it, unlike Poland and Hungary which surrendered to the tyranny Israel doesn't have the option. Tyranny means the end for this country. The inventions done here are due to the a combination of free thought, lack of resources and the backing of courts which judge based on intentions. If it's not a colossal failure it can be written down as another bad experiment.
The system created in Israel has many drawbacks, but one major key factor - it works. Anyone who tried to compete with an Israeli team knows the amounts of money you have to invest in order to beat it, if it's compared to the amount of money the Israeli team invested it's exponential. It might turn to be the past. Nobody knows yet, same as nobody knew that bombing fort Sumter would cause a large scale civil war.
Unlike normal years, in this year I don't state Ella's achievements, in this year I state our fears and hope for a better future.
I know when the time for Shavit's birthday blog comes the future will be clearer, for better or worse.

Monday, November 21, 2022

Magic word for Software Architect (and others too)

Moving to the architecture side of the programs made me ask a simple question all-day long: "Why?"

Most of the time I get reasonable answers, some developers actually know better than I do what is the problem they solve. From time to time there are good discussions which teach me. When a discussion which teaches me happens it means the day was extremely profitable! The problems arise when the answer is awkward.

In some cases, rare ones, I received an answer beginning with "it's for..." followed by some unrecognizable sounds and a quick "I'll call you later" hang-up. The code on the 2nd call somehow was lighter, more efficient and readable.

In most of the cases I get an answer like "the book says it", or "I'm used to" or "why shouldn't I use a time-wasting algorithm on a fast computer". Usually it happens when the developer is a fresh developer out of the academy or whatever they call it. Those are the most hard to handle people, too much theory not enough field practice. The fact 90% of the people wear watches on their left hand doesn't mean the other 10% are wrong. Same goes for using some design patterns. Separating the company to 3 different environments (DEV, QA, PROD) is usually a good practice, but creates extra efforts if there are separated programs in each section. The effort multiplies if each product has its own set of testing environments. The end result of not separating it correctly is "job security" for the poor DevOps.

All those problems could have been solved, or at least handled a priory by asking the simple question "why".

"Why do you separate the environments by product instead of work mode?" Is it because the company works this way or because it's coming from a book? Does the permissions model come from a business requirement or is it a "nice to have" feature equivalent to digging random potholes in the floor? Same goes to the communication protocol used, did you choose something according to requirements or according to tech-department's amusement? Left on their own techies use the latest technology possible, but it might mean the older technology pieces won't work. My new DELL computer doesn't have any legacy USB ports, you can guess the annoyance it causes when the company supplies only USB headphones.

When it comes to development the first "why" is regarding the framework - programming language, source repository and build machines. Companies which have some infrastructure already built are exempted from this, the cost of moving from TFS to Github is huge for a mid-large company. When you have the infra in place it's usually better to continue with it unless other issues intervene. For a new company or a small one the question is different. Switching a small project from one infra to another, regardless of it being the programming language or build machine, "cleans" it from the extras accumulated over time. That code which was added at 2AM during "the caveman hunting feast" crisis, and suddenly fails due to an invalid reference, in this case the "why was it added" is clear, but "why wasn't it removed yet???".

So next time you open your IDE, before doing any other action, ask yourself "why". The fact everyone is saving their work in "c;\work" doesn't mean I should do it too when "D:" is free while "C:" has no space left.

Sunday, February 14, 2021

The difference between a developer and an architect

I encountered the term software architect about 15 years ago while I was a developer in small company. At that time I found it very weird to actually have this type of co-worker. It wasn't long before the architect himself felt the same way. Later on when I met him again he explained that a small company doesn't need an architect.
Nowadays I'm doing more architecture work that actual developer's work and finally decided to try and explain the differences. I must first give a warning about generalization, I've encountered many developers who do better architecture than the architects in their team, but the majority needs the architects' guidance.
I'll begin with a code sample I got from a developer not so long ago:

interface IExporter {
void Export();
OperationMode GetOperationMode();
}
interface IImporter {
void Import();
OperationMode GetOperationMode();
}

The code was working perfectly. From the developer's point of view it was "mission completed" - everything passes. Luckily it had to pass by me too. After trying to understand why both the import and export contain an implementation of the same function I found out the following:

abstract class ImportExportBase {
serialize / deseialize functions
public OperationMode GetOpertaionMode();
}

The developer saw an existing base class, and without fully understanding the meaning of the base class add a new 5th leg to the frog. At this point I stepped in defining the architecture as follows:

interface IExporter {
void Export();
}
interface IImporter {
void Import();
}
interface IOperationModes {
OperationMode GetOperationMode();
}

Explaining to the developer he has to align the code to the defined interfaces, and use the interface in the base class if needed without making the function public. I have to admit that it was a result of my misbehavior - letting the developers write code before the architects' define the API is not fair to say the least.
Unfortunately, as I experienced 15 years ago too, in most cases architects are not involved correctly. Instead of making sure the program will be easier to maintain / debug they find themselves trying to decouple the hog's nose from the giraffe's hind leg because no architect was available when it was developed. To add insult to injury, the customer doesn't understand why should the leg sniff the air, even if there's no way it will sniff the fresh air. It took me half a day to explain to a customer that it's easier to read the data from the device itself than "reading the data from the device and manually typing the same data from the device by someone who reads it" - luckily for me, in that case I had architect's help.

To summarize it to a one liner:
The difference between a developer and an architect is in the scope of the system, an architect has to look at the macro-level - interfaces and public functions, while a developer has to look at the micro-level - make the implementations as efficient as possible and find ways to re-use the code without exposing it.

Friday, May 29, 2015

Debugging 101

Often times I heard from developers (not all of them juniors) the question "how do I debug this?"
Let me begin at the conclusion - use your experience. Most of the times when you have enough experience you can go directly to the source of the misbehavior and fix it.

This post is about the how to get the experience.

First thing to do is to understand the bug. Easy? Not at all. Just the other day we got an error stating "the dates are incorrect." after trying to explain to the user that created date, end date, and effective date might defer we've found out that the user had a totally different error. The original error was missing data, the description for the bug included so many misleading directions that we got lost on the way. Luckily, experience taught us to ask first.

Once you fully understand the bug, it's time for the second step - reproduction. Now this thing might be hard (or nearly impossible when it's a stress related bug), but it's by far easier to debug on your machine then on the lab 5 floors below ground, next to the "devil" called lab-manager, and his "minions" co-workers.
Note that in some cases the only way to reproduce is by using a non-development machine. While not being as easy to debug, it's still a good reproduction.

Now that you managed to figure what you want, and where to test it, we can advance to the third step - checking the code.
It's important to understand, before trying to debug and fix the code, check it. If there's a candidate for the bug's location, mark it (or add a log line to verify your assumption). Note there might be more than one location, mark them all, it saves time.

Step four. Now it's time for the real debugging. After we finished the setting up we run the scenario and verify the preliminary assumption. Hopefully we've caught the culprit, in case we haven't, return to step 3, there are more locations which are hidden.

Step five - the fix. This is the most dangerous step! Fixing a bug is prone to opening a new one in an unrelated location. Assess carefully the impact of the change, consult with others, and try to explain to someone (even your dog) what you are going to do. Usually we do shortcuts on this step, especially when the clock says 2:00AM, but it backfires at us always.

If all passed successfully, we're good to go. Call the QA, say we fixed it, explain the impact, and let them do their magic. Hopefully no new issues arise and we can ship it out.

A quick example. I'm using this code as the "buggy" program.
1 class Program
2    {
3        private class HelperClass
4        {
5            public List StringsList { get; set; }
6
7            public void PrintStrings()
8            {
9                foreach (var str in StringsList)
10                {
11                   Console.WriteLine(str);
12                }
13            }
14        }
15
16        static void Main(string[] args)
17        {
18            var helper = new HelperClass();
19            helper.PrintStrings();
20        }
21    }

The user would come to us stating "IT DOESN'T WORK!!!"
This code can't work, it's lousy and if someone would give it to me, he'll find the way out within the next minute. But "doesn't work" is not the error it gives. "Null reference" or "object reference" is the error message we're expecting to be given by the user. After we'll see the demo of what he did, we'll have it.
Step 2 - reproduction. In this case it's easy, run it on the developer's machine, it will fail.
Step 3 - find the candidates, in this case it would be lines 19,9 and 11. Either print a log or put a breakpoint on those lines.
Step 4 - debug. The debugger would stop on line 19, afterwards on line 9, but line 11 will never be reached. Further investment shows line 9 fails, StringsList is null.
Step 5 - fix. In this simple case the fix might be adding
helper.StringsList=...
or checking for null before the printing
if (StringsList==null) return;
or surrounding with try catch (bad idea, but fixes the bug).
Once we fixed the code, it's time to deliver it. Now the user can check it on its own.

Tuesday, December 10, 2013

Inheriting Someone else's Code

One of the major issues in development is what to do with the previous programmer's code. Usually it begins with the naming convention, this is easily solved - get used to it.
The following issue is the separation, or lacking of it, to different files and projects. While being a little nuisance, it's a "don't touch unless you have to".
The major issues arise when coming to fix a bug. What calls what? Which event comes first? What function threw the exception? All of those questions can be answered easily when you wrote the code, though it might take time to refresh your memory when it's an old piece. When it's not your code - spell trouble.
The easiest solution is using the debugger. There are 2 issues with the debugger:
1. Race conditions hardly ever happen when the debugger is attached.
2. Most of the clients I had didn't want the debugger, didn't allow it, and in some cases looked at it as trying to steal their data.

That's where logs come in handily. All you have to do is select the logging method (personally I prefer NLog, but there are many more libraries out there), and add the log lines.
After practicing logging for a long time I reached the conclusion that a some guidelines are needed. Mainly because no one really needs all the logs all of the time, normally you'll need only the errors, sometimes the warnings too. The lower levels are only used when trying to figure out what causes a certain behaviour.
So here are the guidelines (based on NLog):
1. Fatal - errors that forces the application to shutdown. I'm using it in the global trap, the global threaded trap, and when the application's initialization phase didn't complete successfully.
2. Error - anything that failed to execute correctly without an expected explanation. By expected explanation I mean invalid input data, known erroneous response from service and etc.
3. Warn - anything that failed to execute correctly with an expected explanation.
4. Info - any call to a public method, with the relevant parameters (i.e. username, but not the user's password).
5. Debug - Before entering any "interesting" method, and at the end of each method. By interesting I mean anything that might look like a potential problem to the programmer. For the debug pass EVERYTHING, in some cases even the passwords. When you're forced to use the debug, you have a real bug lurking out there and you must catch it ASAP.

Thursday, August 15, 2013

Interfaces - when to use, and what's an abuse



Recently I found I have way too many interfaces inside my code. Don’t get me wrong, interfaces are good, extremely good, and in some cases a must. It was just that some of the interfaces were “mines in the code”. An interface is a certain boundary which you must cross in order to debug. Placing this boundary incorrectly is like building a window inside the house. It might even look good, but it would be a nightmare to walk in this house, and living there is unimaginable.

Let’s begin with what an interface is:

  • Interface is a contract.
  • Interface is shared between more than one object.
  • Interface promises that a certain method / property will be there.
  • Interface does not prevent another interface.

Reading those 4 terms means that an interface is useful ONLY if you don’t have prior knowledge of the object. In the programmers’ term - late binding, this is a great blessing when working on a multi- whatever project that takes a long time to compile.
But with the blessing comes the price: It’s a contract. You can’t break it without the approval of the other side, or in some cases “sides”. The end result is that once an interface is out of your machine, it mustn’t be changed.
Let’s take a real life scenario, one my team had to deal with. We’re running a local win-service, the service acts as a channel to the outside world. It retrieves messages and launches the correct responder. But who is “the correct responder”? I chose to use a simple interface:
interface IWorker {

bool IsMessageForMe(object message);

string ProcessMessage(object message);

}

When a message comes in, each class that implements IWorker is checked, and ProcessMessage is called if the IsMessageForMe passes. The reason for returning string is logging, a very important thing when you can’t attach a debugger.
Another common scenario, one which doesn’t involve dynamic loading, is usage of more than one type of object on the same mission. For example – ordering a list of objects by their names:
Interface IHaveName {

String Name {get;}

}
By the simple implementation of this interface to 2 types of objects (i.e. boys and cows of the farm) I can sort them out. I don’t care that a cow needs milking and the boy needs Facebook, I just want them in a single line marching to the county fair.

So far I dealt with the when to use interfaces, how good they are and etc… But the reason I’m writing this post is the abusage of interfaces. So from now on I’ll stick to the don’ts. Actually the don’ts are simple:
If you can write it without interfaces – DO SO! Interfaces are for the times you can’t achieve the goal without the usage of this degree of abstraction.
If you can refer to a specific object type – do so! Abstract class is better than an interface in terms of referring to, it’s better to refer to the correct type directly, but I do live in the real world.

Thursday, May 10, 2012

Silverlight Client Logging

The major pin in the ass for client side applications is logging. Silverlight doubles it due to its "sandbox" which blocks from saving a local copy on the client for later sending. As usual, I needed a log to trap a bug. And as usual too, the bug didn't reproduce itself on the development machine. So I came up with idea of logging the actions.
Building a log class is a simple matter:
public static class Logger
    {
        private static List<LogEntry> Entries = new List
<LogEntry>();
        private static bool _isActive = false;

        public static bool IsActive
        {
            get
            {
                return _isActive;
            }
            set
            {
                if (_isActive != value)
                {
                    if (value)
                    {
                        _isActive = true;
                    }
                    else
                    {
                        _isActive = false;
                        lock (Entries)
                        {
                            Entries.Clear();
                        }
                    }
                }
            }
        }
        public static int MinLogLevel { get; set; }
       
        public static List
<LogEntry> GetLogEntries()
        {
            List
<LogEntry> tmp;
            lock (Entries)
            {
                tmp = Entries;
                Entries = new List();
            }
            return tmp;
        }
        public static void AddEntry(int level, string message)
        {
            if ((IsActive) && (level >= MinLogLevel))
            {
                LogEntry entry = new LogEntry(level, message);
                lock (Entries)
                {
                    Entries.Add(entry);
                }
            }
        }
    }


The first thing to note is "GetLogEntries" clears the list. I did it in order to send the entries to the server only once, even if the server did not receive them. You might need to implement it in a different way.
The second thing is I relay on a helper class LogEntry. I provide my implementation of it, feel free to change it, the logic wouldn't change. Maybe a minor change to the constructor is needed. Or using the Server's LogEntry class and setting the properties inside {}.
public class LogEntry
        {
            public DateTime Stamp { get; private set; }
            public int Level { get; private set; }
            public string Message { get; private set; }
            public Guid UserID { get; private set; }
            public Guid TenantID { get; private set; }
            public string Operation { get; private set; }


            public LogEntry(int p_Level, string p_Message)
            {
                Stamp = DateTime.Now;
                Level = p_Level;
                Message = p_Message;
                StringBuilder sb = new StringBuilder();
                StackTrace stackTrace = new StackTrace();
                StackFrame[] stackFrames = stackTrace.GetFrames();
                foreach (StackFrame stackFrame in stackFrames)
                {
                    sb.AppendLine(stackFrame.GetMethod().Name);
                }
                Operation = sb.ToString();
                if (WebContext.Current.WFUser == null)
                {
                    TenantID = Guid.Empty;
                    UserID = Guid.Empty;
                }
                else
                {
                    TenantID = WebContext.Current.WFUser.TenantID;
                    UserID = WebContext.Current.WFUser.UserID;
                }
            }


            public override string ToString()
            {
                return Stamp.ToString() + " " + Message + " - " + Level.ToString() + ": " + Message;
            }
        }

Now we'll have to add a background sending utility. This implementation is the most naive one, but it works great, so we didn't bother to change it.
private bool IsActive = true;
        private void SendLog()
        {
            while (IsActive)
            {
                int CountDown = 300;
                while (IsActive && CountDown>0)
                {
                    System.Threading.Thread.Sleep(1000);
                    CountDown--;
                }
                SendToServer(Logger.GetLogEntries());
            }
        }
        public App()
        {
            InitializeComponent();
            Application.Current.Exit += Application_Exit;
            System.Threading.Thread th = new System.Threading.Thread(SendLog);
            th.Start();
        }
        private void Application_Exit(object sender, EventArgs e)
        {
            IsActive = false;
            System.Threading.Thread.Sleep(5000);
        }

This code goes to the application class. SendToServer is supposed to be a server side function (using WCF or RIA or whatever is at hand).

 That's all, now add the debug lines as Logger.AddEntry(debugLevel, message) whenever you feel like it. Just remember to set the logging level and to activate/deactivate when you need it.