We never perform optimally when using drugs–another example of source code I wrote while high on meth

One of the sites I visit daily is The Daily WTF. It’s a place where programmers go to laugh at badly written source code (and sometimes badly written embellished articles but that’s another story). You go there for examples of the kind of source code that, when you see it in real life, you react with a loud exclamation of “What the fuck?!”

A couple of weeks ago, someone posted an example of his own code in their “Sidebar WTF” section, and commented something like “What kind of crack was I smoking when I wrote this?” Of course he meant it as a figure of speech, but I couldn’t help but reply with some code that was really written while I was tweaking on meth. Today, I’ll share that same code here.

The message in this post is not really about the code, so I’ll paste it at the end. The message is about how drugs affect our performance, even when we may think it does not.

The code in question is part of my “for fun” little GUI that allows editing of zip files. It’s the method that populates my GUI, which results in something like the screenshot below, which I just made while browsing a random zip file with it:

image

Actually the code works, and it works very well. I could almost be proud of it. Almost, but not quite.

It works by enumerating all of the contents of a zip file. It allows recursing into the directories inside the file as well, depending on what parameter it’s passed. When passed a null parameter, it displays the root entries; otherwise it enumerates the entries of a sub-directory of the zip file. It has to be a little intelligent about how it identifies the directories inside the zip file, because zip files may or may not contain separate entries for directories. And it gets all of those things right.

But this code has a number of problems… Some of them are:

  1. The difference between enumerating files and directories is minimal, yet it uses two very similar blocks of code. This could have been made far simpler.
  2. In some lines, it uses constants and string literals that represent the same values, in the same line. That’s just poor programming right there. Nobody who isn’t high as a kite would ever do that.
  3. It always enumerates everything in the zip file, then discards the entries it doesn’t need. That’s a known anti-pattern and a big no-no in programming. What it should have done was to cache the contents of the zip file. i.e. only enumerate it once, unless it changes. The reason was pure laziness… My GUI also allows editing of the zip, which meant that this code would somehow need to be aware of changes to cached entries, possibly by implementing an observer pattern. It is fast though, even for zip files containing thousands of entries, but that’s no excuse for poor code.
  4. It uses separate collections for directories and files; then sorts them separately just so that directories will always be displayed before files. Again, this is pure laziness, considering that the same application, which also features a file browser, knows how to sort a collection that contains both files and directories. i.e. I implemented a Comparer<T> somewhere else in the same application that could do this, but used different, less efficient logic here.
  5. Probably the worst part is that it then builds ListView items directly to populate my custom “Shell ListView” control. This code should have built some sort of structure or collection of the data, but it should not have been creating controls to use on the GUI directly. Now I can’t use the code anywhere else…

Granted, this is not terrible code. It’s my own, and it does its intended job. Sadly I have known many programmers who wouldn’t be able to do this even though they have never used drugs. (But those people are not real programmers in my view. Copying and pasting or downloading others’ source code is not programming; real programmers write their own code.) The code does some clever stuff, like sorting in parallel (via some extension methods that use Microsoft sample code that I modified but did not write – I’m not that smart), and the other code not shown, such as the custom ListView that looks similar to the Windows shell one, and displays shell icons, is pretty good. Also not shown are my methods for doing everything with zip file contents asynchronously. So the code works well… It’s functional, but at the end of the day it is competent. I can be so much better than competent. I can be excellent but on meth, competent is all I’ll ever be.

So that’s the point of this post. When we use drugs we often fool ourselves into thinking that we can still perform well enough at our jobs. (This was my own private code, but still, it is programming and that’s what I do for a living.) Especially on drugs like meth or cocaine, we think it makes us alert and clever. We think we are doing well when we use drugs, but we are not.

Here is the shoddy code described above: (Sorry, it would be too much effort to make this wrap well in the tiny width of this post. The tool I use to generate code snippets in the blog does add a scrollbar, but only at the bottom… I haven’t found a better one yet.)

/// <summary>Populate the file and directory list from the zip file entries, keeping track of the current directory
/// in a class-level property. We always only display the files and directories contained by the current directory.
/// path == null indicates that the current directory is the root directory of the zip file.</summary>
private void Populate(string path = null)
{
    CurrentZipDirectory = path;

    // Use threadsafe collections to hold temporary lists of files and directories.
    var directoryBag = new ConcurrentBag<ListViewItem>();
    var fileBag = new ConcurrentBag<ListViewItem>();

    // This list will be filtered for the current directory.
    var zipFileEntries = Enumerable.Empty<ZipArchiveEntry>().ToList();

    try
    {
        using (var zipArchive = ZipFile.Open(Filename, ZipArchiveMode.Read))
        {
            try
            {
                zipFileEntries = zipArchive.Entries.ToList();
            }
            catch (Exception ex)
            {
                ex.Log();
                MessageBox.Show(Browser.Instance, 
                    string.Format("The zip file appears to be invalid and could not be read.\n{0}", ex.Message), 
                    "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            // Discard everything that is not nested in/below the current directory
            if (path != null)
                zipFileEntries.RemoveAll(
                    entry => !(entry.FullName.StartsWith(
                        path + Romy.Core.Constants.DelimiterChars[0]) || 
                        entry.FullName.StartsWith(path + Romy.Core.Constants.DelimiterChars[1])));

            /* Get the directories to display. Zip files sometimes contain entries for directories, but often
             * do not, and when we parse the entries paths, there will be many recurrences of each directory.
             * Thus use a dictionary to keep track of the directories we have already found. */
            var directories = new ConcurrentDictionary<string, string>();

            var directoryEntries = zipFileEntries.Where(e =>
            {
                // Filter for subdirectories of the current directory.
                var filenameInZip = e.FullName;

                /* Remove current directory from string, so that the same
                 * string-manipulation logic applies to all directries. */
                if (path != null)
                    filenameInZip = filenameInZip.Substring(path.Length + 1);

                /* With the current directory removed, any string that contains one slash (forward or
                 * backslash; whatever this zip file uses) is a sub-directory of the current directory. */
                if (filenameInZip.Count(c => c == '\\' || c == '/') > 0)
                {
                    var directory = filenameInZip.Substring(0, filenameInZip.IndexOfAny(Romy.Core.Constants.DelimiterChars));

                    if (!directories.Values.Contains(directory))
                    {
                        directories[e.FullName] = directory;
                        return true;
                    }
                }
                return false;
            });

            try
            {
                directoryEntries.AsParallel().ForAll(entry =>
                {
                    var index = path == null ? 0 : path.Length + 1;
                    var relativePath = entry.FullName.Substring(0, entry.FullName.IndexOfAny(Romy.Core.Constants.DelimiterChars, index));

                    /* Use my SimpleFileInfo helper class to get the file or directory description and image
                     * index from the SystemImageList. (The SystemImagelist is used by the listview.) */
                    var simpleFileInfo = new SimpleFileInfo
                    {
                        Name = directories[entry.FullName],
                        FileSystemType = Romy.Core.FileSystemType.Directory,
                        //DateModified = entry.ModifyTime,  // This date in this entry refers to a file, not the directory. As we built the
                        Size = 0                            // dictionary of directories, we kind of hijacked a file entry to use for the directory.
                    };

                    directoryBag.Add(ShellListView.CreateListViewItem(new ZipEntryInfo
                    {
                        SimpleFileInfo = simpleFileInfo,
                        DisplayName = relativePath,
                        CompressedLength = entry.CompressedLength,
                        FullName = entry.FullName,
                        LastWriteTime = entry.LastWriteTime,
                        Length = entry.Length,
                        Name = entry.Name
                    }, simpleFileInfo));
                });
            }
            catch (AggregateException ax)
            {
                var handled = false;

                ax.Handle(ex => handled = ex is ArgumentOutOfRangeException);

                if (!handled)
                    throw;
            }

            /* Get the files. The logic is almost identical to the directories. */
            var fileEntries = zipFileEntries.Where(e =>
            {
                return path != null ? 
                    e.FullName.IndexOfAny(Romy.Core.Constants.DelimiterChars, path.Length + 1) == -1 
                    : e.FullName.IndexOfAny(Romy.Core.Constants.DelimiterChars) == -1;
            });

            try
            {
                fileEntries.AsParallel().ForAll(entry =>
                {
                    var relativePath = entry.FullName;

                    if (path != null)
                        relativePath = relativePath.IndexOf(Path.DirectorySeparatorChar) != -1 ? 
                            relativePath.Replace(path + Path.AltDirectorySeparatorChar, string.Empty) 
                            : relativePath.Replace(path + '/', string.Empty);

                    if (!string.IsNullOrEmpty(relativePath) && 
                        !(relativePath.EndsWith(Path.DirectorySeparatorChar.ToString()) && 
                        !(relativePath.EndsWith(Path.AltDirectorySeparatorChar.ToString()) && 
                        entry.Length == 0)))
                    {
                        var simpleFileInfo = new SimpleFileInfo
                        {
                            Name = relativePath,
                            FileSystemType = FileSystemType.File,
                            DateModified = entry.LastWriteTime.LocalDateTime,
                            Size = entry.Length
                        };

                        fileBag.Add(ShellListView.CreateListViewItem(new ZipEntryInfo
                        {
                            SimpleFileInfo = simpleFileInfo,
                            DisplayName = relativePath,
                            CompressedLength = entry.CompressedLength,
                            FullName = entry.FullName,
                            LastWriteTime = entry.LastWriteTime,
                            Length = entry.Length,
                            Name = entry.Name
                        }, simpleFileInfo));
                    }
                });
            }
            catch (AggregateException ax)
            {
                var handled = false;

                ax.Handle(ex => handled = ex is ArgumentOutOfRangeException);

                if (!handled)
                    throw;
            }

            // Copy our ConcurrentBag lists to arrays, and sort them in parallel.
            var directoryItemArray = directoryBag.ParallelSort(Comparer<ListViewItem>.Create((x, y) =>
            {
                return string.Compare(
                    ((ZipEntryInfo)x.Tag).DisplayName, ((ZipEntryInfo)y.Tag).DisplayName, 
                    StringComparison.InvariantCultureIgnoreCase);
            })).ToArray();

            var fileItemArray = fileBag.ParallelSort(Comparer<ListViewItem>.Create((x, y) =>
            {
                string xString = ((ZipEntryInfo)x.Tag).DisplayName;
                string xExtension = Path.GetExtension(xString);
                xString = Path.GetFileNameWithoutExtension(xString);

                string yString = ((ZipEntryInfo)y.Tag).DisplayName;
                string yExtension = Path.GetExtension(yString);
                yString = Path.GetFileNameWithoutExtension(yString);

                return (xExtension + xString).CompareIgnoreCultureAndCase(yExtension + yString);
            })).ToArray();

            listView.BeginUpdate();
            try
            {
                listView.Items.Clear();

                listView.Items.AddRange(directoryItemArray);
                listView.Items.AddRange(fileItemArray);

                if (fileItemArray.Length == 0)
                {
                    sizeHeader.Text = string.Empty;
                    modifiedHeader.Text = string.Empty;
                }
                else
                {
                    sizeHeader.Text = "Size";
                    modifiedHeader.Text = "Modified Date";
                }

                if (listView.Items.Count > 0)
                    listView.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
            }
            finally { listView.EndUpdate(); }
        }

        validZipFile = true;
    }
    catch (InvalidDataException ex)
    {
        ex.Log();
        MessageBox.Show(Browser.Instance, 
            string.Format("The zip file appears to be invalid and could not be read.\n{0}", ex.Message), 
            "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        return;
    }

    UpdateStatusStripInfo();
    SelectLastDirectory();

    // The vertical scrollbar is not being painted unless we mouse-over it or force a repaint.
    // Thanks to writing my own crappy control instead of downloading a decent one.
    listView.Invalidate(true);
    listView.Update();

    InitializeControls();
}
Advertisements

About Jerome

I am a senior C# developer in Johannesburg, South Africa. I am also a recovering addict, who spent nearly eight years using methamphetamine. I write on my recovery blog about my lessons learned and sometimes give advice to others who have made similar mistakes, often from my viewpoint as an atheist, and I also write some C# programming articles on my programming blog.
This entry was posted in Addiction, Methamphetamine, Programming and tagged . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s