Skip to content

Instantly share code, notes, and snippets.

@vkz
Last active July 31, 2023 20:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vkz/9526e50f86b0a8891337977666ab7141 to your computer and use it in GitHub Desktop.
Save vkz/9526e50f86b0a8891337977666ab7141 to your computer and use it in GitHub Desktop.
Could GitHub Copilot and ChatGPT become your tech co-founders?

Launching solo: TAB-driven product development with GitHub Copilot (episode 0)

To LLM perchance to dream

I finally gave in and decided I should take LLMs for a serious spin. Not quite ready to surrender to the likes of GitHub Copilot but I feel like the time has come to give em enough room in my toolkit to truly evaluate their potential. I've largerly remained on the sidelines of the most recent LLM drama as it evolved into a more or less global phenomenon. I can't even tell if we've reached the top of the hype and riding the wave or still climbing - my Twitter has been drowning in all things LLM for months now. It basically rendered For You feed useless - no human can keep up with updates coming in so frequently, nor can one accurately judge their significance. I haven't had a chunky enough task to try them in earnest anyway. Until now. See, I have a severe case of business idea and a short window of opportunity about to be gifted to me. My better half is taking kids to grandparents for the summer break. That's right - I am being left behind - the kind of luxury only a fellow dad of more than one kid can appreciate. It just doesn't happen.

git.ht, which I launched in late May early June, has been gaining users but slower than I would've hoped. It definitely has much growing to do before it can feed a family of 5 in London. So, yet again, I find myself looking for dev contracts to provide. This time, however, it feels different. In recent years I've mostly done Clojure and ClojureScript and never had trouble landing gigs. Not anymore it seems. EU economy appears to be stubbornly set on going into a largerly self-inflicted death spiral; VC funding is no longer easily available to anyone who'd bother to ask or bring up blockchain; waves of layoffs keep hitting big tech, etc. It isn't all red, but businessmen have become more picky and their hiring habbits have changed. They are being less cavalier building engineering teams, not as adventurous with tech stacks. Other than inertia there's now another possible reason for such risk off. There's been a seemingly unwavering onslaught of LLM based tooling and practices or expectation thereof. If your language or favorite framework made it into the training set and had enough code to effect the weights of the big-ass foundational models, you'll be doing fine. Anything fringe - no matter how well engineered, effective, efficient and ostensibly productive - is highly likely to be rendered insignificant by the gains in productivity brought about by LLM tooling. I want to be clear, I'm not making quality judgement here - not saying the end result will be better or even any good as compared to, I don't know, Haskell, Clojure or whatever your niche pet-stack maybe. I'm talking about productivity with the emphasis on product. All I'm saying is that there will be product. It'll work. It's time to market will likely beat anything a well-trained but stubborn team of engineers can produce. I suppose, this is a long winded way of saying that going off the mainstream track may cost you.

First off, the quality gap between what I would call "elite" stacks and boring Java, muh wat JavaScript has been steadily narrowing in recent years. Your Scala, your OCaml, your Haskell, your Clojure, your PureScript - whatever fancy-pants language that makes you feel entitled - may retain some superiority for now but the mainstream has largerly caught on (assuming you've been paying attention to JEPs, TC39 etc). At least where it matters for the end result not for scientific purity or beauty. Even then, many have been on a steady and deliberate path to simplicity - committing to one agreed upon way of doing things, etc - there have been great examples of that marked by decisiveness, agreement and solid engineering. Stability, tooling, choice of libraries to handle necessary but oh-so-boring minutae, attention to security and secure practices, "googlability", exceptional documentation often paired with actual true-to-ansi-ecma-whatever standard, sizeable community increasing the chance of your question being answered in a timely manner, emphasis on monitoring tools and debugging experience, deployment targets catering mostly to mainstream, sheer amount of written code and therefore examples you can steal from.1 This last bit brings us to the now. LLMs and the "TAB-driven development".

Having tried LLMs here and there I can't say I'm troubled or fear I'd be replaced, although I am yet to try them for actual programming tasks. With non-programming tasks they've been a mixed bag for me - you get a lot of grammatically correct but stale and generic content. Ok, well, I admit I'm a little bit frightened but not of being replaced "by AI" so much as by being thrown back a decade or so, or probably the other way around - young devs gaining a decade on me simply by leveraging the DWIM capabilities of LLMs. Does that make sense? Let's unpack a little. I have feeling that my worldview as a professional programmer is up fo a backward incompatible update (or is it forward incompatible?). What I felt was important, what I felt required focus and time investment has been rendered utterly insignificant. Much of what goes into "practice of programming" has been dwarfed (or about to be) by the changes heralded by these models and the tools they make possible. I obviously speculate here and I think it's time I put it to the test. I guess, this post is just me procrastinating instead of diving head first. Oh, well, must avoid further damage to my psyche. I have a few days till family leaves and interruptions leave with them, so instead of venturing into unfamiliar land, I'll procrastinate by pouring my ill-informed thoughts into this hoot. It'll be interesting to compare my notes after I've taken the dive. Enough waxing poetic and being all vague, let's get to the meat of this post in as much meat as can be had, seeing how it isn't about anything I've done so much as about the intent.

RSS

On one hand, I have an idea for a web service I can charge money for once its done. Happens to have a nice quality to it where I can see myself using it every day, just like git.ht - the best kind of business - one where you are its first eager customer. As ever I'm very much scratching my own itch. Oh, yeah, it'll totally ride the LLM hype - I'm very much in the business of selling buckets and shovels, if you get my meaning. On the other hand, must put food on the table. Sadly not many Clojure gigs out there just when I find myself needing one. Pay went down, too. Doesn't help being senior and expensive. Certainly not in the UK or EU. It's been looking gloomy enough, that I have to seriously ponder switching to a more mainstream stack - something I'd normaly try hard to avoid if not dread. For better or worse that attitude will have to change following the rise of LLMs. I'll continue looking, obviously, but I'd like to hedge my bets. Now, I tend to go niche and obscure - some loose wire in my brain that forces me to root for the underdog. Might just be me looking for the "silver bullet" of a language that a chosen few are privileged to use and it is so awesome we'll just out-hack and outproduce everyone around - once someone writes an Emacs major mode for it. Well, I am committed to not go this route this time around. What I mentioned earlier about the mainstream catching up to the niche and the hip is half of the reason. My only regret with the mainstream is that it seams to be obsessed with parenthesis, curlies and all sorts of braces - I don't know what it is but your average Java or TypeScript programmer insists on splashing this syntactic soup all over their code. I mean, I would've thought Lisp and s-expressions offer enough parens for anyone, but no, they need more. What can you do? LLMs and what I call "TAB-driven development" championed by the likes of GitHub Copilot makes up the other half. Like I mentioned, I've no time to lose, and I'd like to put my "increase in productivity" with the emphasis on the "product" to the test. And pick up a mainstream "stack" along the way. This admittedly muddies the experiment, cause not only will I be TABbing towards an actual product, but I'll be doing it in an unfamiliar language, ecosystem, even editor. I mean, just shipping a product using the tools and languages you have a good grasp on is challenge enough. I should know. But I just can't help myself. Also, if I am to go through the transition in my programmer beliefs, I'd rather endure the bulk of the associated pain and be done with it. The great fire of London, the great fire of Moscow. Build it again - make good use of modern materials.

Ok, so what's our mainstream? What are we learning? What are we building? We are building your typical web-service. Monthly subscription, landing page, sign-up, sign-in, web intreface to the product itself, much of its actual functionality belongs in the backend, it will rely on LLMs for some of its features, etc - nothing too funky - not sending rockets to space. If you've ever shipped any kind of SAAS or web-service, you'll know that (a) building the "essence of your product" is the pleasant part, and (b) is completely dwarfed by everything else you need to put together for customers to even get to try your thing. I'm not even going to bring up marketing. Let me throw some cold water on your shiny and rosy picture of building a business. Getting people to even learn that your thing exists is a world of its own and very quickly turns into a full time job. Hacking together the core of your product is like step zero - you're in the lobby about to open the doors and go outside - seriously don't delude yourselves. Once you learn this the hard way, by your own sweat and tears, any claim that some outlandish "stack" gives you some magical superpowers smells of bs.2 This gets overlooked in the scenario where you raise quite a bit of money. Got money - got room to play and experiment. At least some of that misconseption, I suspect, is due to old Paul Graham's essays. Case could be made it was like that in his day. I don't know. Maybe. I like to think it wasn't Lisp so much as, well, Paul Graham being Paul Graham - smart enough to pull it off in any language. Anyway. Present landscape appears sufficiently different. Every new language or tool better earn their keep. Marginal gains of 3-5% will be quickly erased by the "DWIM damn it" monkeying - brute force prompting. Just look at my list again - there's nothing in it that hasn't been done before - except for your "core product" that is. In the age of LLMs this is kind of good news. It means, in theory, you can prompt much of this minutae out of the way. Even if you're starting out. Being able to open a Java or Typescript file for the first time in your life and ask something as trivial as "how the hell do I read some data from a file?" and have the necessary code magically appear - is that so bad? Especially when you're as verbose as Java with its ReaderBuffer whatever the f... insanity. It's been done like a million times before. Ditto starting an HTML for your landing page or a template. I can never remember the whole <doctype> then <head> with crapton of important but mostly random meta stuff like viewport in it. I always have to Google that. I can see you, Emacs and Vim heads shaking fists, with your skeletons and snippets - yeah, yeah. But here's the thing. You don't even need to know any of these exist. You don't need to set them up or remember the incantation or the head that starts the snippet, etc. In that sense LLMs don't really bring much of anything to the table - a lot of it is already available to practicing programmers. Except for the DWIM part and no need to learn and practice - just brute force your way to a working thing. That doesn't absolve one from ensuring these completions run at all let alone work correctly for edge cases etc. Experience and good programming sense will continue to count for a lot - that's good news for us programmers.

We humans are pretty good at judging what'll work and what won't especially with a little bit of training. Example I like to give is one where you can quickly tell whether a piece of music is beautiful and sophisticated or not, even if you've never learnt any musical theory or played an istrument. You hear Rachmaninoff and you can tell it's amazing even if you're not a fan. Ditto with art, photography and many other things. Discerning bs in maths is a whole diffrent story, of course, but luckily programming isn't as sophisticated - certainly not the kind of programming we're about to engage in. On one hand, I am terrified to learn of just how much of my hard earned knowledege and muscle memory is about to become absolete - a bitter pill to swallow once you realize younger devs won't ever need to go through the pain of picking any of that up. There are invisible scars of course - experience you get to carry and apply that they just don't have, but hardly anyone can see that. There may come a time, probably soon (unless it's here already), when hiring managers can no longer tell the difference between someone who's been programming for over a decade and young shoots fresh out of college. My answer to that is ... become a hiring manager. In a way there's never been a better time to be a solo founder or starting a business with someone you've worked with. Sorry, I've gone off course, haven't I.

TAB-driven product development with ...

What are we going to use and learn? Remember, we want something Copilot et al "know well" and can provide reasonable completions for - the whole point of this experiment. Were it not for this not so minor detail, I'd be very tempted to go with Erlang and take LFE for a spin. Going back to earth I'm thinking TypeScript on the backend and either no client-side code at all - would be my preference - or as little of it as possible. I briefly considered engaging one of the more popuplar web-frameworks but that requires such a huge buy-in from the start, and I'm just not feeling the need. I looked at NextJS, and as far as React frameworks go, it isn't half bad. I know React quite well by way of ClojureScript + re-frame, so I'm reasonably confidend I can hack it, but then again why bother. To NextJS's credit emphasizing backend, deemphasizing client-side and React, was absolutely the right move. Ditto leveraging filesystem for routing. After all HTTP and your early-days web were modeled with filesystem firmly in mind. To this day, I'm convinced noone ever came up with anything simpler for static routing and nothing beats CGI mapping - i.e. dispatching to scripts on your filesysem - for when you need dynamic content generation. So, yeah, I guess as far as frameworks, you could do worse than NextJS. Client-side, I am reasonably confident I can get away with little to no JavaScript, sorry, meant to say TypeScript, but I think I'll load Hotwired Turbo on the client, just in case I find I need my pages a tiny bit more dynamic. It isn't just for Ruby on Rails, which by the way, I don't know at all and have absolutely no desire to learn. It is very minimal, conceptually simple and mostly orthogonal to backend, doubles down, in fact, on server side content and happens to choose HTML for said content. I used to have my own concoction conceptually similar that did even less - that worked fine for personal projects, but then Turbo was announced and I made it play nicely with Clojure on the backend, so I'm going to stick with it. HTMX and friends again require a little too much buy-in, at that point you may as well switch to Erlang + Phoenix or something. Oh, wait, it's Elixir, isn't it?

So, TypeScript. I can't claim I know it, but I did write a lot of JavaScript with Node back when it was ECMA5 or was it 3, that is to say, when JS was utter garbage. It made it extremely easy to dunk on it at every opportunity. I had mine talking at Strange Loop way back when. I don't know if I should feel ashamed now, but can you really blame a guy. JS ecosystem has always been rich and nourishing to creativity even if the host language was ridiculous, but the language has grown by leaps and bounds since. One can argue it's too much, there's just too much of it and it's bloated beyond reason, but there's something to be said about large languages. JavaScript wouldn't be the first and it is in good company. You thought I meant Java, didn't you? Nah, I was thinking of Common Lisp. TypeScript means a bit of a learning curve for me - I've not used it in anger - but I am partial to optional typing by way of Typed Racket. With TypeScript I still think it is a tradeoff - one you need to be conscious about. Having a compiler in the mix robs you of the immediacy provided by going with straight up JavaScript. With widespread addoption among the browsers ditching transpilers sounds like a good idea to me. Ditto bundlers. With HTTP/2 you no longer need them on the client, and you've never needed them on the server to begin with. I'll admit I'm spoilt by Clojure3 when it comes to eval-driven development. Not quite Common Lisp experience, but close enough. JavaScript, IMO, made a mistake with const vs let vs var. Did you know Chrome's console makes no distinction at top level to allow re-definitions? I think V8 shipped with Node ought to follow suite, but the issue opened against it some years ago remains unresolved to this day. Not a huge problem, and certainly not something worth fighting over when you need to compile and typecheck anyway. There's a lot to recommend TypeScript, too. It is a marvelous engineering achievement, isn't it. Its source, which I looked at, its tooling and its whole attitude - not lax but not in your face brutal either - gradual, you know, almost acommodating and forgiving - I like it. TypeScript compiler and toolchain deserve more credit and I, for one, can see how I can hack interesting language thingies by hooking into the pipeline. It's code shows a fair amount of indirection that I don't appreciate, but with some work I can plug my changes. There are also a few nice hooks that it provides where you can avoid forking the compiler, like e.g. you could give it your own handler for JSX syntax. Lo and behold you can leverage all available tooling that assumes JSX but you use it for strictly server-side rendering - essentially JSX as your HTML templating engine not tied to React in any way. More verbose than s-expressions or hiccup, but still nice.

Another first for me will be using VSCode. Can't say I look forward to the experience seeing how I practically live inside Emacs. I'm so sceptical, in fact, that I might just get pleasantly surprised - we'll just have to try and see. The thing I dread the most is not really having to pick up a bunch of new habbits and learn how to use what few extensions I need. How do I explain this? You can poke at Emacs while you actively use it. You'd be surprised how often I find myself jumping to some command's definition to look at its code, instrument it for step debugging and maybe switch over to my own version of it. All in the same session. It's a bit like fixing your vehicle as you're riding it. Sounds terrifying until you try it and then you can't live without it. It usually goes something like this. Eh, that key sequence just did something strange or not quite what I expected. What command is bound to it again? Jump to its definition in Emacs Lisp right from its help buffer. Read the code. Maybe instrument for edebug and run it again stepping through4. Hop to callees as necessary. Tweak the code - any code, eval and try this new version. Iterate until you fixed it or you understand it better. These days, I don't even bother installing modules without reading their code first. VSCode by comparison seems ... monolith and unaproachable. I've no clue if you can even reflect where in its code things happen. Can you even touch the code or you need a separate checkout and dark magic? Can I poke at random extension code? I'll have to compile and reload something. I'm guessing it won't be the same editor instance. It's a new less direct way of doing things assuming I can even figure it out. VSCode seems enormous. Sadly, as far as LLM assisted development goes, it largely remains the only full-featured player in town. Sure, Vim and Emacs have bits and pieces talking to Copilot and ChatGPT APIs, but nothing quite like the integration that VSCode enjoys. It's also the only one with the latest Copilot Chat offering, which sounds like something I'd be using quite a bit. I believe they even integrated a special /vscode command that can help you figure out VSCode itself and its settings. Someone had the foresight to either add necessary VSCode related embeddings, or perhaps even better, fine-tune the model. See what I mean, when I say, all that time spent mastering sophisticated tools like Emacs may turn out no more than sunken cost at some point? Either that or we follow suite with local inference5 with the likes of llama.cpp paving the way. I doubt we'll have the money to fine-tune though and just having embeddings might not cut it. GNU/Emacs and Vim chaperons' insisting on having extensive documentation might just deliver the silverlining we need, so not everything is lost, I hope.

So, yeah, fun times ahead. I look forward to the experience. Not. I dread the frustration and scars acquired. That's the price we pay to be in this business, I guess. Why do I suddenly feel like a nobody with nothing to show for all the years hacking computers? ;-) It may also turn out differently. What if Copilot et al are overhyped? Wouldn't be the first time. My bet is on "not quite there, yet" but give it time. I guess we'll find out. Gotta give it an honest try.

PS I love ya

... Clojure, LFE, Elixir, Hylang, Emacs Lisp, Guile Scheme, Racket, OCaml, Forth and so many others. May not be obvious but it isn't all bad news. Not unless we give up. In this frindge camp of ours, seemingly pushed aside by the recent advances in LLMs, we do have hope. These models are pleasantly recursive. Instead of retreating bitterly into a far away corner we should probably try and look at ways to leverage the models to our advantage somehow. I have this nagging feeling that this data advantage the mainstream has on us can be addressed and sufficiently narrowed by using the output of the models for fine-tunining, embedding or to truly effect weights in the models that will surely follow. Even now, one can translate code written in one language into another with some success. It may not be possible to automate much or any of it and one would have to be careful to control for garbage, but IMO the most consequential benefit of LLMs is in that they're often enough to take you from the "blank sheet" to something you can tweak into good enough. That alone is huge. This is all speculative, but we need to have that conversation and have people experimenting in earnest. That is if we feel that our pet-languages offer enough of an advantage over the mainstream and we just need to level the playing field. This, too, isn't obvious at all. If the end result - all code gets written by a machine - our pets will have to die.

Any comments?

As always this hoot is nothing more than a GitHub gist. Please, use its respective comments section if you have something to say. Till next time.

Coda

I'm running a (mostly) Clojure SWAT team in London at fullmeta.co.uk. We are always on the lookout for interesting contracts or fulltime gigs. Can perform competently in modern Java, TS/ES, Go. Can target JVM, V8 and Node, .Net, Erlang BEAM. Now that git.ht is up, which you should go ahead and check out rigth now, I am back to CTOing and contracting. If you're hiring, check out my CV and shoot an email to vlad at fullmeta.co.uk.

Follow me on Twitter

Footnotes

  1. Fair question to ask is wheather we needed all of this to begin with, but it is a topic for an entirely different conversation. Languages, runtimes, tools we use are quite honestly out of control. I'm trying very hard here to remain constructive with what we have. Not a single week goes by that I don't have to squash the urge to nuke the entire "STACK" from the orbit. Or retire myself - less drastic but sadly less affordable, too.

  2. Might be different if you're doing something truly novel, but if it needs software, well, chances are that novelty isn't where its at. I dunno. I've done enough to be extremely suspicious of lofty claims by people who haven't shipped and only have toy examples to sell me. Just so you know, my first 2 languages were Racket and Scheme. Took a few years for me to learn I had been doing functional programming. I thought that's what programming was. You get what I'm saying? Wink, wink.

  3. Yes, I do in fact mean Clojure proper - not ClojureScript. I dunno. CLJS is such an odd-ball. It is increasingly difficult to justify its use. Setting it up is overcomplicated for no real benefit. Closure Compiler shouldn't be there any more; language semantics is sufficiently different especially around modules and namespaces - so much so that when you try to cater to so many environments and use cases (you really shouldn't) it turns into downright mess. I have words. Many.

  4. You may not know it but you can even step through Emacs Lisp macros. Way they handle it is brilliant in its "manual" simplicity.

  5. I have a few fairly powerful servers collecting dust in the closet that I'd like to setup to run inference locally. Sadly, these aren't furnished with GPUs, so I'll have to try and see how I fair with plenty of cores and a lot of RAM. Would that make a difference? Guess, I'll find out. I'm starting to feel this is the direction everyone with tech chops ought to start heading if only to preserve some semblance of independence and hope of filtering out narrative forming bs about to hit the wires en masse.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment