Skip to main content

· 7 min read
Jeff Gonzalez

I've been providing instructor-led classroom training for software developers, off and on, since about 1996. Most of that time has been me, physically in the classroom, standing in front of a bunch of eager developers, face-to-face.

From the point of view of the me, the instructor, there are some really great advantages in this type of training. The biggest is the ability to monitor, largely subjectively, the "vibe" of the students in relation to the material that's being presented. Facial expressions, the sounds of typing (or not typing!), etc. provide clues as to the level of engagement from the students.

For the students, there is also a bit of a panopticon effect. They are a part of something. They can't just get up and wander off (though I've seen it happen!) without the subtle judgement of those around them. Drifting off and doom-scrolling a social media site instead of paying attention would most likely draw the eyes of those around (or behind you).

Early on, in the transition to fully remote training at the onset of the pandemic, I experimented with requiring the students to have their webcams on for all or a portion of the course. While it did help me, as the instructor, a bit in terms of some subtle feedback, it was awkward at best.

Having a webcam inches from your face, while you look at a Hollywood-Squares style grid of all your students live, directly at their mugs does not replicate the classroom experience.

Some students really pushed back on this. Many had the resources to create a private area in their home for work and training, but others were sharing space with other family members. Artificial backgrounds in Teams or Zoom meetings help with this a bit, but also push the whole thing further into a distracting uncanny valley.

For many, it is just very uncomfortable. A scratch of the nose in the classroom would be largely unnoticed, but when the camera is focused on your face? No hiding.

As the instructor, it would be hypocritical if I didn't also have my camera on. Sometimes I do - if I'm presenting material, like a PowerPoints, etc. When we are coding, though, the presence of my face is really just a distraction from the material being presented (through screen share, etc.) Mostly, though, I find it really distracting to be staring at my face as I teach.

There are some instructors that insist on students having their cameras on for the duration of the course. I'm not going to try to assume their motivations completely, but I'd imagine that some of it is a desire not only for the feedback, but also a sort of authoritarian move. Let me explain.

As a contract instructor, your job is to fill gaps. Students are sent to you because their job requires them to have a set of skills they are lacking. The dynamic is a weird though. Any programming class I teach has to assume some commonality in the skills and experience of the participants. While these are usually listed in the "prerequisites" section of the course description, those are often either ignored, or, I find, students (and managers) have a challenge in trying to assess the actual skill level of developers in regard to those prerequisites. My job as an instructor is often very limited by this. If there is something that is a prerequisite for the class, and the student finds during the class that they didn't accurately assess their skills in this area, they have a few choices.

  1. Go off on their own during the class and start Googling like hell to figure out what it is I'm talking about. The problem, obviously, is that I'm unaware this is happening and just naively keep going, and the student falls further and further behind.
  2. Shut down completely. Some students reach a critical mass of "the things they just don't understand" and just stop participating in the class.
  3. Ask me. This is the hardest one for many students, but is usually the best option. Usually they are just missing a small piece, some little thing I can take a moment or two to explain and they'll be right on track.

The problem with #3 is if I'm with a group of students and this becomes the major thing in the course, then I run out of time to deliver the material I was contracted to deliver (and what the students that astutely assessed their skills in relation to the prerequisites need).

This isn't something that is solved through forced camera usage. However, the second item listed - just shutting down - has been a real problem. I run my classes largely on virtual machines shared with the students. I can see the number of hours and minutes they have actually used the VMs during the class. More than once I've discovered at the conclusion of the course that one or more students used their VMs for only an hour or two in a 21 hour course. "Fine", I might say. They will not be able to produce the work they should be able to produce after the class is over, and their karma will come due. However, they get to evaluate the course, and therefore, me. They go back to their teams, I imagine, and are asked how the training was and they say "It sucked. Didn't learn anything". And they can prove it because they can't do anything.

While there will always be a certain percentage of people that sort of fake their way through their jobs to some level, and see training as a few "days off" - and remote training, like work - provides too many opportunities for distraction - I think the real issue here is the assumption of a sort of mono-culture of skills and knowledged in group training.

If a company thinks they are providing adequate training for their developers by just offering instructor-led training they are failing..

It sets up a bad dynamic where the students come to expect that "whatever I need to know to do my job will be delivered to me in the form of a class", and project managers who think that no matter the challenge, a class or two will get their developers up to speed.

Students that work for companies like this often really struggle in class because it becomes a somewhat self-fulfilling prophecy. They feel "If I don't get this - ALL of this - now, I won't get it anywhere else."

That feeling that "As soon as I'm done with this class I'll be expected to apply this to code for a multi-billion dollar company" is overwhelming. It would completely paralyze me.

There has never been a decent class I've taken where I understood absolutely everything that was presented. A good class often leaves me with way more questions than when I came in. If I had some weird consumerist view that made me think this was a problem, that my needs weren't being met, I would never have gotten anywhere.

Good training courses should be followed up by mentoring by trusted associates. It should involve low-stakes application of the concepts from the classroom. It should include an honest assessment of the developers skill or knowledge gaps discovered as part of the training, and a plan to help them fill those gaps.

If you come to a three day class where we spend <1 hour doing things at the command prompt, for example, and you've never done that before, no amount of explanation that I can fit into the classroom is going to fill that gap for you without hijacking the entire class. If you are in a mindset that says you have to understand all of that or you are done for, there is something wrong with both the culture of where you work and your own approach to developing your own skills. Fake it (in class). Ask a question or two if you can, but make a note to get some resources on this - to learn more. A big part of any education is helping you identify the things you don't know, and not always providing you that information on a silver platter

My courses are a mixture of lecture/demonstration, discussion, "code along with me" work, and practice exercises/labs.

· 6 min read
Jeff Gonzalez
tip

Note, for some example Dockerfiles, See /docs/back-end/dockerfiles

When you run applications on servers in production, the safest way is at a minimum one server per application. That way that one application has little opportunity to negatively impact any other applications on that machine. Use up all the memory, the hard drive, access stuff it shouldn’t be accessing, etc. That would be awesome. And with unlimited resources, maybe a good way to do it. But wow would that be expensive!

Virtual Machines

Another way to do it is to take a single server and run multiple isolated operating systems on it. “Virtual Machines”. However, that isn’t a great use of resources, either. Each of those Virtual Machines (VMs) are heavy, and don’t scale well. Imagine your desktop with five copies of Microsoft Word running. Now imagine your desktop with five copies of windows running, each running a single copy of Microsoft word. Kind of like that.

Linux Containers

So, the Linux folks figured out a happy medium a while ago. This is something that is baked into the heart of Linux (the “kernel”) called namespaces. It’s a way to segment a machine so that software running in different namespaces can be lied to. Each namespace can be told to “report” it has X amount of RAM, Y amount of processor, access to this particular disk mount, etc. To the applications living in a namespace, they are blissfully unaware that they are living in a little glass jar inside of a much bigger universe. They can’t see their neighbors, and they can’t ask for more than they are allotted.

Linux Namespaces are awesome. They aren’t easy. And they don’t really have much in the way of affordances to help developers define and install them. As a developer, you basically deliver your code to the production people, and, if they are into it, they can define a namespace for your app. They will set limits on its resources. It’s considered none of your business really.

If you want, the Wikipedia article is pretty ok about this. Read about Linux Containers.

Well, part of the whole DevOps revolution is that this disconnect between the people that write the code (Devs), and the people that make it run reliably and securely (Ops) just doesn’t work in practice. Not well. It served us for a while, maybe, but we’ve outgrown it. What if the Ops people don’t give us the correct amount of resources for our application? What if we are sending them new versions really quickly, and they become the bottleneck? The Operations folks have done glorious work over the decades of letting developers live in ignorant bliss about things like security, reliability, dependencies, all that. It turned into a game of virtual Battleship. We’d keep making guesses until we’d sink their carrier, and them blame them!

Enter Docker

Docker was created as a way for us to responsibly close that gap. As part of our applications deliverable, we will, in pretty simple terms, define exactly what we, as developers, need for this application to run. What dependencies, what networking access, memory, disk, all that. You do it in a pretty abstract way. Like “I wrote this assuming this can have TCP port 80. And that I can write to a directory called /etc/mydata, and I think I can run with about 2 GB of ram, but might need up to 4. And oh, I run on this version of Linux, and need these other things installed. I need some linux utilities, like curl, I need NodeJS (or .NET Core 3.1, or Python, or whatever). And - oh, the data I need lives on or corporate database, so I’ll need a connection to that. Now, you could just put this in an email or something. A set of instructions for the Ops people to follow when configuring your namespace. As you can imagine, this might create a lot of back-and-forth. Lots of Teams meetings. Lots of mistakes. Docker lets you specify all that, and then actually run it in an exact replica of how it will run on their machines. Instant feedback! Run your tests against it! Debug into it! Do a tiny bit of load testing on it to see how it behaves. Docker builds a container image of your application that you can run which means the difference between your environment and the production (or test, or qa, or compliance, or whatever) environment is almost completely eliminated. No more “It runs on my machine!” Problems. Remember, DevOps is about confidence. What can we do to increase the confidence that the code we produce will work as designed when it gets in front of a user. This is huge.

Somewhere near the end of your developer pipeline, the instructions you wrote on how the container image should be constructed (the Dockerfile will be used to build the container image that will move to the next environment. It would be pretty creepy if you hadn’t actually tried it before you shipped it, wouldn’t it.

You must be able to run and verify your container images locally if you are going to sign off on them going to the next environment.

So, let’s be responsible. If you aren’t running your containers locally, running your tests against your containerized applications, verifying them for yourself in front of God and your team, you’ve kind of short-circuited the whole inspiration behind all of this stuff. You are still saying “hey, running code in production is your problem, not mine!” And you are missing the point.

And if you are creating something that you feel you can't run locally in a container in a meaningful way because it is "too big", or "has too many dependencies on outside things" - that are all huge red flags about your architecture that are being shown to you. Don't sweep this feedback under the rug!

Kubernetes and Containers

Modern Kubernetes runs containers. For a long time it used the same Docker application we use on our developer machines to run those containers. But Docker not only runs containers. It builds them. It has an API. It works as a mini container registry on your machine. In other words, Docker is kind of a monolith. Kubernetes only needs to run them. So now it just has the stuff to pull down those container images from your registry at the end of your pipeline and run them.

· 2 min read
Jeff Gonzalez
Lee Cooper
Jamie Mitch

We are just figuring this stuff out.

Here's the story. The three of us (Lee, Jamie, and Jeff) are friends, and we talk about programming, and we do some programming together.

We've collaborated on a few things, we set up a Discord for just us, and we found that even when we aren't working together, that learning together is fun, and we learn more than if we are just trying to learn on our own.

In a very informal way, we started having some discussions about what we are working on, but not just in a "hey, I found this code works better than this!" sort of way, but also we started to have discussions at a slightly higher level. By bouncing our personal practices off of each other, by sharing our experiences of what has worked well, and - maybe more importantly - what hasn't, we were really accellerating our own learning and our ability to deliver high-quality code.

We decided to start this site, open up our Discord Server and we are going to use these to share our experiences, and to share our thoughts on programming, and to share our thoughts on learning to program. And most importantly, to create a community of people what are working as software developers to practice continual learning and improvement.

We are going to try to keep it informal, and we are going to try to keep it fun, and we are going to try to keep it interesting.

We want you to join us. Here, at the Discord server, and join our conversation. You can ask questions, you can share your own stuff, and you can just hang out and listen.

Let's see how this goes!