Blog

Don’t try this at work – Vector Pt. 1

Welcome back! I hope you’re enjoying quarantine. I know for me, not being able to get out climb has definitely had an impact on my mental health. Oh, and my waistline. That being said, I’ve had more time to get into the code, which is a piece of my own little paradise.

As I mentioned in my last write-up, I’m trying to bring these posts back to basics, and give people more of what they’re interested in reading. Though, it’s very likely that the people find those posts more interesting, because I had more fun writing them. Reverse engineering the C++ unit test framework brought me immense joy, because I was really excited by it, and to write about it. With that in mind, I spent a good long while trying to figure out what I should post next. I haven’t had the itch to deconstruct anything lately. I decided to rack my brain, and remember what the original intent of my blog was. To demystify code, to remove the “magic” behind it. I’ve always been curious about the way things worked. As developers, we shouldn’t be afraid of the magic behind libraries, we should embrace it. We should strive to understand at least peripherally how the code we use works. I once made a comment on Reddit, to a untrained junior developer looking for tips on how to further his career. The tip was that they should take their work code home, and try to recreate it. For me, recreating code I didn’t understand was always the best tool to further my understanding. You start small, and you build, as you run into problems you start to understand why the author did the things they did. You can start to form opinions about the decisions they made, as you understand the problems they faced. Needless to say, this comment was down-voted into oblivion, and someone even suggested that I was instructing OP to steal their employer’s code. (Spoiler: I wasn’t.) Reddit not agreeing with me didn’t change my mind. I still think that reverse engineering something is the best way to understand it. If you’ve got access to the code on a laptop, I’m sure your boss wouldn’t mind if you took the initiative to understand company code better. Just don’t go selling your companies code.

So, that’s sort of what inspired this series, Don’t try this at work. In my personal experience, I’ve noticed a commonly occurring problem, people experimenting at work. I’m sure we can all agree that writing code, is as much an art, as it is a science. The problem is, that often times if people don’t have an outlet outside of work, they’ll use the company code base as their canvas. This can be problematic for smaller companies, who don’t always have the capacity and resources of a larger company to catch these things. These “works of art” can sometimes make it into production code, thus needing to be maintained for the lifetime of the application. This type of exploratory code is often coined “toy” code, it’s code you definitely shouldn’t be using at work. Hence, Don’t try this at work. In the Don’t try this at work series, I want to demystify the one of the most commonly used classes, in the most common library, used by almost all C++ developers. The Standard Template Library.

In this, the first of the Don’t try this at work series, I’m going to be looking at something every C++ developer, regardless of experience, uses (or at least knows of). Just because we all use it, doesn’t mean we understand it. So without further ado, let’s dive into the vector!

You can find all the code I write for this series here, if you have any questions or comments feel free to shoot me an email.

The STL vector is the probably the most ubiquitous container used in C++. If you need a generic dynamically sized container, the vector is the first tool you should grab from the STL’s bag of tricks. It’s a thin wrapper over contiguous memory, providing immense usability with little overhead over a raw array. It can easily be used with STL algorithms, and fits most cases where a dynamically sized container is required. It features constant time random access, amortized constant appending and removal to the end, and linear insertions and deletions. In short, if you don’t use vectors, you should.

Warning: Because a vector is a generic container, we’re going to be doing template programming. So if you’re faint of heart, stop reading now.

Where do we start? Well, the vector is essentially a wrapper over an array, that will expand when the array runs out of space. So, something simple probably looks like this.

template <typename T>
class vector
{
    T* data_;
    size_t size_;
    size_t cap_;
public:
    vector()
        :data_(new T[10]),size_(0),cap_(10)
    {
    }

    void push_back(const T& value)
    {
        if (size_ == cap_)
        {
            grow();
        }
        data_[size_++] = value;
    }

private:
    void grow()
    {
        T* tmp = new T[cap_ * 2];
        for (int i = 0; i < size_; ++i)
            tmp[i] = data_[i];
        cap_ = cap_ * 2;
        auto data = data_;
        data_ = tmp;
        delete data;
    }
};

Pretty simple right? The basics of a vector are that, we have an array, the count of objects (size), and the capacity. When we push a new object, we check to see if we have space, if not we’ll grow, and then push that item on the end. When we do have to grow, we allocate double the capacity, copy all the items over, and then delete the old array. Neat huh? The problem is, that this is toy code. It’s inefficient, it requires that objects be default constructible, and not to mention it isn’t at all safe. It gets the point across, but it’s not really rocket science, or STL science for that matter. This code is a Fisherprice vector. It’s light-years away from being a real vector. This is your 3 year old’s vector. We want a real vector. We want a vector that looks and feels like the vector you use from your compiler writer.

Where do we even start? Well, the first thing would be to maybe look at a real vector implementation. Cooking is also an art form, and when you’re learning how to cook something new, you generally use a recipe. So, let’s start with a recipe.

I’m a Microsoft guy, through and through. So naturally, my first thought was to go look at the files in VS 2019. So I cracked open Visual Studio, opened a new C++ file, typed #include <vector>, right-clicked “Go to Document <vector>”, and voila. Sorry vim folks, I’m not sure if you can do that, BUT BASICALLY I RIGHT CLICKED AND OPENED THE VECTOR FILE. Have you ever looked at the MSVC’s implementation of anything STL? Well, be thankful when “Just my code” works when you’re debugging. Here’s a snippet. (I didn’t write this code, it’s directly from MSVC vector)

Note: If you don’t use Visual Studio to code and debug. I truly feel sorry for you.

// vector standard header

// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// ...
template <class _Ty, class _Alloc = allocator<_Ty>>
class vector { // varying size array of values
private:
    template <class>
    friend class _Vb_val;
    friend _Tidy_guard<vector>;

    using _Alty        = _Rebind_alloc_t<_Alloc, _Ty>;
    using _Alty_traits = allocator_traits<_Alty>;

public:
    static_assert(!_ENFORCE_MATCHING_ALLOCATORS || is_same_v<_Ty, typename _Alloc::value_type>,
        _MISMATCHED_ALLOCATOR_MESSAGE("vector<T, Allocator>", "T"));

    using value_type      = _Ty;
    using allocator_type  = _Alloc;
    using pointer         = typename _Alty_traits::pointer;
    using const_pointer   = typename _Alty_traits::const_pointer;
    using reference       = _Ty&;
    using const_reference = const _Ty&;
    using size_type       = typename _Alty_traits::size_type;
    using difference_type = typename _Alty_traits::difference_type;

private:
    using _Scary_val = _Vector_val<conditional_t<_Is_simple_alloc_v<_Alty>, _Simple_types<_Ty>,
        _Vec_iter_types<_Ty, size_type, difference_type, pointer, const_pointer, _Ty&, const _Ty&>>>;

public:
    using iterator               = _Vector_iterator<_Scary_val>;
    using const_iterator         = _Vector_const_iterator<_Scary_val>;
    using reverse_iterator       = _STD reverse_iterator<iterator>;
    using const_reverse_iterator = _STD reverse_iterator<const_iterator>;

    vector() noexcept(is_nothrow_default_constructible_v<_Alty>) : _Mypair(_Zero_then_variadic_args_t()) {
        _Mypair._Myval2._Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alty, _Getal()));
    }

// ..

Mmhmmm. Yup. Feast your eyes. If the code I wrote was Fisherprice, this is Dewalt. It’s safe, efficient, and it works. The reason that we never question much about things in the STL, is because they almost always work the way we expect them to work. The authors of these libraries deserve praise. So if you’re an STL developer, you have my sincerest thank you. The problem is, that this code is so dense, and I for one am not smart enough to understand what’s going on at a glance.

Shout out to @StephanTLavavej, and all others on the Visual C++ team for making our lives easier.

What do you think a _Scary_val is? I actually have no idea.

Okay — so that recipe might as well be in Cuneiform, or French. Neither of which I’m particularly talented at reading. We need a recipe we can understand. Thankfully, I did some digging, and I was able to find something. Located in the depths of the internet, here, I found Alexander Stepanov’s implementation of the STL. If you don’t know who Alex is, he’s the father of the STL. The man is a living legend, to him we owe a massive thanks. Anyways, his implementation of vector, is clean, simple, and readable. It’s something we can easily consume. The only problem is, that it’s from 1994. Do you know what this means? It means it was written when mullets were popular. I would know, I had one. It also means, that it was written before any of the cool modern C++ existed. It was written before C++ was even standardized!! Talk about using Grandma’s recipe. It’s fine, we’ll make due, things haven’t changed that much, have they? Until I find a better resource, this is the best I’ve got. (Edit: I actually found another good resource, a bit into my experiment, the EASTL). I’m going to use a hybrid between Stepanov’s vector, the CPP reference standard, and whatever I can figure out from MSVC. Then I’ll sprinkle a little bit of my knowledge, and bingo, we’ll have a real working vector.

Let’s start by defining what we’re working towards. First, we want a standard vector. This means we want it to fulfill the standard for what a vector is. It needs to work with standard algorithms, which we’ll eventually test. Lastly, we’re going to compare it performance wise to MSVC’s implementation.

From cppreference.com, a vector is a sequence container that encapsulates dynamic sized arrays. It’s declaration looks like this.

template <typename T, typename Allocator = std::allocator<T>>
class vector;

So, the template declaration is a bit different from the toy code we looked at earlier, and Stepanov’s vector. It has this weird thing called an Allocator. So you might be asking, “what’s an allocator, and why is it a template argument?” Let’s address the first question, an allocator encapsulates your allocation mechanism. This means, it hides away how the memory is getting allocated, behind a constant interface. To answer the second question, it’s a template argument, so that you can supply what type of allocator your vector will use. A huge part of what makes the STL so nice, is that it’s very very flexible. It works against all your custom hand rolled classes, and it allows you to control how allocations happen for standard containers. It does this through the Allocator template argument. Why would anyone use a custom allocator? Well — a few reasons come to mind. If you’ve got memory constraints. Or maybe you have a highly optimized use for your vector. You might want to use a custom allocator for these cases. Maybe you noticed that Stepanov’s vector implementation doesn’t have the allocator template either. However, if you read deeper, he uses a static member allocator that’s defined at the top section of the code.

If you recall back to the toy code, we used “new T[]” directly to allocate our array. This is problematic for two reasons. It forces the user of our toy vector, to use the runtime’s default allocation mechanism and it will call the default constructor on all of the items in the array. So we force our library user to have a default constructor on all their objects and use the default allocation heap. No bueno. The Allocator interface breaks the responsibility of allocation and construction, into two separate calls. This way we can control when the memory gets allocated for our objects, and when our objects get constructed. The member functions of an allocator are:

template <typename T>
struct allocator
{
    allocator()=default;
    ~allocator()=default;

    // return the address of an object
    T* address(T&);

    // allocates sizeof(T) * count
    T* allocate(size_t count);

    // deallocates the storage pointed to by p, must have been obtained by a call to allocate
    void deallocate(T *p);
    
    // construct - a given object in place of p (deprecated C++17, removed C++20)
    template <typename ...Args>
    void construct(T *p, Args &&args);
    
    // destroy - destruct the object pointed to by p (deprecated C++17, remove C++20)
    void destroy(T *p);

};

Note: I’ve chosen to use the deprecated functions construct / destroy. They’ve been replaced by allocator_traits, and honestly, I just didn’t want to go that far down the rabbit hole for this first post. So my vector takes advantage of them. For now.

So given that we can’t have a vector, without an allocator, we should probably start our journey there.

For brevity, I’m not going to write out the entire implementation, but I will write out one of the important functions, allocate. Taking a look at Stepanov’s implementation.

/*
 * Copyright (c) 1994
 * Hewlett-Packard Company
 */
template <class T>
inline T* allocate(ptrdiff_t size, T*) {
    set_new_handler(0);
    T* tmp = (T*)(::operator new((size_t)(size * sizeof(T))));
    if (tmp == 0) {
	cerr << "out of memory" << endl; 
	exit(1);
    }
    return tmp;
}

It’s pretty simple, we just use ::operator new, to allocate some space of the size multiplied by the size of our type. If we fail (returns 0), we write to the standard error, and exit the application. We what? We write to the standard error, and exit the application. Hmmm. I would’ve expected this to use exceptions, but my best guess is that in 1994, exceptions were not yet widely accepted. Also, at the time, if you ran out of memory, what was a guy to do? Other than to print to standard error, and crap itself. Well — in this day and age, that isn’t appropriate. We’ve got something up our sleeves known as exceptions. Exceptions are a fundamental piece of the STL, and they’re perfect for this very thing. The only problem is that, in this little experiment we’re doing, we have to implement everything that isn’t bare metal C++ (mostly). So, we’ve gotta implement standard exceptions.

Thankfully, exceptions aren’t that complicated. They’re basically a wrapper over a constant character array, or in other words, an immutable string.

class exception
{
    const char * const message_;
public:
    exception()
        :message_(nullptr)
    {
    }

    exception(const char* message)
        :message_(reinterpret_cast<const char *>(::operator new(strnlen(message,256))))
    {
        if (message_ == nullptr)
            exit(-1);
        strncpy_s(const_cast<char *const>(message_), 256, message, 256);
    }

    exception(const exception& e)
        :exception(e.message_)
    {
    }

    ~exception()
    {
        ::operator delete(const_cast<void*>(reinterpret_cast<const void*>(message_)));
    }

    virtual const char* what()
    {
        return message_;
    }

};

class bad_alloc : public exception
{
public:
    bad_alloc()
        :exception("bad_alloc")
    {
    }
    bad_alloc(const char *message)
        :exception(message)
    {
    }
};

So, now that we have an exception to throw, we can use it in our allocator and have the allocation look something like this.

pointer allocate(size_t count)
{
    T* temp = static_cast<T*>(::operator new(count*sizeof(T)));
    if (temp == nullptr)
    {
        throw bad_alloc();
    }
    return temp;
}

Once we have our allocation function, the rest of the allocator is pretty self explanatory. Mine came out looking something like this.

template <typename T>
struct allocator
{
    using pointer = T*;
    using const_pointer = const T*;
    using reference = T&;
    using const_reference = const T&;
    using size_type = size_t;

    allocator() = default;
    ~allocator() = default;

    // address
    pointer address(reference x) const
    {
        return &x;
    }

    const_pointer address(const_reference x) const
    {
        return &x;
    }

    pointer allocate(size_t count)
    {
        T* temp = static_cast<T*>(::operator new(count*sizeof(T)));
        if (temp == nullptr)
        {
            throw bad_alloc();
        }
        return temp;
    }

    void deallocate(pointer p, size_type n)
    {
        ::operator delete(p, n * sizeof(T));
    }

    size_type max_size() const
    {
        return max(size_type(1), size_type(UINT_MAX / sizeof(T)));
    }

    template <typename ...Args>
    void construct(reference dest, Args&&... args)
    {
        ::new (static_cast<void*>(&dest)) T(htk::forward<Args>(args)...);
    }

    void destroy(pointer p)
    {
        p->~T();
    }
};

Basically, the calls are thin shims into the default C++ mechanism for allocation (new) and deallocation (delete). Then the construction uses placement new to construct the object in a given destination, and the destroy call explicitly calls the destructor.

If you’re still following along, before we even started writing our vector, we needed to create some foundations. I searched and searched, but I couldn’t find instructions on how to implement an STL. What I mean by that, is where do you even start? Obviously classes in the STL depend on other classes in the STL, but where’s the leaves? I wish I could say I found that. So my best bet it to just pick a common class, and implement. So thus far, we have the basic exception, we have a bad_alloc exception, and we have the default allocator. All so we can start on our vector.

In order to keep this post from becoming my first novel, we’re just going to focus on implementing one method on the vector. We’ll leave the default construction for now, and we’ll look at the emplace_back function. This is a function that allows for argument forwarding, into direct construction at the back of the vector. It’s a really nice starting point. It seems rather straightforward. I’ll soon find out, it isn’t.

So the signature of emplace_back is something like this. It takes a variadic set of arguments, and returns the object it created. The decltype(auto) specifies that the compiler is to figure out the return type based on what we’ve returned.

template <typename ...Args>
decltype(auto) emplace_back(Args&&...args)
{
    ensure_space_at_least(1);
    allocator_.construct(*(data_.last++), htk::forward<Args>(args)...);        
    return back();
}

This code though, is pretty straightforward. We first ensure we have enough space for 1 element. Then, we use our allocator to construct the element in the last position, and increment the pointer.

You might be asking about this strange htk::forward<Args>(args)? Well, I debated going into it, and going down that rabbit hole. But decided against it. What std::forward or htk::forward does, is passes arguments exactly as they were passed into the function. This means that if we’re passing r-value references into emplace_back, we’re forwarding those as-is to the allocator construct call.

What does ensure_space_at_least(1) do? In our toy vector had some code to grow and copy our existing objects. That’s effectively what this is doing. We’re going to ensure we have space for at least one element. If we do we can just create the new item, right at the end of that memory we allocated earlier. This illustrates separating allocation from construction. We allocate space which hasn’t been initialized, then when someone pushes into our vector, we just initialize that memory!

void ensure_space_at_least(size_t count)
{
    if (initialize(count))
        return;
    // we need to see if we have enough space.
    if (freespace() < count)
    {
        const auto cap = calculate_growth(count);
        grow(cap);
    }
    // we good.
}

So the first line, is just to initialize the vector. Since with this vector, we’re starting out with no memory allocation. The first call will just allocate some memory, and return. If we have enough memory allocated, we don’t do anything. Where we’re really interested, is when we don’t have enough memory available. Our growth algorithm, is just going to keep doubling the capacity until we can fit the count. So that’s what calculate_growth(count) will do. Just return us the next capacity that’ll fit our count. Then we need to grow our memory.

In order to grow the memory, we need to do a couple things. First, we need to allocate a contiguous block for our new capacity. Then we need to transfer all existing items into the new memory block. Then we need to free our old memory.

void grow(size_type cap)
{
    pointer new_vec = allocator_.allocate(cap);
           
    move_items(data_.first, data_.last, new_vec);

    auto old = data_;
    auto curs = size();
    data_ = data{ new_vec,dest, new_vec + cap };

    // destroy the old stuff
    destroy(old.first, old.last);
    allocator_.deallocate(old.first, old.capacity());
}

void move_items(pointer first, pointer last, pointer dest)
{
    while (first != last)
        allocator_.construct(*(dest++), *(first++));
}

First thing we do, is to allocate the size of our capacity. Then we call move_items, which takes the first, and last element, and a pointer to the new destination. Then in move_items, we just iterate from first to last, and construct the old item into the destination, and increment it. Then, we’ll assign our new vector pointer to our internal data pointer, then destroy all the old items, and deallocate the memory. With that, we have a pretty simple growth algorithm that copies from our old vector into the new space, and frees up the old items.

My initial thought was to type “we’ve got a problem here“, like we only have one. There’s a boatload more than one problem in this code. This folks, is why being a library developer is hard. At this point, we’re still only writing the basic algorithm. We haven’t taken into account safety, or optimization. Just thank your god, that you don’t have be a library developer. (unless you want to be, you masochist.)

The first problem we’re going to address, is the fact that we only support copying items. This means, that every time our vector expands, we’re going to copy all the items over. For large types, this can be costly, and as of C++11 we don’t need to copy the items. We want to take advantage of move semantics. Move semantics are a pivotal part of smart pointers, and optimizations for things like the vector, because they effectively allow you to move the guts from one object to another. This is primarily useful when you have a temporary, or an item you know will be going out of scope, and do not want to copy. It’s done by defining a “move constructor” (see Rule of 5).

If you think about an object like a vector, that has an internal pointer to some array of objects. In C++98, when we pass that object by value (a copy), to be correct, we would need to allocate enough space, and copy all the items over into the new vector. This means then, we would have two copies of our vector. If you were passing this into a function, that vector you copied would then be destroyed. This is very wasteful. This also would happen when you would return by value. It’s obvious today, that we need a way to say “I’m only temporary”, and when it’s a temporary, we can commandeer that temporaries pointer as our own, set his pointer to nullptr, and let him go out of scope. This way we’ve moved the object. Before we had move semantics we had a lot different techniques, like reference out parameters, and copy-on-modify semantics. With move, those workarounds aren’t necessary.

Obviously, we want to take advantage of move semantics when we copy our vector. That way, if the class we’re holding is optimized for move, we will use that and not copy it. As well, we can hold on to classes that have only move semantics, and not copy. Things like resource holders. So how do we do that?

In order to take advantage of move semantics, we need to use std::move (or in our case htk::move), which will convert an object reference into an r-value reference.

void grow(size_type cap)
{
    pointer new_vec = allocator_.allocate(cap);
    
   if(has_move_semantics())
   {
         move_items(data_.first, data_.last, new_vec);
   }    
   else
   {
         copy_item(data_.first, data_.last, new_vec);
   }

    auto old = data_;
    auto curs = size();
    data_ = data{ new_vec,dest, new_vec + cap };

    // destroy the old stuff
    destroy(old.first, old.last);
    allocator_.deallocate(old.first, old.capacity());
}

void move_items(pointer first, pointer last, pointer dest)
{
    while (first != last)
        allocator_.construct(*(dest++), htk::move(*(first++)));
}

void copy_items(pointer first, pointer last, pointer dest)
{
    while (first != last)
        allocator_.construct(*(dest++), *(first++));
}

It’s that simple! Pfft. Library implementation is easy…. Just kidding. This probably is not that easy. If this way did work, we would be doing the check at runtime! Because whether or not a type can be moved, is based on the class definition (does the class implement a move constructor?). We can do this check at compile time. This means, that when the vector code is generated for contained type i.e. <T>, we know whether we want to move or copy it.

If you’ve ever programmed in a language that doesn’t have function overloading. You’ll know how important it is. Because it lets you specify a function with the same name, but different arguments, and then the compiler can choose the best function to call, based on the type you’ve provided it. This is great, because then we can write one algorithm, and based on the type the compiler can select the best function to call. When we’re talking template code, the compiler will only call the required function. This may seem like a digression, but it’s not, and let me show you why.

template <typename T>
class adder 
{
    T value_;
    public:
    adder(const T &value)
    :value_(value)
    {
    }
    void add(const T& value)
    {
        add_internal(value);
    }
    const T& get() const
    {
        return value_;
    }
    private:
    void add_internal(const std::string &s)
    {
        value_ += " + " + s;
    }
    void add_internal(int val)
    {
        value_ += val;
    }
};

This code isn’t really useful at all, but it’s just to illustrate the point, that based on the type of our template, we can call different functions. I made a compiler explorer here. You can see in the compiler explorer, that when we use a std::string, we call the appropriate add_internal. Can you see where this is going? We want to call different functions based on traits of the class we’re containing. So back to our grow code.

void grow(size_type cap)
{
    pointer new_vec = allocator_.allocate(cap);
    
    move_items(data_.first, data_.last, new_vec, /* something here */);
   
    auto old = data_;
    auto curs = size();
    data_ = data{ new_vec,dest, new_vec + cap };

    // destroy the old stuff
    destroy(old.first, old.last);
    allocator_.deallocate(old.first, old.capacity());
}

void move_items(pointer first, pointer last, pointer dest, /* argument when movable */)
{
    while (first != last)
        allocator_.construct(*(dest++), htk::move(*(first++)));
}

void move_items(pointer first, pointer last, pointer dest, /* argument when copyable */)
{
    while (first != last)
        allocator_.construct(*(dest++), *(first++));
}

We want to take advantage of overloading, and the template system, to call the right call based on our type. This is a technique called “tag_dispatching“, we want to get the compiler to pick the right function, based on the template type we’re using. Or, at least that’s what we’re trying to do. ūüôā

I’ve been eluding to “traits about a type” without outright calling it what it is. To a library author, I can only assume that type_traits are a bit like paint, to a painter, or gasoline, to an internal combustion engine. (or arsonist?) Type traits (type_traits) are part of the STL, and they allow you to get compile time answers to questions about the types that the template code is working on. In our case, we want to ask the question “is this class moveable”? and based on the answer, we’ll have the compiler call the right move_items call.

In the STL, these “questions” are generally answered by small helper structs called type_traits. In general, they take a type argument (or a few), and give back a compile time constant boolean value. You can ask questions like:

std::is_reference<T>;
std::is_pointer<T>;
std::is_member_pointer<T>;

Honestly, there’s a lot, if you can think to ask it about a class, it’s probably a type_trait. Type traits are a build up of little tiny structs, that enable huge possibilities. The root of most type traits, is this thing called a bool_constant. It’st just a small struct that has a boolean as a compile time constant. With this, we can define two types (obvs) std::true_type && std::false_type. These classes are aliases of bool_constant<true> and bool_constant<false> respectively. So let’s go back to the code.

void grow(size_type cap)
{
    pointer new_vec = allocator_.allocate(cap);
    
    move_items(data_.first, data_.last, new_vec, /* something here */);
   
    auto old = data_;
    auto curs = size();
    data_ = data{ new_vec,dest, new_vec + cap };

    // destroy the old stuff
    destroy(old.first, old.last);
    allocator_.deallocate(old.first, old.capacity());
}

void move_items(pointer first, pointer last, pointer dest, htk::true_type /* is moveable */)
{
    while (first != last)
        allocator_.construct(*(dest++), htk::move(*(first++)));
}

void move_items(pointer first, pointer last, pointer dest, htk::false_type /* is not moveable */)
{
    while (first != last)
        allocator_.construct(*(dest++), *(first++));
}

You can start to see how we can get the compiler to choose which function to call. If we want to move the object, we use htk::true_type as the tag that we want to move, and htk::false_type when we want to copy. The last piece is asking the question! Thankfully, in the STL’s bag of tricks there’s a helpful trait called std::is_move_constructible<T>.

Since this blog is about demystification, this is the last piece (for now) of wool we need to lift off our eyes. How do we implement is_move_constructible<T>? I’ll be totally honest with you. I had 0 idea. My first thought was I needed to some how have the compiler test call the move constructor with the arguments, and see if that could compile, if not fallback to false_type, this is something called SFINAE. (I’m definitely not an expert, and I have little confidence I could explain it without a significant amount of research.) So after some thinking, I decided I need to phone a friend. So I pulled up VS again and dove into type_traits.

// STRUCT TEMPLATE is_move_constructible
template <class _Ty>
struct is_move_constructible : bool_constant<__is_constructible(_Ty, _Ty)> {
    // determine whether _Ty can be direct-initialized from an rvalue _Ty
};

That’s it. No crazy template magic. Just 3 little lines. Wemp. Womp.

But wait! What the heck is that __is_constructible(_Tv, _Ty)? Yeah. That had me too. I actually spent longer than I’d like to admit, trying to figure that *expletive deleted* out. It wasn’t until I found the EASTL, that it dawned on me. Well, there’s a line that gives it away.

#if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_constructible)))

I’ll let you see their code when the compiler doesn’t do it, for yourself here. It’s really quite fascinating and very impressive. Thank goodness for Microsoft and the compiler writers, because they made that job easy. We basically have a compiler intrinsic function, that will answer that question for us! Let’s go back to our code, so we can finish this off.

void grow(size_type cap)
{
    pointer new_vec = allocator_.allocate(cap);
    
    move_items(data_.first, data_.last, new_vec, htk::is_move_constructible<T>::value);
   
    auto old = data_;
    auto curs = size();
    data_ = data{ new_vec,dest, new_vec + cap };

    // destroy the old stuff
    destroy(old.first, old.last);
    allocator_.deallocate(old.first, old.capacity());
}

void move_items(pointer first, pointer last, pointer dest, htk::true_type /* is moveable */)
{
    while (first != last)
        allocator_.construct(*(dest++), htk::move(*(first++)));
}

void move_items(pointer first, pointer last, pointer dest, htk::false_type /* is not moveable */)
{
    while (first != last)
        allocator_.construct(*(dest++), *(first++));
}

With that we’ve got our vector growing, and choosing the correct function for copying the old items, based on the type specified to the vector. Cool!

It’s been a journey, we waded (deeper than we may have wanted) into the world of the STL. We uncovered things like allocators, exceptions, and type_traits. We also looked at how we can leverage tag dispatching to ensure we’re doing the right thing based on the type at hand. We saw that library development past a toy, is hard. We didn’t even get into exception safety. Which admittedly complicates things passed something that’s understandable without writing a novel. I can only hope to be able to dig into that one day, until then we can let it remain magic. For now, we have the start of a vector, and some other useful tools in our just heavier than a toy STL.

I hope you enjoyed the opener in this vector series. Next up, we’ll be making our vector work with the STL algorithms. Then lastly, we’ll pit our vector against Microsoft’s, in a battle of the…. Well battle of the vectors. To see just how poorly this vector performs against the professionals.

Until then, stay healthy, and happy coding!

‚ÄúLife is really simple, but we insist on making it complicated.‚ÄĚ
‚Äē Confucius

References
https://en.cppreference.com/w/cpp/container/vector
http://stepanovpapers.com/butler.hpl.hp/stl/stl/VECTOR.H
https://github.com/microsoft/STL/blob/master/stl/inc/vector
https://github.com/electronicarts/EASTL
https://foonathan.net/2015/11/overload-resolution-3/


They say Hindsight is 20/20

As we enter into a new year, I can’t help but reflect on the last. What I did, what I didn’t do, with a focus things I’d like to accomplish in the coming 12 months. I’ll spare you the details of my self reflection. Though, I would like to share the method that I use for my approach. I am aware that this is a tech blog, some might feel that personal and self growth have no place here. Well to them, I say “thanks for the view”! ūüôā This is Unparalleled Adventure after all, and what would an adventure be without some reflection? For those of us in the industry, unless you want to stagnate, it’s important to set goals, reflect, and to take steps to get better. Self reflection and employee growth isn’t always on a company’s radar, which is interesting, because capital growth and ROI often are. For me, it seems there should be a positive correlation between employee growth, and growth of a company. However, I digress. If it’s not part of your companies yearly mandate to reflect and set goals. You should mandate it for yourself! Often times developers want to become super-star 10x developers overnight. This isn’t realistic, and can lead to disappointment in ones self. The reality of it, is that it takes time, and lots of work. Becoming a great developer is a lot like optimization, you can’t optimize what you don’t measure. So in order to progress, you need to reflect, and take stock of where you are, set some goals to progress, and most of all have a vision for where you want to go. For some of us, this can be quite an eye opening experience. If you’ve never reflected and looked objectively where you are at, you might surprise yourself, one way, or the other. If you’re struggling with the how to reflect, and set goals. It can be helpful to understand someone else’s approach.

Over the years, I’ve adapted a model that I feel has worked (for the most part) for me. As like anything in life, it doesn’t need to be followed to a tee, nor should it be written in stone. Instead it should grow and adapt, as you grow and adapt. You should follow what works, and disregard what doesn’t. My method may serve a a jumping-off point, or give you enough perspective to turn and run in a different direction. I’ve built the model I use off of what has worked for me in the past, removed what hasn’t, built on foundations learned in school, as well as tactics and practices I’ve picked up from books, conferences, podcasts, and some creative ideas I crafted myself.

If you’ve ever read the book Tools of Titans by Tim Ferris, you’d have seen the break down and categorization of Healthy, Wealthy, and Wise. Healthy being what directly affects the health of ones body. Wealthy being what directly affects the health of ones bank account. And, Wise being what direct affects the health of ones mind. For a few years, I crafted goals like I’d been trained in school. Short-term, Mid-term, and Long-term goals. I want to exercise more in the next 30 days. I want to learn to program in the next 6 months. I want to have my vehicle paid off in the next year. Regardless of the quality of these goals. I always struggled with a way to categorize and relate them. What does exercise, programming, and having my vehicle paid off have to do with each other? This problem was only magnified by my ability to be overly self critical. I felt that they didn’t make sense, and in turn it didn’t make me want to work towards them. After reading Tools of Titans, I decided to categorize my goals into the three categories. Healthy – goals that pertain to my physical health. Wealthy – goals that pertain to my financial health. Wise – goals that pertain to my mental health. I still kept the Short, Mid, and Long term lengths, and decided on one of each goal per category. This gave me a total of nine goals. Which wasn’t bad. I made them SMART goals, based on their time frame and I went from there.

The problem was within categories, the goals didn’t relate. The Short Term goal didn’t run into the Mid Term goal, which in turn didn’t do anything to help me get towards the Long Term goal. The second pitfall, was that my short term goal would get completed, and I would have nothing to work on that was “Short Term”, while I worked on the longer term goals. This year, I’ve decided a good structure is to have a “summary” for each category, and 3 SMART goals that work towards the summary per quarter. This leaves me with 3 months of goal to focus and work on, and in the next quarter make an adjustment. I’m hopeful this breakdown will give me more to work with, and allow me to work a little closer to my goals.

So, that brings us to the goals for my blog. In the two years I’ve had this blog, I’ve posted a whopping 14 posts. I’m proud of that, but it’s not the amount of content I would’ve liked to have posted. Though I never put a measurable goal, I would’ve liked to have closer to 50 posts. This year I dug in and set a goal, my goal for 2020 is 12 posts. It’s only 1 per month, so it’s seemingly doable. I’m hoping that 12 posts will raise readership and subscribers, and in 2021 I’ll be able to put more fingers to keys and share more of my learning.

In 2019, I had a total of 2 041 views, with 1 442 unique visitors. The post with the most views was¬†The one where we reverse engineered Microsoft’s C++ Unit Test Framework (Part 1) it had a total of 714 views! The series as a whole did quite well, totalling around 1500 views. My posts that talked about architecture, design, and advice I wish I would’ve listened to each had a whopping 1 view. (Probably was me reading it. :P) It’s obvious what people are interested in, and to be honest, it’s what I’m most interested in too. The code, digging into the details of the code, and doing obscure things.

I look forward to the next series of posts!

Until then, Happy Coding!

PL

Life can only be understood backwards; but it must be lived forwards. — Soren Kierkegaard

 

A Single Responsibility

Over the years I quite often find myself pondering software development patterns and practices. It’s the kind of thing I think about in my downtime, when I’m driving to and from work, or sitting at home… pondering. I always seem to come back to one question, is the common interpretation of the pattern, that is how the majority of the world sees and implements it, what the author had intended? Is that inventor okay with it? It’s not like I’m going to solve this mystery today. One day I might have the opportunity to meet one of these greats and ask them. Is the outcome of their idea what they intended? I often times find myself reading coding, or working on past code where the implementation, doesn’t line up with my current interpretation of the pattern / practice. Though, upon talking about the code, or reading comments, or blind guessing. It can be clear that the intent was to implement towards a given pattern. In my last post, I talked about Separation of Concerns, which in my opinion can be closely related to, and often confused with the “Single Responsibility Principle“.

The intent of my last post, on Separation of Concerns, was to show that it in itself is not a¬†pattern.¬†It’s merely a practice that can be applied to thought, at any level. This can apply to your application at a¬†macro level (application architecture), all the way down to the micro level (lines of code). Where I see things start to get fuzzy for people, is around the application into class level. The Single Responsibility Principle, is an embodiment of Separation of Concerns, but this embodiment is at a specific level. Unlike Separation of Concerns, Single Responsibility Principle applies only at the class level. I mean, that’s in the definition.

Classes should have a single responsibility and thus only a single reason to change.

But it’s like everything in software, open for interpretation. Patterns, Practices, and Principles fall victim to the subjective nature of application development. The real world of development rarely sees foo and bar, outside of whiteboard sessions. This means that you have to deal with real world objects, and real world problems. Then as developers we have to translate the canonical and sometimes naive FooBar examples, into our real world problems. Sometimes, more often than not, especially with less experienced developers, this leads to incorrect or harmful application of these principles.

Sometimes strict adherence to an interpretation of SRP and “Separation of Concerns”, can be deleterious to an application. The unfortunate nature of this, is that it’s a problem that doesn’t manifest until much later, when it’s too late. Now, I’m not trying to sit on my high-horse and say I don’t misapply these things. In fact, it would be foolish to think that anyone is perfect when it comes to this. I would be willing to bet that Martin Fowler himself doesn’t get it right 100% of the time. The difference is that with experience, you’re able to spot the blunder before it’s too late. Before you’ve gone to far, and you’re on the cliff being faced with a re-write. In the real world, this often times ends in a manager wishing he would’ve reviewed the code a little earlier, or a little more often. Hopefully, this post will help to clarify and add some litmus tests to the application of this principle.

First off, Separation of Concerns, isn’t SRP. If you think that, just forget it. Right now.

Separation of Concerns is the organization of thoughts, the ability to separate components, that are not overlapping, or mutually exclusive. Single Responsibility Principle, is an application of this practice, of grouping things that have the same concern, or reason for change into a single class. So it has a¬†real world, level of application. It’s at the class level, that’s where you apply it…. And this is where the problem stems.

Say you have an application, you’ve got a Web Service that deals with incoming client web requests, and you’ve got an Auxiliary Service that is moving data to and from a database, and servicing long running system requests. This is an example of Separation of Concerns. This is¬†not¬†an example of Single Responsibility Principle. It’s too macro, we’re talking at our application level. Not at the¬†class¬†level. The problem that will stem from this form of thinking, is¬†macro level class development. God classes. Sure — you have a class that represents your service that “Fulfills web service requests”. That’s his single responsibility… But is it? Is it really? If we imagine this mock class, he would have to

  1. Receive a message from the Web Server Service
  2. Parse said message
  3. Understand what to do
  4. Fulfill the request
  5. Build the response

Now, that’s definitely more than one responsibility! But from a macro level, it’s easy to see your class as having a single responsibility. You’re Separating your Concerns, remember?

In this case, it would probably make sense to have 1 class for building and parsing messages, 1 class that can switch on those messages to dispatch what to do, and 1 class for each of the actions to fulfill the requests. Woah. Woah. Woah. Wait just a minute. You just said 1 class for building and parsing… Isn’t that violating the SRP? Well, the answer as so many are in Software Development, is ‘it depends’. That statement, was intentional. It was meant to bring light to the fact, that the definition says “a single reason for change”. When you’re dealing with protocols, building and parsing can often be symmetrical. Therefor, if the protocol changes, that could be our single reason for change of this class. So it could be said to have a single responsibility of dealing with the protocol.

As you can see, where you focus the light of Single Responsibility will really play a factor into the organization and structure of your code. Just wait until you start shining that light too close.

When you start focusing the light at a micro level into your code. You’ll start to actually factor¬†out¬†responsibility.

Imagine you have a system, that is used to dispatch sms style messages, but it’s old school, so it takes time. You’ve got a client facing API called a MessageBroker, and a background service called a MessageDispatcher. Clients of your API deal directly with the MessageBroker, they give the MessageBroker in the format of

class Message 
{
public:
   enum RecipientTypes { Specified, Random }; 

public:
   const Address sender_;
   const Address recipient_;
   const RecipientTypes type_;
   const String &message_;
};

The intent, is that we give the MessageBroker the message, and he’ll do something with it for later pick-up by the MessageDispatcher. The MessageDispatcher will ensure delivery of the message to the recipient. Now, the API of the Message class is such that if you set the type, to Specified and set the address, the message will arrive at your intended target. However! If you set the type to Random, it should go to a random target. This randomness, isn’t really random, it could be based on a location heuristic.

You might think it’s best to define an interface for the message broker, and make it look something like this.

interface IMessageBroker 
{
    void Send(const Message &msg);
};

Then you might implement the IMessageBroker, something like this.

class MessageBroker : public IMessageBroker
{
public:
    void Send(const Message &msg)
    {
           // Validate the fields are appropriate for database
           ValidateFields(msg);
           // put it in the db
           Database.Store(msg);
    }

};

There you have it! Our SRP MessageBroker! He has a single responsibility. He accepts a message and stores it in the database. That’s it right? Well, you might be asking “What about sending to a Random recipient?” Yah — that’s not the MessageBroker’s responsibility… His responsibility is to “Accept” a message, and store it in the Database. It’s someone else’s¬†responsibility to determine the recipient.¬†/s

I hope even without the /s, you saw the sarcasm in that. But this is the reality of imposing SRP at a micro level. You’ve just shirked the responsibility of this class. He’s not anything more than a glorified secretary for the database. Worse yet, the real responsibility is now imposed somewhere it doesn’t belong.

Let’s say you require the client of your API to specify it. Well — you’ve just opened up a can of worms… Who’s to say they’ll use the same heuristic? They might have your carrier running all over Hell’s Half acre for the random recipient. Okay — force them to use a Utility class to generate the random. What you’re saying now, is that they have to¬†remember¬†to use your utility class to set the recipient. Or else… That’s not a very good design.

It makes sense, to put the responsibility, where it belongs. If calculation of a random recipient is the behaviour of how this system works. It only makes sense to put that logic into the MessageBroker.

class MessageBroker : public IMessageBroker
{
public:
    void Send(const Message &msg)
    {
        if(msg.type_ == MessageTypes.Random)
           msg.recipient_ = GenerateRandomRecipient(msg.sender_);

        // Validate the fields are appropriate for database
        ValidateFields(msg);
        // put it in the db
        Database.Store(msg);
     }

};

What’s curious about this, is that you can start to see you never needed the IMessageBroker interface in the first place. You see, the point of an interface is to be able to define a boundary of responsibility. Then have any implementation of that interface, provide that contract. Now, in our case, what’s our contract? Well, we get the Message somewhere where it can be dispatched. If it’s specified as a Random type, then we have to know to generate a random recipient, and get that to be dispatched. Would you get this out of the contract the IMessageBroker defines? I wouldn’t. So, for this design, it doesn’t make sense to have an interface. It’s a specific implementation, for a specific Message class. They’re very tightly coupled to each other. The behaviour expectation of your Message client, is very much dependent on the implementation behind that interface, implicitly. As you can see, his responsibility, really came to light once we took that step backwards, and looked at it for what it really was. (If you’re curious how I would do it differently, shoot me an e-mail!)

In summary, when you’re trying to apply the Single Responsibility Principle, it’s really important to focus your view at the right level. Take an objective look, and ask,¬†what is this thing really doing? What would be reasons for me to make edits to this class?¬†If you are honest, and you start to see that your class has many jobs. You can start to refactor some of those into their own classes, and compose that larger class of the smaller classes. Nothing says that Composition cannot occur with SRP. It just means your larger class’ job, becomes orchestration. There’s nothing wrong with that. The trap you don’t want to fall into, is shirking responsibility. You don’t want to start refactoring your code, where you’re pulling out responsibilities, and putting them on other classes. This will lead to a host of skeleton classes that are merely pass-through objects. The refactor in that case, is to look for the responsibility you’ve pushed on your clients. Ask yourself,¬†should the client need to know that? If I was using this, and didn’t write it, would I know to do this?¬†Those are the types of questions that you’ll find start to drive responsibility back into where they belong. That said, it’s a balance, and finding it is tough, it’s just a matter of practice.

I hope you enjoyed the post. As always — Happy Coding!

PL

“The price of greatness is responsibility”¬†— Winston Churchill

 

Separating your Concerns

I spent a lot of time debating what I should title this post. Should it be “Buzz Words”? Or maybe “Separation of Concerns and SRP”… SOLID Concerns? In the end, I settled on this — Separating your Concerns. I also spent a bunch of cycles, asking myself what I really wanted to cover. What ideas do I want to convey? Then I spent some time thinking about how I would convey that message. What literary road would I take? From whom’s style would I borrow. However, none of this is of concern at this moment. The fact that it’s written is all that matters now.

I want you to think about the word, Organization, and what it means to you. Just take a moment to reflect on it.

When I think about Organization, I think about form, and about order. Organization makes me think about neatness, about cleanliness, and about space. Room to breath, and room to work. Organization to me is logical, it’s order — and the opposite of that is chaos, and anarchy. In our world, spaghetti.

Hold that thought.

Now, I want you to consider what “programming” is. What exactly is it for? What is a programming “language” for? Be specific.

You might think to yourself — “programming is telling the computer what to do.” Kind of. “A programming language is the syntax we follow to do that.” Kind of.

One of the definitions of “programming”, is the act of providing a computer (or machine) with with coded instructions for the automatic performance of a task. Now, that’s the definition of programming. But anyone who has worked on any project bigger than a hobby project, with multiple developers, knows it’s so much more than that.

Programming, not only is about telling the machine what to do. It’s doing it in a way that other¬†people can understand it. It’s almost as if our programs are stories, and the compiler is the translator that turns it into instructions. The programming language, therefor is our medium of communication, between developers. Since, realistically the computer can’t understand C++ or C# directly. Consider for a moment, if we all had to “program” in CPU instructions written in binary, something a computer can understand directly. As soon as you have more than one person on the project, you’ve got a nightmare. It would be enough that the person has to communicate with the computer in that way, let alone with other developers. Trust me when I say, programming in higher level languages is for us, not them.

You might say “No. Comments are for communicating with other developers, and code is for the computers.”, to which I would reply simply “You’re wrong.” If you think that, I am sorry for you. (Actually, I’m more sorry for people who work with you.)

So programming, then is really a form of communication. It’s not completely unlike writing a story. This may seem like a bit of a Woo-Woo metaphor, but it helps to illustrate my point. Your tangled rats nest of notes you took in school, might’ve served its purpose for your studying. Though, it’s highly unlikely that it is of any value to anyone else. Not unlike programming, just because something is working when you write it, doesn’t make it of value to anyone else. Unfortunately, that mess of notes you took 3 years ago, is probably of little value now, even to you. The realistic truth, is that you then, is not you now. This is just like bad code. Trust me, I know because I’ve written so much bad code it’s mind boggling.

It’s not like this wasn’t a problem with writing. That’s why people invented literary tools, sentence structure, paragraphs. That’s why we have archetypes, and plot patterns. It’s to better communicate our stories. These things exist in programming, we have numerous languages, different patterns and practices. Hell, we even have smells. All these things try and make our code more easy to understand, for others, and for ourselves.

Let’s go back to Separating of Concerns, and how any of what I just wrote actually applies to programming. If we stick with the metaphor, that coding is a lot like writing, then what in writing is “Separation of Concerns”? Well, in your travels I’m going to assume you’ve read a book. In that book might’ve been a Table of Contents, that Table of Contents laid out the chapters of the book. The ‘Logical Separations” in the book. The book is structured in such a way, that the chapters flow. The author has taken the time to logically bundle pieces of relevant information. Can you imagine reading a book that is teaching you about Botany, and in Chapter 1 they dive directly into the root structure of a Hibiscus, and on the next page the configuration of soil nutrients? That’s not a book I want to read. So the act of bundling relevant information, for consumption of the reader, is in fact “Separation of Concerns”. Now, you can take this further. Do you think that when the author is crafting her book, that she’s worried about what type of paper it’s going to be printed on, or the font size? Probably not. Though — if she’s writing a book that contains needs special paper and tiny font,¬† likely she will ensure that the printing process will indeed support her special paper and tiny font. She certainly isn’t going to worry about this while she’s writing the book. In this regard, the author is Separating Concerns, regarding her¬†functional requirements¬†i.e. writing the book, and the¬†non-functional¬†requirements that the book needs to be on special paper in tiny font.

If we consult Wikipedia in regards to “Separation of Concerns”, we can look at the statement from Edward Dijkstra, that¬†probably¬†coined the term.

Let me try to explain to you, what to my taste is characteristic for all intelligent thinking. It is, that one is willing to study in depth an aspect of one’s subject matter in isolation for the sake of its own consistency, all the time knowing that one is occupying oneself only with one of the aspects. We know that a program must be correct and we can study it from that viewpoint only; we also know that it should be efficient and we can study its efficiency on another day, so to speak. In another mood we may ask ourselves whether, and if so: why, the program is desirable. But nothing is gained¬†‚ÄĒon the contrary!‚ÄĒ by tackling these various aspects simultaneously. It is what I sometimes have called¬†“the separation of concerns”, which, even if not perfectly possible, is yet the only available technique for effective ordering of one’s thoughts, that I know of. This is what I mean by “focusing one’s attention upon some aspect”: it does not mean ignoring the other aspects, it is just doing justice to the fact that from this aspect’s point of view, the other is irrelevant. It is being one- and multiple-track minded simultaneously.

The first time I read this quote, I don’t think I fully groked it. So I read it again. And again. And again. Then I remembered a term that a lot of developers will preach.¬†Make it work. Make it good. Make it fast.¬†Coined by Kent Beck, in the UnixWay we’ll go with sometime ago. But Dijkstra beat him to it. Kind of. The common theme here, is that these pieces are logically separated. You concern yourself with the correctness, the efficiency, and the functionality of your application each in isolation. All the while, keeping in the¬†back¬†of your mind the other concerns. It was eye opening.

Alright — enough philosophy. How does that actually affect my programming?

Well we know now, that Separation of Concerns is essentially grouping logically functions of our program. That allows us to worry about a certain function of our application, without flooding our minds with other pieces. It allows you to¬†focus.¬†I don’t care how smart you think you are, you can’t focus on more than one thing at a time. If you try when you’re programming, you’ll end up with a tangled mess. You’ll start to bring pieces that belong in other areas, into the area you are. Then you’ll take pieces from where you are, and put them in areas they don’t belong. The smartest people, have the innate ability to focus on one thing at a time, while keeping track of all the other things outside.

While authors have chapters. As programmers we have abstractions. In my opinion, the two definitions that most closely apply to programming are:

the process of considering something independently of its associations, attributes, or concrete accompaniments.

and

the quality of dealing with ideas rather than events.

The first part of an abstraction, is that it lets you consider the component devoid of its baggage. You don’t care that it references EntityFramework, Boost 1.61, or the entirety of¬† GitHub. You don’t care that it has 1.3 million member variables, and 42 private functions. The only thing you care about is that it fulfills its contract to you. That is, you care about it’s public API. You ask for a list of Foo, you better get a list of Foo. That’s why you need to keep your public API clean and concise. Because that’s your first layer of abstraction.

The second definition, and an extremely important part of an abstraction. Is that it allows you do deal with a concept, rather than its details. This lets you think at a higher level, and deal with larger concepts without drowning in all the details. The (not so) modern remote or clicker on a television, had an abstraction that allowed you to press “up”, and that would tune the frequency of the television to the channel. This allowed you to work with the idea of “up” and “down” on your remote, to tune your television. Instead of being concerned with the tuning of the radio frequency that represents the channel.

Obviously given the fact that this entire post is riddled with metaphors, you might already know I’m a sucker for metaphors. The good news is, I’m about ready to unveil the¬†pi√®ce de r√©sistance,¬†of my metaphors. It’s the one I think most clearly buttons this concept up. It’s the car. The car, isn’t just a fantastic example when we’re teaching inheritance. It’s just a great all around metaphor when it comes to programming.

Specifically the steering wheel — this is a fantastic abstraction metaphor. You get into your car, and you look at the wheel. Do you care about the mechanics behind it? No. Do you care about the linkages between the wheels and whatever makes them turn? Nope. How about the power steering pump? The electronics? Nope, and Nope. You care that this thing makes your vehicle go left and right.

Do you know why this is so important when it comes to driving? It’s because driving is complicated, you need to have quick reaction times, and be able to focus on other things, like the rules of the road. At that level, you only have the capacity to concern yourself with “left” and “right” when it comes to steering. Imagine what driving would be like, if you had to push and pull leavers and rotate gears to turn. It would be a nightmare. That wheel in the cockpit of your vehicle, allows you to focus on actually driving, instead of the details of turning the wheels. It moves that concern to a different area. Now, do the mechanics behind that wheel still matter — hell yeah! But as long as they’re functioning when you’re driving, it isn’t your concern. It’s beautiful. The second benefit of this, you can drive a bunch of different cars. You could have a beat up pinto today, and tomorrow be “rolling ‘benz”, all because you know how to use a steering wheel. Steering stays the same, and it has for many years.

Another awesome benefit of the steering wheel, debug-ability. Say you crash your pinto taking a turn. Pretty easy to figure out where the bug is. Is the bug between the seat and the wheel, or the wheel and the head lights? Let’s check, when I turn left, do the wheels turn left? Yes. Is it the correct amount? Check. Okay — problem lies between the wheel and the seat. Easy.¬† It’s also really easy to check this when the car comes off the lot, or after you’ve had it serviced. Weird — that sounds a lot like unit testing to me.

So in order to sum all of this up. Separation of Concerns affects the entire spectrum of software development, from architectural design, right down to the details of the code. It’s about organization, and only concerning yourself with one topic at a time, all the while keeping in mind those other pieces. You first concern yourself with the design of your program. Capture the like ideas, divide them into chapters. While you’re implementing your chapters, look for steering wheels. Let your chapters flow into one another, but don’t mix Chapter 1 and Chapter 13.¬† Find spots for steering wheels, don’t force them to use gears and knobs. Mostly — know that this is a process, and it’s hard. You’re likely not going to get it right the first time. It’s just about trying, keeping these concepts in the back of your mind, and looking for opportunities to apply them.

I hope that this post has brought some light to the topic of Separation of Concerns. Maybe next time I’ll try my hand on one of the other concepts of Computing that I got wrong so many times.

“Organizing is what you do, before you do something, so that when you do it, it is not all mixed up” — A.A. Milne

I hope you have a splendid day, and as always — Happy Coding!

PL

 

 

Separation of Concerns

Make it work, Make it Right, Make it Fast

What I wish I would’ve listened to – Part 1

You’ve heard it a million times, “here’s some advice I wish they would’ve told me when I was your age”. In my case, I’m very fortunate to have grown up with great parents, who shared with me a lot of their life experience and knowledge (thanks Mom & Dad). Sometimes though, I was just too stubborn to hear or see it, or maybe I just wasn’t ready.¬† Regardless, I think that much of “What I wish they would’ve told me”, is sometimes actually “What I wish I would’ve listened to, when they told me.”. We often just don’t get it at the time. Maybe we just want to do things differently, or we know better. Now, don’t get me wrong, it’s not to say I haven’t blazed my own trails, and that I haven’t walked on paths not yet traveled by my mentors. But it’s to recognize, that we often times miss some of the things our elders want us to know. This isn’t to say that the world would be a better place, if we just followed everything our parents, grandparents, teachers, or bosses told us to do. We would then just be a society of automaton, that can’t think for ourselves. Regardless of whether we wanted to hear it, or they never told us, this miscommunication becomes things “I wish they would’ve told me that when I was younger”.

So, now it’s my turn — my reflection on my career sparked an urge to share some of the life lessons I’ve learned in my short time on this rock, and my even shorter time as a Software Developer. The things I wish I would’ve paid a bit more attention to. Those things that I’ve had to learn the hard way. That advice I wish I would’ve heeded. I’m going to try and make it as accessible as possible, but there’s a high likelihood, it will become information lost in the folly of our future generations. Just as lost wisdom of our elders past.

Television will rot your brains… You should read more.

These days with all the streaming services, access to everything our friends and idols do every moment in their lives at the tip of our fingers. Who even has time for reading? Who even wants to read? From as early back as I can remember, I despised reading. My grandmother, and my mother, did their best to try and get me to read as a youngster. Reading to me, giving me access to any books that I desired. I desired a lot of books, I liked the way they looked on my shelf. All with perfect spines. It was obvious that reading was for people who couldn’t watch movies. Why would anyone want to stare at a bunch of text on paper, when they could stare into the wonder that was film?

By the time I was in high-school, I could probably count the number of books I’d actually completed on one hand.¬† For most of my elementary and junior high days, the internet wasn’t much of a thing just yet. So you couldn’t just find the synopsis online. I had to work to do less. I did things like read the first and last paragraph in each chapter. Read the back of the book. One memory that sticks out, was from grade 11. We had to write a book report on The Life of Pi. Obviously, I loathed book reports, because not only did I have to read — I had to write. So instead of actually reading the book, I read¬†part¬†of the book, and relied on chatting with my classmates to “absorb” the rest of the book. I did a pretty good job of gathering the information. I got the scoop on what happened in the book from a friend, we’ll call him Chris, because that was his name. Chris filled me in on the plot. A boy and his family, and their zoo get on a boat to move to Canada, and sell the zoo. On the journey, the freighter sinks leaving Pi and some other zoo animals, Tom Hank’s style castaway’d on a life raft, one being an adult Bengal tiger. They have some trials and tribulations, some of the animals die. Pi and the tiger eventually get rescued. End of story. If you’ve read the book, or seen the movie… Spoiler alert. There’s this whole part about Pi telling an alternate story which involves humans, as the zoo animals. To which you’re left a choice of which story to believe. Apparently, my English teacher thought this was of some of “literary importance”. Thanks a lot, Chris… Needless to say, the grade on that report wasn’t on the fridge.

You’d think this would be enough to push me to the books. Nope. I was able to skate by on minimal effort through high-school, into and through university. In university, the internet was in full force, so I didn’t have anymore “Chris” episodes. However, after university in my early 20’s, I hit my breaking point. I had just finished a climb with a friend from school, we were all going to go out for beers. It was with friends of a friend, she was an engineer, so I figured I was safe. Arts degrees…. amirite? So we go out for beers, and somehow we get on the topic of reading and “literature”. I still get chills down my spine when people pronounce it lit-er-at-ture. The round table ended up on me, and my reply was that I didn’t read. To which, one fellow commented “you can’t read?” I stumbled and tried to recover, “No. No. I can read. I have a university degree… I just don’t read for fun.” “Sure.” He smirked. That rocked me. After that, I would be a “reader”.

It’s been about 10 years since that guy made a fool of me. I wouldn’t consider myself a book worm by any means. But I read everyday. I didn’t start that right away. It just came organically, I just started reading programming books. That evolved into other non-fiction, self help, biography, history, philosophy, etc… I’m not a huge fiction fan though. The thing that I failed to realize, as a kid, youth, teen, and young adult is just¬†why reading is so important. I’m sure someone, at some point in my life told me. I wasn’t ready for it, because it didn’t affect me at the time. I didn’t need reading to get by at the time, and getting by was what I was focused on. I suspect, if you’ve read this far, “getting by” isn’t what you’re interested in.

People have probably spouted the traditional benefits of reading. Things like mental stimulation, relaxation, and increase of knowledge. In order to set myself apart, I won’t use those traditional examples. Hopefully my examples will be more application and less theory. Maybe, they’ll apply more to a modern age.¬† In a modern corporate world, why is reading so important? You’ve heard the saying “Cash is King”. How about “Communication is King”. The way you communicate with your colleagues, mentors, and supervisors determines largely how you progress through your career. You could be the most brilliant entrepreneur, but if you can’t communicate your brilliance, to an outsider you look like a buffoon. In my opinion, strong communication skills are the key to success. You want a successful fulfilling career? You’ve got to be able to foster healthy corporate relationships, you do this by communicating your thoughts and ideas. You hope you get a mentor or supervisor with good communication skills as well. So she can communicate to you, your weaknesses and how you can improve.

Communication, is successfully conveying information to an audience. The key point of that is “successfully”. The thing is, that humans are social beings. We’re made to communicate. A group of like-minded individuals have an easier time communicating, and thus successfully exchanging ideas. If you put the “cache-me-ouside-how-bo-dah” girl (Bhad Bhabbie), in a room of her friends. They’d all understand her. Put her in a room of executives, and you’d have a lot of men in suits scratching their heads. Did someone say cash? In order to be good at communication, you’ve got to be able to communicate outside your immediate circle, or those like minded individuals. As always, you might be wondering why I’m explaining this, and what the hell it has to do with reading. Well — writing is a form of communication, and like it or not, with IM, SMS, and all the various forms of messaging applications. Writing is becoming a very important form of communication in the workplace. So when you read a variety of books, you learn a variety of communication styles, with a variety of communication styles. When you have an arsenal of communication styles, you’ll be more suited to customize your communication style to the audience at hand. This will allow you to have a higher percentage of your thoughts and ideas understood by others.

The second important part, is that reading provides you with better “mental models”. If you read non-fiction, you’ll amass knowledge of history, current facts, etc. If you read fiction, you’ll learn about archetypal story telling.¬† You can use this knowledge to help you frame the massive amounts of stimulus (data) you receive every day. Being able to frame, sort, and organize the data you receive allows you to make better informed decisions. Which in turn leads to better and more successful outcomes.

In summary, if you’re having trouble getting your messages received by others in your world. You should read more, that television will rot your brains.

‚ÄúThe more that you read, the more things you will know. The more that you learn, the more places you‚Äôll go.‚ÄĚ ‚Äď Dr. Seuss

On Leading Yourself

Forgive me, for it has been two months since my last post.

Sometimes life just ends up getting in the way of the things you have desires to do. Your passions and goals get moved to the back burner, as you deal with the daily chaos that is life.  It takes a concerted effort to be able to maintain balance where one is able to dedicate consistent time to their hobbies, interests, and self growth.

In the past couple months, I’ve had a bit of what one could call a career “do-si-do”. It was good and gave some great insight, and different perspectives on careers, life, and balance. It also allowed me to solidify some of the things I had questions about, or the unknowns I wasn’t sure about. I was able to meet a tonne of new people, and gain a whole bunch of different insights into other people’s point of view. When reflecting on everything that transpired in the last 6 months, I couldn’t help but look back on my career. Now, I haven’t had the longest career, I’ve only been a software professional for about 8 years. However, I think my journey has been quite fruitful, and has allowed me to learn a lot about the industry, and learn a lot about myself. Interestingly enough, in my 8 years, I’ve spent more than five, as a “lead”. For me — this felt normal. Isn’t this how every software developers career progresses?

Spoiler alert — it’s not. To me though, it never seemed like I did anything out of ordinary to move myself towards being a technical lead, or even into a team lead position. In fact, when I graduated and started my career, my goal was just to be the best developer. Management? Eff that. I wanted to be the best developer, ever. Not the best developer I could be, not to be the best developer at the company. I wanted to be the best developer — EVER. Lofty goal right? SMART Goal? Wrong, I’ll be the first to say it was a stupid goal. Though it was rooted in good intention, for the most part, I won’t lie and say I wasn’t enticed by the money, women and fame I would get. The reason I wanted it so badly, was that I had never really been the best at anything. Growing up I was exactly average, if you placed me on a bell curve I would be right smack dab in the center of the bell. This being average my whole life lead me to want one thing. I want to be the best at something. I didn’t know what, but I wanted it, bad.

When I got to university, I selected my primary study as business. What 17 year old high-school male doesn’t want to graduate with a business degree, become an investment banker, and then be Batman? I have parents so that tells you something about me becoming Batman. I found out that a degree in business required a lot of reading, something that I wanted no part of. Faced with a daunting path ahead, which consisted of a plethora of reading and likely writing. I did what any 18 year old, pre-business student who hates reading and writing would do. I looked for the easiest out possible. The obvious choice here, was a computing science degree. I had taken Computing Science 101, and received an A (woo not average). So I selected the obvious easiest path forward. Computers were always a thing I was good at, I just hated the thought of being a nerd. Here I was faced with the choice to be a nerd, or suffer having to read books. shudder Flash forward a few years, what was not as easy a path as initially thought, and I graduated. You guessed it, I had an average GPA. To my surprise though, I graduated with a job.

It wasn’t long into my career when I realized that in order to be good at something, I mean above average good, you have to put a substantial amount of effort in. Those people, who are the best at something, anything. Pick something running, swimming, math, music, or writing, you name it. I can tell you one thing about that person, they worked their ass off to get to where they are. It was a cold realization that day, if I wanted to be the best at something, I had to work harder than everyone around me. All the years I spent trying new hobbies, searching for that one thing I would be the best at. I finally realized I would never find it. Because it was right there in front of me. It was a matter of picking something and dedicating myself to it. That meant, to achieve my goal of being the best developer¬†ever. I would need to practice, a lot.

You’re probably thinking at this point, that I’m just telling you my life story. That I’m not actually giving any relevant information on how to actually become a technical lead. Maybe you’re right. Let’s just consider though, if you’re young and you’re looking to be a lead developer, or a team lead, you’re probably not looking to ride the conveyor of time. Sure, that’s one approach to becoming a lead, you wait it out. Eventually, you’ll add enough years of seniority, and enough people in front of you will age out that you’ll get promoted. That is if they don’t hire someone external ahead of you. If you’re fine with that, you can stop reading. If you’re looking to get off the conveyor, you have to be the best, or at least better than the guy in front of you. And that takes work, significant work. You might say “people who are technically strong don’t make the best people leaders”, and you would be right, sometimes. To be a technical lead though, you have to be technically strong. To get strong, you have to train.

So, let’s address that elephant of strong technical leaders not being good people leaders. If we look at why often people who are strong technically, struggle with the interpersonal side. Ask the question, what does it take to be strong technically? Well, with computers especially, you have to be really good at telling them what to do. You have to be very explicit in your instructions. If you’re not, the computer, doing exactly what you told it, will behave different from your expectation. The response is easy. Inspect the source, tell it what you really meant, and have it try again. Machines aren’t like people. After you re-tell what to do, it will execute your instructions with the utmost care and accuracy as before. To be technically strong, you only have to know in depth how and why the computer behaves the way it does. In short, you have to think like a computer. Unfortunately, humans don’t act like computers. So in order to lead people, you have to think, you guessed it — like a human. Which is a hard dichotomy to master. Hence the difficulty between being a technical leader and a people leader.

When I became a Team Lead, I will fully admit, that I wasn’t ready. The guys who had to work with me, would say the same thing. So what did I do that made me stand out? I can’t say for sure, but I think it had something to do with the way I lead myself. Recently I was listing to a Jocko Podcast 170, about 25 minutes in he gives advice to a person who interviewed for a team lead position and didn’t get it, because they didn’t have experience. His quotes is something along the lines of “You’re in charge of something.” He uses examples like machinery or a process. Something. If you can’t think of anything you’re in charge of, think of this. You’re in charge of yourself. The reality is, that if a company can’t see that you’ve got it figured out enough to be in charge of yourself. How can you expect them to feel comfortable letting you be in charge of others? In my case, I didn’t know how to listen to people. I thought being a Team Lead meant barking orders, and expecting perfect results. I didn’t know what I was doing. The silver lining, was I knew how to realistically evaluate the situation, and learn from it. This let me move forward. Moving forward is key. No one is perfect, and no one is the perfect team lead, especially in the technical industry. There’s too much variability, and when people are involved nothing¬†can¬†be perfect. What I have, is a burning desire to do better. I never want to end a day, and be worse at something than I was the day before. There may be setbacks, there may be plateaus, but overall I want an upward direction. So maybe I wasn’t the best at listening, my thought was how can I get better at listening? Maybe I’m not good at communicating. How can I get better at communication? It’s always been about the next step. Taking the next step, and the next step, is how you break away from the pack and lead. This also keeps you humble, because you can realistically see your faults. You have to see them to get better. If you can see your own faults, it will help you lead. A realization that everyone has faults, lets you pick not only yourself up, but others around you as well.

Realistically, if you want to be any sort of lead, in any sort of industry. You have to start by leading yourself. Making the decisions that will ensure that you don’t stagnate. Just because you work 8 hours per day, doesn’t mean you’re getting better. It takes a focused effort, it takes practice, and it takes willpower. You also need the realization that nothing in life is a guarantee. Leading yourself, means taking these steps, not with a short sighted goal, but a long term goal of being better. It means putting in the effort day in, and day out to ensure,¬†you’re¬†better for it. Naturally people will see this, and want to follow it. Eventually, you will be able to switch your focus from supporting and teaching yourself, to supporting and teaching others. That right there, is a whole different story.

“Example is not the main thing in influencing others, it is the only thing.” Albert Schweitzer

[ASPeKT] Oriented Programming

I recently had the pleasure of doing a podcast, with Matthew D. Groves, of¬†Cross Cutting Concerns¬†blog. He essentially “wrote the book”, so to speak, on Aspect Oriented Programming. It’s called¬†AOP in .NET,¬†without pumping his tires too much, I will say that his book is pretty great. I just recently finished reading it, and came to the conclusion that Matthew and I are on the same page regarding a lot of Software Development Fundamentals. Specifically, his take on AOP (Aspect Oriented Programming) and the benefits of it. The ability with AOP to factor out common code that crosses all areas of your code base, and encapsulate it so that you have a single point of change, is a very powerful concept. He illustrates concepts like these, and many others in his book. It also gives a nice overview into the different tools available in the AOP world. Even after writing my own AOP library, I was still able to learn a lot from this book. If you’re interested in AOP or Software Development in general, you should definitely check it out.

To follow up with Matthew’s Podcast, featuring me and the library I created called [ASPeKT] (no relation to ASP, I just liked the way it looked). I wanted to write a post that overviews AOP, and some of the benefits of this powerful programming paradigm. I want to talk about [ASPeKT], the benefits and costs of using a simple AOP library. Then detail some of the challenges I faced as I wrote it, as I work to make it more known, and as I continue to make it better.

Why Aspect Oriented Programming?

AOP is a little known, yet very widely used programming paradigm. How can it be little known, yet very widely used, you ask? Mostly because it’s built into a lot of .NET libraries and frameworks that people use every day, but they just don’t know they’re actually using AOP concepts. Interestingly enough, .NET ASP MVC Authentication, uses AOP patterns. Most people just go about programming and using the Authenticate attribute, without knowing they’re actually hoisting a cross-cutting concern up with a more declarative (cleaner) approach, and letting the framework deal with it.¬† For me, as a skeptic of AOP at the beginning, it was a¬†huge eye opener to realize that these concepts are actually applied all over in the .NET world. We just don’t realize it. This also brings to light, the power of being able to spot cross-cutting concerns, and be able to encapsulate them, using a library like [ASPeKT]. Thus, removing the need for clunky boilerplate code, and copy-pasta patterns that live in documentation, or worse yet only the minds of your more senior developers.

What is Aspect Oriented Programming, really?

In order to really understand what AOP is, we have to first understand what a “cross-cutting concern” (CCC) is. A CCC is, is the fundamental problem AOP looks to solve. These CCCs typically tend to be the non-functional requirements of your application. They’re code, that spreads¬†across¬†your code base, but they’re not easily factored into their own units. The canonical CCC is logging or auditing. Your application can function, business wise, without it. Yet, if you were to implement the need for “logging” across your application, you would end up with logging code, that pollutes your actual business logic. Things like logging the entry and exit of functions. You end up with code like this.

class Foo 
{
    public void Bar() 
    {
        Console.WriteLine("Entered Bar");
        Console.WriteLine("Pour a drink.");
        Console.WriteLine("Exiting Bar");
    }
};

You can see how this can get tedious, you end up having ‘rules’ or ‘patterns’ that define how and what you log. “This is how we log entry into a function, with it’s parameters. ‘Entering Function – Function. The format lives in a document, stored in SharePoint.” Now imagine when one day that needs to change, and you’re forced to update the 43 million different log lines across your application. Welcome to Hell. Talk about why they call these things ‘concerns’.

Logging isn’t the only concern that spreads and tangles across your code. Things like Authorization, what I call function ‘contracts’ or defensive programming, threading, and many other patterns. These patterns are often overlooked as cross-cutting and don’t always speak to boilerplate, but with a keen eye and some creativity can be teased out into their own re-usable aspects.

Using an AOP tool, allows you to hoist this boilerplate code into its own encapsulated class, where it belongs. Then it allows you to place it declaratively, which makes the code read more explicitly. But also, removes the clutter from the actual business logic of the function. These tools make it so you don’t have to weed through the logging, defensive programming, authorization, etc. Just to find out what the actual intention of the function is. You’ll end up writing code more akin to this.

class LoggedAttribute : Aspect 
{
    public override void OnEntry(MethodArgs args)
    {
        Console.WriteLine($"Entering {args.MethodName}");
    }
    public override void OnExit(MethodArgs args)
    {
        Console.WriteLine($"Exiting {args.MethodName}");
    }
};

class Foo
{
     [Logged]
     public void Bar()
     {
          Console.WriteLine("Pour a drink.");
     }
};

This code effectively functions the same as above. However,¬† it is substantially cleaner, and the biggest benefit is the ease of change. Now, if I’ve used the LoggedAttribute across my code base and I want to make a change. I only need to make the change in one spot, as opposed to everywhere we copied and pasted the logging lines. AOP allows you to offload the tedious boilerplate code, on the machine. Who is much, much, much faster at typing than humans. The machine also, never makes a typo.

Now that you know what a cross-cutting concern is, I can explain AOP. Effectively AOP is a tool, set of tools, or a paradigm to deal with cross-cutting concerns. In order to prescribe to an AOP model, you need the following 3 things.

  1. A Join Point Рthis is the point at which our AOP model allows us to interject code. In the case of [ASPeKT], the join-points are method boundaries. i.e. Entering / Exiting of a function. Other libraries like Castle DynamicProxy, and PostSharp allow for actual method interception, so you can say the join-point is this instead of that. This can be useful for things like error handling, retry logic, or threading models.
  2. A Point Cut – this is the way in which you specify, where you want to apply code to the Join Points. Think of this as a sentence describing where you want the code to run. I know my Join Point is Entry/Exit of function. My Point Cut could be “every function that starts with My”, or simply, “every function in the application”. [ASPeKT] uses attribute placement as the Point Cut definition. So where you place the attribute, determines how it will apply the code to the Join Points.
  3. Advice – essentially, the code you want to run at the Join Points. So for [ASPeKT], this is the code you write in OnEntry / OnExit / OnException.

Given these three things, you can start to encapsulate the CCC, which then allows you to start¬†applying¬†that code to other code. You don’t need to copy-pasta, you don’t need to find the document that says how to do logging or auditing. You just¬†apply¬†logging, you¬†apply¬†auditing. It becomes very powerful, because these concerns are now tools in your development toolkit. They’re easily tweaked, they’re modifiable without the daunting overhead of find and replace in every file in the solution. Now, they make sense.

So hopefully now you see the benefit of AOP, and can maybe start to see places where AOP could benefit your projects or workplace. I’ll be honest, it’s not always the easiest sell. So if you’re interested and you want more information, please feel free to reach out. I love talking about these kinds of things.

[ASPeKT] In a Nutshell

My first real intriguing look at AOP, was as I was reading the book Adaptive Code via C# — Gary Maclean Hall. He gave a brief introduction into AOP, mostly to describe its use with logging. Which at the time, I laughed and thought, ‘there’s really no other use than logging’. Later on in the book, he describes a pattern to reduce dependencies on lower layer APIs, by translating API level exceptions into higher level exceptions. This is so higher level components can make decisions based on the exceptions, without being explicitly tied to the lower level library. Consider the use of a library that is encapsulating sending data to a webserver for storage. Something like Office 365 Drive.

You might have code like this.

// MyStorage.dll - our internal wrappers, depends on OfficeWebDrive.dll
interface IStorage 
{
      public void Store(string name, Stream stream);
}


class OfficeDrive : IStorage
{
    public void Store(string name, Stream stream)
    {
         // use OfficeWebDrive.dll third party library
         // make requests to store data,
         // can throw "OfficeWebDrive.StorageFullException"
    }
};
// Application.exe - depends on MyStorage.dll, 
// but should have no dependency on OfficeWebDrive.dll

class Book 
{
    public void AddText(string text)
    {
        // Code to append text.
    }

    public void Save() 
    {
        storage_.Store(Title, Data);
    }
   
    Stream Data { get; }
    string Title { get; }
};

class Application 
{
    public void SomethingHere()
    {
         try
         {
             Book book = new Book("AOP in .NET");
             book.AddText("Lorem Ipsum");
             book.Save();
         }
         catch(OfficeWebDrive.StorageFullException e)
         {
               // Deal with the StorageFullException
         }
    }
};

As you can see, we’ve done our best to program to an interface, using the IStorage interface. Our application should have no dependencies on the actual underlying storage libraries. Except that because we need to deal with the StorageFullException, we need to now explicitly make a dependency between our application and the lower level third party API.

The sentiment then, from Adaptive code, is to wrap the 3rd party library calls, and translate the exception. Like so.

class OfficeDrive : IStorage
{
    public void Store(string name, Stream stream)
    {
        try 
        {
            // use OfficeWebDrive.dll third party library
            // make requests to store data,
            // can throw "OfficeWebDrive.StorageFullException"
        }
        catch(OfficeWebDrive.StorageFullException e)
        {
             // translate the error
             throw new MyStorage.StorageFullException(e.Message);
        }
    }
};

Now, the higher level code can make the same decisions about what to do when the storage is full, but no dependencies on the low level libraries. If we wanted, we could completely change the underlying storage mechanism. Without needing the Application to rebuild.

‘Hey Gary, this is a great spot for AOP’ I thought being clever.

class OfficeDrive : IStorage
{
    [TranslateException(typeof(OfficeWebDrive.StorageFullException), 
     typeof(MyStorage.StorageFullException))]
    public void Store(string name, Stream stream)
    {
        // use OfficeWebDrive.dll third party library
        // make requests to store data,
        // can throw "OfficeWebDrive.StorageFullException"
    }
};

Now, we let the AOP framework handle the boilerplate try/catch code. This also really calls out what is happening, and why.

Where does [ASPeKT] come in?

Well — after I thought about this, I wanted to build it. I guess I could’ve easily used the PostSharp Express version and whipped it out really quickly. But that’s not me. If I’m going to understand something, I’m going to¬†understand¬†it. So I set off to write a small AOP library, where I could solve this problem. It was a rather simple concept, or so I thought.

I didn’t even really know what an AOP library did. That’s where the research started, “open source AOP libraries”, “how does PostSharp work”, etc, etc. Just some of the multitude of search terms I used while I did research into how to build an AOP library.

I had the concept of what I wanted. I wanted something that I could declare an attribute, that would translate an exception. Easy.

Let’s go down the rabbit hole.

At it’s core, AOP is actually allowing a machine to write code for you. You’ve moved the copy and paste from your fingers Ctrl+C / Ctrl-V to the machines apt fingers. Allowing the computer to ‘weave’ the code for you.¬† You define the boilerplate as an aspect, and you let the machine do the work for you, because that’s what they’re good at (no offense computer).

You’ve got three options for when this can happen.

  1. In the source code, before you compile. Using some type of marked up code in your source, you could run a pre-compiler that will insert code snippets into the source. Before the compiler does it’s work.
  2. After the compiler — though not impossible on native assemblies. It is far easier on languages like C# and Java, which use an intermediate language, between source code and assembly. We can post-process the compiled intermediate language (IL), to apply the code we want.
  3. At runtime. Well this has somewhat of an over-watch pattern, where something is watching the calls as they run through and interpreting whether or not to run our aspects.

Now — knowing this, which one do you choose? My thought process was as follows.

  1. Option 1: Modify the source — I don’t want to write a compiler. Well, I do, but not for this. So that was off the table, at least for now. You also have dependency on language syntax, not that I would expect much of C# syntax to change, but still.
  2. Option 3: At runtime – I don’t want this. I come from a native background, specifically C++. I don’t want to pay overhead where I don’t have to. I didn’t want to have something that is monitoring functions as they run, or building code at runtime. Just wasn’t what I wanted.

So that left option 2, what exactly is that? How does it even work?  I need something that will run, after the binary compiles, and modify it to add in the CCC code.

Let’s go deeper…

To understand post compile weaving, we must first understand how the .NET runtime operates, at a high level. The .NET Runtime is what’s called a “virtual machine”. The draw towards these “virtual machines”, was started with JAVA created by Sun Microsystems. The large benefit to JAVA, was that it was a compile once, run anywhere language. This was hugely powerful, when you consider the alternative of compiling for every architecture, as is the case with C and C++.¬† The virtual machine, allows you to compile to a well known set of instructions (IL), which then will output machine specific instructions for the hardware when run through the virtual machine. This way, you only need to write a virtual machine for the hardware, and you open yourself up to all the applications available for that runtime. This is one of the reasons JAVA became so hugely popular, because you could write a JVM for your VCR and all of a sudden pow¬†smart VCR, with lots of apps available.

Obviously, Microsoft saw the benefit and flexibility in this and took advantage, so they started shipping JAVA in Visual Studio. They had their own JVM, and JAVA compiler as well. They also saw an advantage to extend this language, for the Windows operating system. Enter J++, Microsoft’s implementation of Java with extensions for the Windows OS. With J++, came a lawsuit from Sun Microsystems. Microsoft had a non-compliant JVM and they were violating the terms of the license agreement (who reads those things anyways?). Wah. Wah. So what does Microsoft do? They do what any billion dollar software development company would do. They eat the lawsuit, and take J++ and turn into what we now know as C#.¬† They also see the immense power in this .NET Runtime, and see that they can compile a whole multitude of different languages into IL. With the release of .NET Runtime 1.0, there was support for 26 languages (I think). To be completely honest, I’m glad that Sun sued Microsoft, because I hate JAVA as a language, and I love C#. So it was a win, in my opinion.

Anyways — aside from that little lesson in history, we can understand how ‘weaving’ works in a .NET language. Like I said, C# is a language that compiles to IL, aka CIL or MSIL. An intermediate language, is on the fence. Between a language that is “compiled” to actual assembly (hardware instructions). And an interpreted language like JS, that is completely interpreted at runtime. The C# compiler, takes the C# language and outputs a binary form of instructions that complies to the .NET runtime standard. These instructions are then interpreted, and compiled Just-In-Time to output hardware instructions. This means, that after we compile to IL, and before running, we can insert some extra IL instructions, then voila.

How do you weave IL?

Weaving IL is actually pretty straight forward, if you know what you’re doing. Which I didn’t. Ha. At first, I kind of flew by the seat of my pants. I knew I needed to re-write the IL, and I had heard about tools like Roslyn and Mono.Cecil. Roslyn being a compiler, wasn’t exactly what I wanted. I needed at tool to modify the IL, which is exactly what Mono.Cecil is. It not only uses the built in Reflection.Emit, but also adds a lot of ease to manipulating the IL.

The task at hand for me, was to open the binary, find the spot that I had declared my “TranslateExcepton” and then insert the instructions for that, into the method where I declared.¬† I just decided to make it generic, to work with any Aspects I created. I will spare the gory details, but the high-level was as follows.

  1. Open the compiled .NET assembly
  2. Find functions decorated with Aspekt.Aspects
  3. Write IL to instantiate the Aspect, and make the entry call
  4. Write IL to wrap the existing code in a try/catch
  5. Execute the existing code
  6. Write IL to make the exit call

I could write an entire post on weaving IL, but not today. If you’re interested in that, please drop me a line and let me know. I can describe, in detail, all the pain I felt while I was learning how to do this.

Once, I had figured out how to do this. I had an executable that I could run against my compiled .NET binaries, which would weave aspect code, where I place attributes. Then all I needed to do was write the aspect, to translate the exception. You can actually find this aspect in the [ASPeKT] code. Kind of like an ode to the beginning, for me.

What came next?

Now that I had the start of this framework. I thought to myself, that I had actually built something that could be useful. “People might actually want to use this”. I had also always wanted to author an open source library. So I started reaching out on Reddit, and making the foundation more easily accessible for people to use. I made the core more stable. Then I started writing new features, like [ASPeKT] Contracts. It was a surprising journey. In the past I had written many throw away libraries, and many small tools that have never seen the light of day. Always just to prove to myself, well, that I could. There was just something to this one, it was a niche library and I thought there was something to it.

I guess the reality is that I’m still in the middle of this journey, with [ASPeKT] core having 588 downloads, and Contracts having slightly less at 416. I’m still working towards my goal of 1000 downloads for each. Realistically, a project that uses [ASPeKT]¬†could be the spark that it needs to ignite. Until then though, I will just keep plugging away and making it cooler and easier to use.

Why should you use [ASPeKT]?

Well — if you’re at all curious in the inner workings of an AOP library, the code is public on my¬†GitHub¬†or you can easily get the package on NuGet. The second, is maybe you have a project that could benefit from AOP?¬†[ASPeKT] is pretty lightweight, and easy to get started with. Though, if you’re looking for a robust, feature complete, production ready library — [ASPeKT] isn’t there yet. If you’re looking for a library to contribute to, or a library that can be adapted into something production ready, then shoot me an email!

‚ÄúMan cannot discover new oceans unless he has the courage to lose sight of the shore.‚ÄĚ
‚Äē¬†Andre Gide

As always, thanks for reading. Happy Coding!

PL