New invention: the wheel
Why did we create this service, when there is a great, free alternative out there?
Posted by Ragnar on Feb 20, 2022

Supershields.io has launched!

Wohoo! Or is it Wohoo? That's what this article looks to explore.

The legacy

As some may already know, there is a free service / tool called shields.io that is pretty nifty. It creates very nice-looking SVG badges/icons you can use in the README.md for your Github repo, or on your website.

Here is an example shields.io badge:

So shields.io will talk to the Github API and ask it stuff about your repo, then create an SVG badge that shows the information and which you can put on display somewhere. It also supports many services and tools besides Github. And you can host it yourself or use it as a SaaS that is completely free. In short, it's a very nice tool/service!

The new era

However, as is often the case, there will be people who are just not satisfied with existing solutions, no matter how nice they are.

We are those people. While great, shields.io was not enough for us, because we're always striving for more. We're the kind of people who like to break new ground. Trailblazers, if you want. Disruptors of the status quo. Within us flows a raging river of creativity that makes us get up every morning and build things never before imagined!

So, we built something else! Let us show you what it is. Without further ado, here is another example of a shields.io badge:

And below you can see our much-improved version of the same badge

Yeah. Take that shields.io!

Some vague similarities

OK - to be perfectly honest they look a bit similar. I'll admit that. The main difference seems to be that the dimensions of the badges are different by a tiny amount. If you get really serious and use a magnifying glass (or maybe just set width,height="a lot"), you may note that our badge also has a slightly narrower font, slightly worse positioning of the content, and a slightly different background shade. Actually, the shields.io badge looks better, if you ask me.

But if they're almost identical, why did we bother to create something new?

Well, first of all "we" is not technically correct unless you include my cat into the definition, and I'm not sure how much of a contribution he made, the slacker.

Secondly, there is really no single, good reason to build a new shields.io. Just a lot of tiny, not-so-great reasons that somewhow overwhelmed me through sheer numbers and made me do it. Or maybe it was just a whim. Probably just a whim.

To be honest, the first version of Supershields was a fairly lame attempt at creating something very similar to shields.io, with perhaps the biggest differentiator being that I had written the code. In the end though, after a few pre-launch pivots and rewrites (a.k.a 600 commits later), this thing has turned into something that is actually different from shields.io. So if you can stand my writing style at all, please read on.

This article is an attempt to explain what it is that I have built, and who should use it.

The original concept

The first idea I had was to create a Github app that could download all the code in a Github repo and run lots of tests and analyses on it, producing results in the form of badges/icons users could put on their websites. By creating a Github app I'd have access to all the code in a repo where the app was installed, and I'd be able to find out lots of interesting things to create badges from. I didn't see shields.io doing this, so I thought I'd be able to produce a lot more in-depth data to create badges from.

But then I thought: "Hey, what kind of interesting things, and will this analysis functionality be simple to implement?"

The answer to those questions were "Uhmm, not sure" and "Probably not", respectively, which gave me a bit of a reality check. Reality checks are always tough on motivation, which is why I've spent years building up a resistance to reality. This came in handy now, as it allowed me to just forge ahead without regard for the viability of my application.

The Github app

I quickly got a basic Github app up and running but still had no idea what my envisioned code-analysis functionality would actually be. In order to have something to test, I decided to start by replicating some of the shields.io badges.

It was really simple to get the app to ask the Github API for metadata on a repo and produce e.g. the current number of Github stars that repo had.

Then as soon as I had some data I wanted to show, I got interested in how to create a good-looking SVG badge to display the data. This is when I fell into a new and unexpected rabbit hole:

SVG is a cool file format!

So I'm a bit slow. SVG has been around a while but I only just recently realized it's text-based XML, similar to HTML and very easy to read and write as you would HTML.

SVG data

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink=
"http://www.w3.org/1999/xlink" viewBox="0 0 100 100">
   <rect width="100" height="100" fill="green"/>
</svg>
                            
Image

A more advanced example

SVG data


<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink=
"http://www.w3.org/1999/xlink" viewBox="0 0 100 100">
   <g stroke="black" stroke-width="2" fill="black">
      <circle cx="50" cy="50" r="48" fill="yellow"/>
      <ellipse rx="5" ry="14" cx="37" cy="30" r="7"/>
      <ellipse rx="5" ry="14" cx="63" cy="30" r="7"/>
      <path d="M15,50A35,35,0,0,0,85,50" fill="none"/>
   </g>
</svg>
                            

Image

I started by looking at the code for the shields.io badges, and saw that it was actually very simple to write by hand. I took their SVG code, reworked it a little and then had my Go backend generate similar badges on the fly.

Here I was, happily rewriting shields.io from scratch in Go (the original is a Node.js application), when I thought "Hey, SVG looks very much like HTML. I wonder if that means you can use <script> tags also?"

Turns out you can! So you can embed Javascript into the SVG, and that opens up an almost endless range of opportunities to create fun code that may be both insecure and annoying to end users!

Adding some JS code

SVG data


<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink=
"http://www.w3.org/1999/xlink" viewBox="0 0 100 100">
   <g stroke="black" stroke-width="2" fill="black">
      <circle cx="50" cy="50" r="48" fill="yellow"/>
      <ellipse rx="5" ry="14" cx="37" cy="30" r="7"/>
      <ellipse rx="5" ry="14" cx="63" cy="30" r="7"/>
      <path id="the-smile" d="M15,50A35,0,0,0,0,85,50" fill="none"/>
   </g>
   <script>
      var animPos = 0;
      function smile() {
         document.getElementById('the-smile').setAttribute('d', 'M15,50A35,' +
            Math.abs(35 * (animPos/25)) + ',0,0,0,85,50');
         if (++animPos == 25) animPos = -25;
         setTimeout(smile, 50);
      }
      smile();
   </script>
</svg>
                            

Image

Animated SVGs? No problem (there is also an <animate> tag you can use to animate things inside your SVG). Animated with logic (e.g. different behaviour depending on the data they're showing) also no problem. Hey, badges could even update their own data using AJAX requests!

After the initial endorphins wore off, however, I came to my senses and realized that tacky animations would probably just put off an audience of mainly developers. Developers absolutely hate animations unless they're made by Pixar.

But automatic updating of the badge data, that was somewhat interesting. If I could make my badges smarter than the decidedly non-smart shields.io badges I'd have something that was actually a little better, in one way at least.

So that became a design goal - to make all the badges I created include functionality to update themselves, without the need to reload the page where the badges are displayed.

OK, sorry about the SVG orgy above. I just had to write about SVGs. I've always had a love of file formats and this one is just so...liberating. Being able to create simple, scalable graphics - e.g. logotypes like the supershields logo here on the right - by just typing in some code in an editor is a ton of fun.

Supershields SVG logo

More novelties

It's not just about smart SVGs

So one thing I realized was that I could make my badges smart, and smart badges that update their own contents would be something new.

Also, it turned out that being a Github app had its advantages. The onboarding flow became easier - just click to install and then browse what badges you want to create, as opposed to using shields.io where you have to read several paragraphs of text first, to figure out how to write the URLs for the badges you want shields.io to generate for you.

The supershields.io user flow became:

  1. Install the Github app and decide which repositories it should have access to

You then get redirected to your account on https://supershields.io:

  1. Create badges there

The USP

But I also realized there was a third advantage. Business literature talks about USPs - Unique Selling Points - but I have found that Unexpected Selling Point is a more fitting description for what usually makes one of my projects viable. Luckily, this project turned out to have one:

Private repo support!

Because supershields.io is hosted, it acts as an intermediary for all data requests. Or MitM attack vector, depending on your point of view (and how well I've implemented security measures).

But the point is that as the supershields Github app gets access to your repo, it can relay private repo data, via supershields.io, to happy end users frolicking on a web page somewhere. With shields.io you have to self-host the whole solution (and maybe modify it slightly) to get it to do the same.

https://supershields.io/55a6503ad8f44bb2ceb8

That's what a supershields badge URL looks like. Because they are built from random hash strings they're pretty much impossible to guess.

When a private repo owner creates Supershields badges, they will all get unique, impossible-to-guess URLs like the one above. The repo owner then just has to decide which URLs to share with the world (on e.g. a public web page). This way, the repo owner never have to expose more information than they want to.

Pivoting

At some point, I forgot all about the original "code analysis" concept and instead started to think of this service as a slightly more convenient, Github-only version of shields.io, usable for both public and private repos.

This made the path forward a lot more clear: just try to offer something similar to what shields.io offers for Github repos, then release and see if anyone will use this thing, given that it may be slightly more convenient and supports private repos.

Still, shields.io has over 100 different badges it can create, just for Github repos. To be able to compete I had to have something approaching feature parity. As I had five or so badges at the time I realised I had a bit of work to do, and so I started creating more badges.

Testing

I also got one test user, because it is important to thoroughly verify your product assumptions before putting in too much development time and while I had only spent about six months on the project so far, I wanted to be on the safe side.

Sure, most people would choose to involve more than one test user - maybe two or even three of them. I, however, happen to be extremely good at judging people and I judged this user to be totally representing my target audience in every aspect. So more test users just seemed like a waste!

My test user asked for a feature right away. He wanted to be able to just create static text badges where he chose the text on them. To use as labels on a Trello board where he managed development tickets for a team of developers. I saw that it was a killer feature - it would make 100% of the user base happy - so I implemented it immediately.

My test user ended up creating three static text badges, and looking at server logs I could see they weren't used (requested by clients) very often. This made me realise the monetization opportunity here was probably pretty limited. I needed all those extra badge types to lure him (and others) into creating more badges and so get more value out of the service.

Not just for Github users anymore

When users could create badges with static text on them that was not related to Github in any way it was of course silly to require that they install a Github app in order to use Supershields. So another thing that changed was that users now use their Github identity to login and create a Supershields account, but they do not have to install the Supershields Github app anymore.

The user flow now is:

  • Login using your Github identity
  • Create badges

You can still install the Github app but it is optional and will only make it easier for you to e.g. access private repo data from Github. See the developer documentation for more information.

Pivoting again

To reach feature parity with shields.io I started coding lots of new badges, but that was when I ran into another issue - creating new badges was a pain when I had to implement everything in Go and recompile the freaking server every time I created a new badge (or changed an old one). I needed a way to churn out new badges that had less friction and that didn't involve recompiling stuff.

Aha! A pain point, and the very best kind - one of my own pain points!

So I added a Lua virtual machine that executed the badge logic, which was then to be written in Lua instead. Much better - now I could just add new little Lua scripts and instantly get new badges with advanced logic in them.

Enter Lua

The perhaps coolest USP

I rewrote the logic for my current badges in Lua, added a few more, but realized it was still a lot of work to produce 100 badges.

That's when my next Unexpected Selling Point suddenly struck me - I could let the users write the Lua code! Then they'd be able to create any type of badge they'd like. Also, it would mean I wouldn't have to write a million badges in order to successfully compete with shields.io!

This, however, meant a lot of extra ground work for me. I had to:

  • Provide a somewhat usable Lua scripting API
  • ...yes, with documentation!
  • Have a code editor as part of the UI
  • Somehow secure the Lua virtual machines so north korean hackers did not use them to post slanderous news on Twitter about the swedish crown princess

Things like that. A lot of work, but a positive thing was that the project scope expanded further. As everyone knows, bigger scope => bigger success.

Regardless, this feature was just so cool that I didn't even bother to ask my test user if it was a good idea - it was just too obvious that is was exactly what everyone would want. I started implementing it right away, rewriting and refactoring large parts of the codebase. Due to some unforeseen demands from my kids to play Minecraft with them it took three months longer than expected. Before this pivot it was October 2021, and at the time of writing this it is February 2022!

I found a decent JS-based code editor called Ace, which was easy to integrate. I also had to provide some means of testing and debugging scripts, which required a bit of work.

Ace

Security was another issue - all Lua VMs I looked at had pretty basic sandboxing capabilities that looked like it was 50/50 whether they'd provide reasonable security or not. Gopher-Lua, which I was using, let you disable libraries and functions by name, i.e. blacklist-style. Blacklisting things you don't want people to have access to is a very fragile way of implementing security measures and given the ultra-high quality of the architecture in general in this project, I didn't want to take any unnecessary risks. What to do?

Lambda to the rescue

But what if a jailbreak doesn't affect me much? What if I use throwaway instances to run the user-created Lua scripts?

For a long time I've wanted to try out AWS Lambda, and this seemed like the perfect opportunity. Also the perfect opportunity to expand the scope of my project yet again!

Finally a reason to use Lambda

As it turned out, Lambda was pretty easy to implement. And this despite the best efforts of Amazon to provide needlessly complicated tutorials. It only took me a couple of days to move the script execution from my own machine to Lambda instances.

Now, if the north korean hackers take over an instance, they have less than 10 seconds to do nefarious things before the instance is forcibly shut down by AWS. And if they break free somehow, it's as much AWS's headache as mine. When you have a problem, it's always best to make it someone elses problem too!

Current functionality

Here is the actual TL;DR for those who are all about the destination rather than the journey. Or if you just think I write too much.

1. Now users start by creating a new badge using one of the available templates.

There are currently templates for static text badges, a few Github-related badges, and some finance etc. ones, but users can really start with any template and then modify the badge to do whatever the heck they want (except post slanderous news about the swedish crown princess, which will be seriously verboten in our soon-to-be-written terms-of-service).

Creating a new badge

If you want more templates, just open an issue in the SuperShields repo on Github. Depending on how caffeinated I am when I see it I will either add your template right away or close the issue with an annoying comment.

2. New badges appear on the default page users see when they are logged in. I.e. this page shows all your badges.

Here you can see the URLs for the badges, and delete a badge or generate a new URL for it if you want. There is a spanner icon that when clicked opens up the badge configuration editor and another icon next to it that opens the script editor, if you want to edit badge logic.

List of your badges

3. The badge configuration editor allows you to change the looks of a badge.

The badge configuration editor lets you change the default looks of your badge. For static text badges and in many other cases you only need to customise your badge using this editor.

Yes, those BTC quotes are real and taken only weeks apart. Guess when I bought!

Badge configuration editor

4. The script editor lets you program logic for your badges.

The script editor is used to modify the Lua script code the ultimately defines what the badge will look like and what information it will display.

The script editor

  • The Lua script is always executed when a client requests a badge from the Supershields server.
  • The script returns the badge configuration that is then used to render the badge. It often uses the configuration from the badge configuration editor (shown above) as a starting point, then modifies it a bit before returning it. Static text badges tend to have scripts that use the completely unmodified configuration from the badge configuration editor.
  • The Lua script may also fetch data externally, using HTTP, which means it is possible to create script logic that e.g. fetches a stock price and then creates a stock ticker badge.

Do you identify as a developer? Check out the Developer docs

Key takeaways from the project

I'd like to share some general product development wisdom and takeaways from the project with you, lovely reader. My hope is that you may learn and some day become as advanced and efficient as I am.

Features

As an experienced tech entrepreneur I know that it's very important to launch with an extensive feature set in order to properly impress the very first users that accidentally end up on my site.

This meant that throughout development I tried to come up with as many new features as possible, and implement them all, or at least prepare for their eventual and inevitable implementation.

Like always, the strategy resulted in some minor delays to my schedule. I estimate the delay to be about 4 this time. Days, weeks or months you may wonder but no, sorry, I'm talking multiples of the original estimate. Still, the huge success waiting around the corner will prove my strategy to be the right one. My foresight will pay off big time once the users arrive in droves and it turns out all of them sorely needed every single one of the features I've built!

Performance

Another important take-away from being a long-time entrepreneur is that performance optimization and scalability is very important early on in any new project. Because post-release it is just way too late. With all the millions of users that will come flocking within days as they hear about my fantastic product in its very first iteration, I will curse every second I didn't spend on optimization and scalability efforts.

So not only did I put everything behind a CDN, I also implemented caching and sharing whenever possible between badges of results data from slow, external API requests (e.g. to the Github API).

I'm sure that over ~7 active users will still expose serious scalability issues that will make me go into a tailspin, but at least it feels like I'm on top of things due to the work put in. I guess I could have load tested also, but it's not like I have a background in load testing or anything.

Testing

As everyone knows, but few dare to utter, testing is completely unnecessary if you simply know what you're doing. Still, I did test every feature I built, multiple times actually. And despite building the product for myself I had an outside test user that wasn't me, so I can gladly report that testing has been intensive. There are probably no bugs left whatsoever.

Specific takeaways

On rewriting the whole backend in

If I had wanted to be efficient, I would have just installed shields.io and built everything on top of that codebase. But that wouldn't have been as much fun because I'd had to both work in a large JS project and use Node.js. Both of which I'll go to great lengths to avoid. Also, having to produce a lot of Go code is fun, and fun motivates.

On making a Github app

The Github app part actually turned into somewhat of a nightmare as the Github docs aren't fantastic. Github seems to think it is totally unnecessary to explain how various data objects (like accounts, app installations, subscriptions, plans etc) relate to eachother and interact.

The UX people at Github also seem to have been poached from some spy school or something, given how skilled they are at hiding things where noone can find them.

Especially annoying was how much effort they put into hiding important UI functionality needed to develop and debug Github apps. Like, if you install your Github app using an install link found under /marketplace/appname, the installation will get a subscription connected to it and all will be just fantastic. But if you install the app from the app admin page /organizations/orgname/settings/apps/appname, the app installs fine but doesn't get any subscription/plan connected to the installation. This almost drove me crazy before I figured it out. I'll probably write an article on Github app development at some point, because there is a lot to say and not much info available out there.

But who the hell should use this thing?

Beats me!

Or, well... Before the latest pivot, the one that gave users access to the Lua-based script logic, I really don't think Supershields had a lot to offer compared to shields.io. Now though, I think Supershields is more fun to hackers, which will find the scripting capability simple to use and allow them to easily create any type of weird badges they want.

I'd say that Supershields is good for hackers who want some type of badge currently not supported by shields.io, but given how many badges shields.io has I'm not sure the Total Addressable Market for Supershields is huge. Most people should probably just use shields.io and be done with it!

But:

  • If you want a special type of badge not supported by shields.io, Supershields may be an option.
  • If you want to create badges for a private Github repo without self-hosting shields.io, Supershields is the best (i.e. only) option.
  • If you prefer a slightly eccentric badge provider without a clear color scheme, Supershields is the obvious choice.

Post as:
🌹