DEV Community

Cover image for code-workshop-kit: a tool for remote code workshops
Joren Broekema
Joren Broekema

Posted on • Originally published at joren-broekema.Medium

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

I created a tool for people that teach code, called code-workshop-kit. It makes remote workshops interactive and allows for experiences similar to those in a classroom, and better.
In this blog I will explain the problems of remote code workshops, why I created code-workshop-kit and how you can use it.

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. Even though I am optimistic about the future of this pandemic, it still seems likely that it has sped up this transition of workshops and education. I foresee that even most conferences will embrace digital means of attending from now on, which would include their workshops being held remotely as well.

Challenges in online workshops

Next to 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 in 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 less common for people to answer. 
    Part of this is a lack of accountability and responsibility, since a participant is 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 busy 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 that participants are far less likely to ask for help for this reason alone.

These two problems alone in my first workshops online before COVID-19 made things quite exhausting; I really disliked the experience.

It was awkward, inefficient, and many of my participants lost their attention span and I don’t blame them. I figured I would ask my participants to be present, physically, for my workshops and trainings, if possible.

However, after COVID-19 hit this was no longer possible. 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 are not meant for live collaboration. 
CodePen Professor Mode and codeshare are probably the closest I found to the solution I needed. However, 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 like to 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. It is open-source, has an Extensibility API to write or extend upon VS Code extensions and a bunch of other features, most notably Shared Servers.

So with this, my first requirement was met, kudos to the Live Share team at Microsoft for creating such an incredible product! Shared servers inspired me for the second requirement.
With shared servers, any participant that is connected to your session has an SSH tunnel to you over the port you share in shared servers. This means that they can use localhost:<port> on their machines and access a shared API or web server.

However, there are remaining challenges:

  • See the output of backend languages where the output is not a served web application or module
  • 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

code-workshop-kit

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

It is a smart development 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.

This server is essentially an abstraction on top of Koa, making it 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, among other things, has:

  • Basic user authentication for participants and hosts
  • An overview page on which the output of every participant is aggregated to
  • Hot Module Replacement for frontend workshops
  • Follow-mode, allowing the host to switch pages on localhost and the participants’ URLs are updated to follow
  • 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 are either frontend web workshops or workshops for backend languages, where the terminal is the input/output. So let’s go over those.

Having NodeJS and NPM installed is a prerequisite.

Frontend

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

mkdir cwk-test && cd cwk-test && npm init -y && npm i code-workshop-kit
Enter fullscreen mode Exit fullscreen mode

Open the folder in VS Code.

Create a file called cwk.config.js:

export default {
  appTitle: 'Welcome to Joren\'s Frontend Workshop',
  participants: ["Joren", "Bob", "Alice"],
};
Enter fullscreen mode Exit fullscreen mode

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:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <h1>Hello <%= participantName %></h1>
    <script src="./index.js"></script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

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

console.log("Hello, <%= participantName %>");
Enter fullscreen mode Exit fullscreen mode

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:

npx cwk scaffold
Enter fullscreen mode Exit fullscreen mode

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

Let’s see it in action:

npx cwk run
Enter fullscreen mode Exit fullscreen mode

Now check out the browser on localhost:8000. Feel free to invite some others by creating a session in VS Code using the Live Share extension.

If you select a name, you should then 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.

Participant Overview of code-workshop-kit inside the browser

Simple enough right? But it gets cooler.

Right now we render the participant’s webviews through iframes. This is not ideal, especially with a larger number of participants, as 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 and slowing down your page.

Very often, in the land of frontend, the main entrypoint is a Javascript file: index.js. We then export some sort of template which gets rendered to 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.

Let’s change our setup to use this method.

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

export default {
  appTitle: 'Welcome to Joren\'s Frontend Workshop',
  participants: ["Joren", "Bob", "Alice"],
  targetOptions: {
    mode: 'module'
  }  
};
Enter fullscreen mode Exit fullscreen mode

This will assume an index.js file in the root folder of every participant, which must contain a default export which is either an HTML string value, a DOM Node/Element (document.createElement('div') for example) or a lit-html TemplateResult. I’m happy to accept feature requests or contributions for other templating methods, as long as they are not locked behind a compilation step. You can always pre-render with whatever tool or engine you like, and pass the DOM node.
Delete your index.html inside the template folder.

Edit the index.js:

console.log("Hello, <%= participantName %>");

export default `<h1>Hello <%= participantName %></h1>`;
Enter fullscreen mode Exit fullscreen mode

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

npx cwk scaffold
Enter fullscreen mode Exit fullscreen mode

Then restart the cwk server:

npx cwk run
Enter fullscreen mode Exit fullscreen mode

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:

export default `<h1>Hello Bob</h1>`;
Enter fullscreen mode Exit fullscreen mode

to:

export default `<h1>Hello Bob!!!!!</h1>`;
Enter fullscreen mode Exit fullscreen mode

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

At this point, 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?”.

Instead of using Live Share’s shared terminal feature and giving all your participants a separate terminal with full access on your machine, I created a more safe and user-friendly way of aggregating terminal output, which is the most common method of “output” for backend. 

The workshop host has control over which command gets run in each participant’s root folder, and just re-run that command when files are changed. 

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:

export default {
  appTitle: 'Welcome to Joren\'s Backend Workshop',
  participants: ["Joren", "Bob", "Alice"],
  target: 'terminal',
  targetOptions: {
    cmd: 'node index.js'
  }  
};
Enter fullscreen mode Exit fullscreen mode

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

const readline = require("readline");

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

rl.question("Hello <%= participantName %>! Where do you live? ", (country) => {
  console.log(`You are a citizen of ${country}`);
  rl.close();
});

rl.on("close", () => {
  process.exit(0);
});
Enter fullscreen mode Exit fullscreen mode

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

npx cwk scaffold -f
Enter fullscreen mode Exit fullscreen mode

And rerun the cwk server:

npx cwk run
Enter fullscreen mode Exit fullscreen mode

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.

Participant Bob's view of code-workshop-kit for backend, inside the browser

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. 

The code is open-source, which I think is fair given that I build on top of existing open-source projects. I also want to reach as many teachers as possible and I 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, as it directly impacts my work as a trainer. 
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 (thanks Jonathan Carter and Filisha Shah).

  • 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.

Latest comments (2)

Collapse
 
ludovicdubois profile image
Ludovic Dubois

Hi.
Very interesting. However you said participants were ashamed to answer your questions but now you show their source code and output to everybody. Do you think it is really better?
I want to know if there is a mode, like in a classroom, where the host sees everybody output/source code, but participants see only their own.

Thanks again. It seems a very interesting product.

Ludovic.

Collapse
 
jorenbroekema profile image
Joren Broekema • Edited

Hi, good remark!

My answer is yes, I really think it is better. Let me explain.

The difference is that before, they would have to "broadcast" actively, meaning their screen is the only shared visual in the call, it kinda grabs the attention from everyone and puts them in the spotlight by themselves, to show their failing code.

With Visual Studio Code's Live Share, everyone's code is broadcasted simultaneously, in a more passive way. This puts everyone in the same "spotlight", which basically means no one in particular is the area of attention when they have an error.

What also happens a lot is that I see an error or I see someone who is lagging behind a bit, and I quietly check their code and plant a comment in it to help them out with a hint if needed. This is actually one of my favourite interactions in my remote workshops: when I am live commenting and assisting in their files and we almost have a chat in code comments. My participants, so far, respond really well to that compared to asking them to share screen to show where they are struggling.

Hopefully my answer makes sense!

Edit: forgot to respond to your question about the classroom mode where the host sees all, and participants see only their own code. This is currently not possible, because of the limitations of the Live Share extension which cannot hide files based on participant ID or similar, but it's something I will bring up with the Live Share team for sure, as I get this question a lot. From the output side of things, it's quite easy to hide files based on which participant is requesting them. I actually had that working already but disabled the feature until it's also possible from Live Share perspective.