Skip to content

Instantly share code, notes, and snippets.

@jorenbroekema
Created December 5, 2020 15:32
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 jorenbroekema/19d88afd754674ee1182f1d1ffd70f3c to your computer and use it in GitHub Desktop.
Save jorenbroekema/19d88afd754674ee1182f1d1ffd70f3c to your computer and use it in GitHub Desktop.

code-workshop-kit: a tool for remote coding workshops

Structure:

  • Intro: Remote workshops/trainings/classrooms for code. COVID-19
  • Problems
  • Solution: code-workshop-kit
    • Shared input through VS Code Live Share extension
    • Shared output through @web/dev-server extension
    • Scaffolder
  • How to use
    • Frontend example
    • Backend example
  • Future / conclusion

In today's world, more and more workshops and trainings are held online rather than offline. Instead of standing in front of a classroom in a real physical location, we often find ourselves educating in front of a digital Teams or Zoom room. This transition has been happening for many years, gradually. Then, COVID-19 hit us, meaning that more and more people are now permanently working from home and classrooms with a bunch of people in a small room are a no-go in most places in the West. Even though I am optimistic about the future of this pandemic, it still seems likely that it has sped up the transition of workshops and education, and I foresee that even most conferences will embrace digital means of attending from now on.

My troublesome experiences with online workshops

Beyond my daily work as a web developer, I am also an educator, giving workshops and full-day trainings usually twice a month or so. My style is very interactive, hands-on and exercise-driven. This requires input from my participants. If you happen to be like me this regard, you will recognize the following problems when giving such trainings online.

  • No response. When you ask a question to the room of online participants, you will likely find that it's much more uncommon for people to answer. Part of this is a lack of accountability and responsibility, since you are essentially invisible in a group of many other participants that might answer. Even when asking a participant by their name specifically, will sometimes leave an awkward silence, as you did not realize the person was at this moment grabbing a snack, a coffee, having a toilet break or shooing away their kids from their improvised home office.
  • Can you share your screen? Whenever one of your participants runs into an issue, especially if they're not an expert at explaining code bugs/errors, you end up asking them to share their screen so you can look what's going on. Apart from the time spent to share screens and get that working properly, you also distract everyone else in the meeting with the issue of that one participant. In a physical classroom, you can walk up, look over their shoulder, and whisper to help them out. This is much more welcoming than asking the participant to essentially broadcast their mistakes to the entire room. I have found from anecdotal experience that participants are far less likely to ask for help for this reason alone.

These two problems alone, were enough to exhaust myself after giving my first 2 workshops online. I hated the experience. It was awkward, inefficient, and many of my participants lost their attention span, and I do not blame them. I basically decided I would require my participants to be present physically for my workshops and trainings. However, after COVID-19 hit this was no longer possible and when I realized all of my future trainings and workshops would be like this, I decided I had to find a better way.

Finding a solution

When identifying the problems, two main requirements arose:

  • Shared code: I need to be able to see and collaborate on the code of my participants.
  • Shared output: I need to be able to see the output that the code of the participant produces.

When searching for a solution to the first problem, I came across many tools. Some examples are simple codeshares like pastebin, Github gists, Codepen, JSFiddle, but these lack the feature of live collaboration. CodePen Professor Mode and codeshare are probably the closest I got to the solution I needed but both are closed source and have their limitations which I figured would end up biting me. The final contender is perhaps one you already thought of: Visual Studio Live Share, in my case the extension for Visual Studio Code. Or as I call it, the Google Docs of coding. This puts collaborative code sharing and writing, in what also happens to be my favorite code editor of all time. My experience with this extension has been great even in my own work as a web developer, when collaborating on something with my team members. The main advantages of this are:

  • Open source! Meaning I can easily fork, patch & contribute
  • Extensibility API, to write or extend upon VS Code extension
  • A bunch of other feature, most notably Shared Servers.

So with this, my first requirement was met. And Shared Servers even inspired me for the second requirement.

If you are a frontend developer, you will often run a development server so that you can check out your app on localhost:8000 or something similar. With shared servers, any participant that is connected to your session, has an SSH tunnel to you and the port you share in shared servers. This means that they can go to localhost:8000 in the browser and see the running application as well! That is a great start to satisfy the second requirement: making sure we can see the output of the code of my participants.

A few challenges remain however:

  • My participants will all have their own code, and therefore their own output. How do I easily distinguish and view a specific participant's output?
  • Seeing an overview of all the outputs of the participants, so I can easily glance at all of them simultaneously to see if I find a participant who is lagging behind or stuck on something.
  • See updates of the output whenever a participant saves a file inside their folder without refreshing the page.
  • See the output of backend languages where the output is not a served web application or module.

code-workshop-kit

This is essentially where code-workshop-kit, my NPM package, comes in.

It is a smart dev server that is built on top of a revolutionary, buildless, development server called @web/dev-server, which is the successor of es-dev-server built by the guys from Open Web Components.

The cool thing about this server is that it is essentially an abstraction on top of Koa making it super easy to write plugins and middleware for serving files over HTTP, and it has a really good NodeJS API for extending and building on top of it to make your own opinionated dev server. This is exactly what I needed to overcome the remaining challenges.

What the code-workshop-kit server does on top of @web/dev-server, is ensure that when serving the main index.html, an app shell component is inserted which does a few things:

  • It serves a "select a user" screen where visitors of the page can pick their name from the participant list. This will act as basic authentication with the dev server where needed.
  • Serves an overview page where the output of every participant is aggregated to, whether that's a frontend Javascript module, their HTML page through an iframe, or terminal I/O for backend workshops.
  • Insert client side scripts to setup Websocket communications for things like Hot Module Replacement to see live updates, or for a cool feature called in-browser follow-mode where if the host visits another page on localhost, every connected participant's URL is updated to follow the host.
  • Insert an Admin-only UI bar for toggling dev server settings on the fly!

There's many more cool features, to read more about this, visit the code-workshop-kit docs!

How to use it

So far the main use cases I get are either frontend web workshops, or workshops which are backend and where the terminal is the input/output. So let's go over those.

I assume here that you have NodeJS and NPM installed.

Frontend

Create an empty folder and install code-workshop-kit:

https://gist.github.com/6f2b34321401ee7f7431eb3c7e037a92

Open the folder in VS Code.

Create a file called cwk.config.js:

https://gist.github.com/273f1b13ce7567937cd1f90af2994586

This creates the default export that the CWK server uses to read the user provided configuration settings.

Now let's create some starter files for our participants. Create a folder template.

In this folder, create index.html:

https://gist.github.com/c9c96e776444c871714b01d5ce635f07

Let's also create a starter JavaScript file, index.js:

https://gist.github.com/1357a17ba0d8e7ee452cff9657bf1085

Note the special <%= %> tags in which we can place variables that will be filled in by the scaffolder. Read more about that in the scaffolding docs

Scaffold these starter files for all participants:

https://gist.github.com/f4415cf78c191f0b12b7c662c9ed2e0b

You should now see a folder "participants" with a folder for each participant and their starter files.

Let's see it in action

https://gist.github.com/bd3e0fe3462537d90089b061fe5b16aa

Now check out the browser on localhost:8000. Pick a name!

You should now see the participant overview, and every participant's index.html rendered through an iframe. You can click the view buttons to view only one specific participant's output.

Simple enough right? But it gets cooler.

Right now we render the participant's webviews through iframes. This is not ideal, especially in larger number of participants, since iframes are just not that performant. They also live in their own realms, meaning they cannot share dependencies, making this even heavier on the server end of things.

Very often in the land of frontend, the main entrypoint is a Javascript file: index.js, and we export some sort of template which gets rendered in the DOM. This is quite common for Single Page Applications. The benefit of this approach in code-workshop-kit is that we can use a technique called Hot Module Replacement to reload this exported Javascript module whenever files have changed, without needing a page reset. Furthermore, the overview page can load the module and no iframes are needed, meaning dependencies can be shared easily.

Hot Module Replacement, to my knowledge, was first conceptualized and implemented in Webpack, but by now this concept has been implemented in a myriad of ways in different frameworks and technologies, and I personally implemented it in code-workshop-kit as well.

Let's change our setup to use this method.

In the cwk.config.js, edit it to:

https://gist.github.com/82d939b29728c782528c3b91c71a8bb8

This will assume an index.js file in the root folder of every participant, which must contain a default export which is either:

  • A string value (containing HTML template)
  • A DOM Node/Element (document.createElement('div') for example)
  • A lit-html TemplateResult. This is one I am familiar with, I'm perfectly happy to accept feature requests or contributions for other templating methods, as long as they are not locked into a compilation step

Delete your index.html inside the template folder. Edit the index.js:

https://gist.github.com/e7c4909b6d23412eaff167c15dffb871

Delete your participants folder entirely, and just re-run:

https://gist.github.com/43a87728a61c59a1db5da8e6c3d54dd7

Then restart the cwk server:

https://gist.github.com/a05417dfc38c591284fe0ac2bb214268

You should see the same overview. But this time, things are rendered through modules instead inside iframes. Hot Module Replacement also works now. You can see this by going into for example Bob's index.js, and change:

https://gist.github.com/927d29ae760e50911354d06e3d1ca289

to

https://gist.github.com/73162441d7e99a670e09a2d45ac0c051

Hit save, and immediately the application will reload the module, and it gets updated in your browser and those of all other participants, without anyone needing to do a thing for it! As a workshop host, you just sit back and watch the outputs change over time as your participants are writing away at their exercises.

Backend

So many of you will ask, "okay that's great but what about my backend workshops, where the output is not a served web application or module?"

This is one I struggled a bit with myself. At first I thought, just use the shared terminal feature of VS Code Live Share, but that means giving write access to your machine to all your participants, which I personally do not feel very comfortable with. It also gets tricky to keep track of which shared terminal is assigned to which participant..

So I figured, why not give the workshop host the control to specify which command gets run in each participant's root folder, and just re-run that when files are changed. Then, just spawn a child process with the specified command, and aggregate the terminal input & output to the web server.

So that's what I did. Let's see it in action. Since you have NodeJS installed, I will use a NodeJS example, but I have personally tested this with many other backend languages as well.

If you want more information, see docs on using terminal target

Change your cwk.config.js:

https://gist.github.com/bc67b9d4d23b0e5d04404b05b9deab71

Change the index.js inside the template folder to create a tiny terminal input/output program:

https://gist.github.com/4c31f2f886fc267def369f934a847430

Rerun the scaffolder with -f to force overwriting existing files.

https://gist.github.com/90d85a3d6116d767f15db9a74a2f9354

And rerun the cwk server

https://gist.github.com/cd08b5d5e30e5b2672e55eede45a603e

You will see a slightly different overview page now, because there is now a clear and a rerun button, as well as a terminal input field which is disabled by default.

Try saving one of the files of the participant, or click one of the rerun buttons. This will make CWK run node index.js inside that participant's folder, and the output is aggregated to the participant's view. You will see a green circle pop up notifying you that a script is running for that participant, and you can now use the terminal input field to and press enter to send. This will send your text to the process' input.

Future

At this time of writing, code-workshop-kit is v1 (v1.0.4 to be precise). That means the API is stable. Me and two others have personally alpha tested with this a fair bit, both for frontend, usually web component related workshops, as well as Java backend workshops. From personal experience, this tool is revolutionary for how I host my workshops and trainings online, and even if I have an offline classroom, I would likely still use this tool. It has solved my painpoints, and that by itself makes creating this tool easily worth it.

That said, the code is open-source, which I think is fair given that I build on top of existing open source projects, want to reach as many teachers as possible, and want to carry my weight during these difficult COVID-19 times.

This project is not finished, I will continue working on it for the foreseeable future. Microsoft's VS Code Live Share extension team were kind enough to reach out to me and we had a very insightful meeting, so I have many ideas on how to further improve.

  • Leverage codespaces to allow participants to connect to a session from their browser, without needing to install VS Code & extensions
  • Collaborate with the live share team to further improve and suggest new features for their extension
  • Leverage the extensibility API of VS Code to further reduce the work needed to be done by the workshop host
  • Create more content on delivering high quality workshops, and supplying out of the box working setups for specific languages/frameworks

If you use code-workshop-kit, please do reach out to me, I'd be really happy to know about your experiences and feedback!

You can reach me on Twitter and LinkedIn, or send me an email

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