🚀 Black Friday Sale starts early for our new Rails 6 Course — 40% off now!
Developing With Elixir/OTP
Build a complete Elixir/OTP application from start to finish
Put Elixir and OTP into action as you build a concurrent, fault-tolerant application from scratch in this 6.5-hour video course.
If you're new to Elixir, you'll get step-by-step guidance in an engaging format you won't find anywhere else.
If you have experience with Elixir, you'll gain a deeper understanding of things you've been taking for granted and fill in any knowledge gaps.
“This was by far the greatest single course I've ever watched start to finish (it was just that good)! This course sets the bar like none other.” Toran Billups
“This is the best Elixir material I've used... It really cemented my Elixir knowledge and I feel much more comfortable in my Elixir role.” Sergio Tapia
“I've been working with Elixir for two years now but never had the need to dive into OTP much. This course absolutely exceeded my expectations. Building up a web framework from scratch was quite an eye opener. I only wish I took it sooner!” Chase Pursley
“I loved this course! It really hit the sweet spot of teaching me Elixir and OTP. Building a web server from the ground up really helped me to understand how Elixir apps fit together.” Michael Twomey
Build a Real Elixir/OTP App with Real Code
Master functional programming the Elixir way and demystify the power of OTP.
You can do a bunch of cool stuff with the Elixir programming language, from building web apps using the Phoenix framework to embedding code on networked devices. But first you need a solid understanding of all the fundamentals.
In this course we build an HTTP web server step-by-step from scratch. By developing a real app with real code, you'll gain practical experience putting all the pieces together to craft applications using Elixir/OTP best practices. Working in the context of an application, we explore real-world scenarios for:
- pattern matching
- multi-clause functions
- recursion and lists
- concurrent processes
- asynchronous tasks
- external Elixir libraries
- built-in Erlang libraries
- OTP GenServers and Supervisors
The first half of the course focuses on core Elixir facets, principles, and techniques. In the second half, we focus on what sets Elixir/OTP apart: concurrent processes, the actor model, OTP behaviors, and fault recovery.
By building an application incrementally and progressively using facets of Elixir/OTP to accomplish specific goals, you'll gain a deeper understanding of both the how and the why of Elixir/OTP app development.
Learning this way makes everything "click"... and it's more fun!
36 Concise Videos • 56 Exercises • 6.5 Hours
Just the way you like 'em: easy to digest, straight to the point, paced just right.
This course takes a project-based approach, so you won't find a course module such as "Elixir Strings". Boring! Instead, we incrementally add new features as we build out a complete Elixir/OTP app from start to finish.
Welcome! After taking a peek at the type of app we're going to build in this course...
...we'll help you get your development environment set up so you can start coding Elixir.
Elixir has conventions for organizing projects and great tooling to automate project tasks using mix. We'll get a quick lay of the land, learn various ways to run Elixir, and jump right into code!
Our web server will make three high-level transformations—parsing, routing, and formatting a response—with each step being a function.
We'll set up an initial pipeline using modules, named functions, strings, maps, and the pipe operator.
4. Parse the Request (10:21)
To transform a request into a response, we first need to parse the request string into a more usable data structure. This presents a great opportunity to learn the match operator, atoms, pattern matching techniques, and built-in functions.
5. Format the Response (6:40)
Formatting the response string takes us deeper into Elixir maps and introduces us to programming with immutable data, which is a hallmark of functional programming.
6. Route Multiple Requests (6:28)
In Elixir you don't use conditional expressions as often as you would in imperative languages such as Ruby. Instead, it's more idiomatic to control the flow of a program using function clauses and pattern matching.
Routing HTTP requests gives us an ideal context for learning how to design code in this declarative style.
7. Request Params and Status Codes (8:45)
Designing a web server presents interesting scenarios that let us explore many of Elixir's features.
How do we handle a request that has parameters? What happens if a route doesn't match? And how should we respond? The solutions require more pattern matching techniques and multi-clause functions.
8. Rewrite Paths and Track 404s (9:31)
Once we have requests flowing through a pipeline, we can plug in specialized functions that transform requests and responses in unique ways.
By pattern matching maps we can run these functions conditionally—a powerful techniques that's used extensively in Elixir applications.
9. Serve Static Files (11:27)
Even something as familiar and straightforward as reading a file involves pattern matching.
Serving static files, and properly handling successes and failures, introduces us to tuples and case expressions.
10. Module Attributes (3:01)
Sometimes you need to attach metadata to a module, be it for documentation or to squirrel away a compile-time constant.
In this section we use reserved and custom module attributes.
11. Organizing Code (6:30)
Modules let us organize functions with similar concerns in a namespace. We'll group related functions in properly named modules, put them in separate files, and knit it all back together using aliases and imports.
12. Modeling with Structs (11:09)
One of the benefits of modeling our request/response conversation as a struct (as compared to a generic map) is we can ensure that the functions in our pipeline always get the expected type.
In this section we compare structs vs. maps and refactor our design to use a struct.
13. Handle POST Requests (10:32)
Handling a POST request means we have to take into account the list of request headers and the POSTed parameters. To do this, we'll process the request by matching head and tail patterns: a technique used pervasively in Elixir apps.
14. Recursion (13:17)
Recursion makes Elixir go 'round and 'round. You've no doubt seen simple examples of recursion, but what about real-world use cases? Turns out, recursion is exactly what we need to parse the HTTP headers in our POST requests.
And while Elixir has convenience functions that often let you sidestep using recursion directly, Elixir pros know how to use recursion to their advantage.
15. Slicing and Dicing with Enum (22:16)
You'll find familiar high-order functions in the Enum module for transforming data. But to use them effectively you need to be comfortable with anonymous functions and how to capture functions.
We also put guard clauses to good use as our application begins to take the shape of a familiar web framework.
16. Comprehensions (11:15)
Now it's time to generate dynamic content by reading and evaluating template files. We make quick work of this using comprehensions to "loop" through collections of data and generate HTML.
17. A Peek At Phoenix (13:12)
Since Elixir is the language you use to build Phoenix web apps, a peek at a Phoenix app reveals a lot of familiar syntax and design concepts. Alas, you discover there really is no magic after all!
18. Test Automation (15:20)
It's time to automate with ExUnit tests! We look at two different ways to write unit tests, and various ways to run them.
By the end we have green dots across the board.
19. Rendering JSON (06:49)
To build a JSON API, we install an external JSON library and use it to render JSON and handle POSTed JSON data in response to API requests.
20. Web Server Sockets (19:11)
Now that we have a fully-functioning HTTP request handler, it's time to write a TCP socket server so that any HTTP client can interface with our application.
To do that, we use Erlang's gen_tcp library and learn how to transcode Erlang to Elixir. Cue the browser!
21. Concurrent, Isolated Processes (22:28)
At this point our web server can only handle one request at a time. We need a way to handle multiple requests concurrently and also isolate the failure of one request so it doesn't affect other requests.
Concurrent, isolated processes are what set Elixir apart from other functional languages! We also look inside the Erlang VM to see how it takes full advantage of multicore computers to achieve remarkable levels of concurrency and parallelism.
22. Sending and Receiving Messages (19:38)
So if processes are isolated and run concurrently, how do they communicate? Just like people! They send asynchronous messages to each other.
In our app, we spawn a series of API requests that run in independent processes. They send back their results as messages to be received by the request-handling process. We also look at how to avoid unwanted synchronization points in our code.
23. Asynchronous Tasks (20:19)
With several one-off asynchronous tasks now running and getting results at a later time, we're starting to see a definite pattern. In fact, running functions (or tasks) in a short-lived process is so common that Elixir provides a helpful abstraction: the Task module.
By the end you'll know how the Task module works under the hood.
24. Stateful Server Processes (38:52)
Now we turn our attention to long-running server processes that manage internal state and respond to various messages. We build up from a basic receive loop to a client API that sends synchronous and asynchronous requests to a registered server process. Along the way, we see how a server process preserves the integrity of its state while under load from multiple concurrent client processes.
By writing a server process from scratch, we begin to demystify the "magic" of a GenServer.
25. Refactoring Toward GenServer (21:12)
Looking at our stateful server process, we see two flavors of code: code that's common to all server processes and application-specific code.
So what happens when we move all the common code into a generic module? Well, we're not the first ones to have that idea! GenServer is a design pattern (an OTP behavior) that helps us write server processes with greater ease. By refactoring our server process, you'll come away with a better understanding of how (and why!) GenServer works.
26. OTP GenServer (16:57)
When you're starting out with Elixir, writing a GenServer can be confusing and it's tempting to just cargo cult from example code. But we want you to feel really confident, so we've been incrementally building up to using a GenServer. Spoiler alert: Now that you understand the underlying design pattern and how it's implemented, actually using a GenServer is a snap!
Besides converting our app to use a GenServer (and eliminating a bunch of code!) we also add new application-specific behavior to our GenServer.
27. Another GenServer (9:00)
As another practical example of when and how you'd use a GenServer in a real application, we write a server process that performs background work on a periodic interval.
This lets us explore the power of the handle_info callback in greater depth so you can take full advantage of all that GenServer has to offer.
28. Linking Processes (13:38)
At this point we have three server processes that should run continuously without missing a beat. Alas, things don't always go according to plan! We need a way to monitor the server processes and recover when trouble strikes.
To do that, we start by linking processes, which is fundamental to understanding how the OTP Supervisor behavior works.
29. Fault Recovery with OTP Supervisors (19:52)
Normally, designing an application that's resilient to failures is a tall order. With other languages, the best you can do is to code defensively. Elixir is different: it frees you to "let it crash." That's only possible because OTP Supervisors offer unparalleled support for detecting and recovering from process failures.
Indeed, Supervisors are the key to building high-availability, fault-tolerant systems. We design a supervision tree so our application can elegantly recover from unforeseen failures.
30. Final OTP Application (15:22)
Up to this point we've been using the term "application" fairly loosely. But an Elixir application is a first-class OTP entity. We look at how an application works behind the scenes, and then specialize the OTP Application behavior to start our supervision tree.
We also configure the default application environment. In the end, you have a complete application designed the Elixir way!
For Experienced Developers
Because this isn't your first programming language.
To respect your time in the videos, we assume you have project-level experience with another programming language. However, we don't assume you have any prior experience with functional programming or Elixir.
We aim for 100% satisfied developers, so if this course turns out not to be a good fit for you, we'll gladly issue you a 100% refund.
Why should I learn Elixir?
It's smart to question why you might need to add another programming language to your repertoire. Here's the thing: Elixir isn't just another programming language. It's unique in that it's built on the Erlang VM which has a long, proven track record of powering concurrent, distributed, and fault-tolerant systems. Elixir gives us the joy and productivity of Ruby with the concurrency and scalability of Erlang.
Do I need this course if I already know Elixir?
If by "know Elixir" you mean you've read a book and perhaps experimented with some code, then we think you'll get a lot of value seeing how to build a complete app from scratch. Folks often say our courses help them fill in gaps in their understanding.
If you're using Elixir but haven't tapped into the power of OTP, then this course will demystify OTP so you can advance to the next level. Many reviewers of this course say it finally made OTP click for them!
If you're using Elixir and OTP in earnest on a project and feel confident, then frankly this course may be too introductory for you. Then again, it's always helpful to see other examples of Elixir and OTP in action. And you just might discover one tip, trick, or explanation that makes it all worth it!
Will I learn the Phoenix framework?
Sorry, not in this course. Elixir is a functional programming language with a fairly steep learning curve. Phoenix is a full-stack web framework built on Elixir. Trying to learn Elixir and Phoenix at the same time is a recipe for confusion. The good news is once you're comfortable with Elixir, learning Phoenix is an incremental step that's a lot easier to take.
Created by Mike and Nicole
Hi, we're real people just trying to share our passion for creating stuff!
Many of you have emailed and tweeted us about an Elixir course. We did a lot of head-scratching coming up with a good way to teach Elixir. We didn't want a referency, syntax-focused course because, well, those make us fall asleep. Instead, in this course we'll actually build something with Elixir. We'd love to have you join us in the Studio for this great course! Find out more about us…
Many thanks to Scott Thompson, Clinton De Young, and Nathan Herald for taking the time to review early drafts of the OTP sections. Your insights and suggestions based on hard-won experience with Elixir/OTP were instrumental in the design of this course. We really appreciate it!
What developers like you are saying about this course:
“I loved everything about this course, especially how you build out the behavior provided by the OTP library in order to understand what is happening underneath the hood. It was very useful in order to grok GenServers and Supervisors. Over the years you have helped me progress in my career as a programmer. I don't know where I would be without your courses. Thank you so much! Please carry on!” Gabe Lafontant
“Learned a lot from the pragmaticstudio [Elixir course] and couldn't recommend it highly enough.” Ralph Bankston
“I'm so impressed with the @pragmaticstudio Elixir course. They show you how to build parts of Phoenix/OTP rather than just how to use them. [The course] is also great for learning best practices for designing and refactoring Elixir APIs. The @pragmaticstudio Elixir course is worth much more than the purchase price. If you want to get deeper into Elixir, you should own it! Really awesome learning experience!” Tweets from Bill Peregoy
“The way you built an application piece by piece worked really well. This is my favorite way to learn a language, and building an HTTP server was an ideal project for learning Elixir's full range of capabilities. This is one of the best video courses I've ever seen!” Kim Godard
“I've read almost 3 books on Elixir yet this course taught me small tricks that I didn't know before. I attribute that to the realistic project that is being developed throughout the course instead of the typical book-style teaching in which the language features are presented almost like documentation. This course is taught with just the right amount of detail and speed, and the realistic example project really helps to solidify the concepts being taught. The course notes are well thought-out and thought provoking in that they anticipate questions a developer may have which extend naturally from what is being taught, especially questions like 'could I do this a different way?'” John Joseph Sweeney
“The course was great! I'm starting on Elixir (coming from Ruby) and the course helped a lot. Awesome work! It's worth every cent and, most importantly, every second spent watching it!” Franco Catena
“The @pragmaticstudio course on Elixir/OTP is excellent. They walk you through creating a lightweight version of the Phoenix router, controller, view & templates... so you gain a better understanding of how @elixirphoenix is built. Highly recommended.” Nathan Hopkins
“Loved the Elixir course! Amazing flow! I really loved how you took the time to explain things that matter (without glossing over small details) and that we basically built GenServer from scratch. This gaves me a much much better understanding of how Elixir/Phoenix works.” Edison Yap
“@elixirlang is the coolest tech I've using lately. Not 100% sure if I find it more enjoyable than Ruby, but mind blowing idioms + so fast. Best I've found to learn is the course by @pragmaticstudio...project-based always works better for me.” Steve Corona
“What a fantastic job you've done with the Elixir course. I was a little reticent at first to buy the course because I've been doing Elixir for almost 4 years now, including a couple of production apps, but I needn't have worried. I was soon picking up things that had passed me by. Before long I was starting to deeply understand things that I'd been kind of taking for granted like processes, tasks and now GenServers. The way that you start off with plain ol' Elixir and build up to the point where we need the things that you are explaining is brilliant! The way you introduced GenServers in particular is perfect.” Alan Gardner
“Excellent explanation of Elixir and OTP concepts” Jørgen Orehøj Erichsen
“I really loved the explanation of the various parts of OTP / Tasks / etc. I've been trying to wrap my head around GenServer, Task, Agent, and Supervisor. This course finally made these things click for me! I especially liked the way you made your own variant of GenServer first and then moved from there to using Elixir's version. At that point it finally dawned on me that it's all just functions, not magic!” Jacob Atzen
“I really enjoyed this course and will recommend it to any budding or experienced Elixir devs. I liked the project-focused lessons and the pacing of progression through Elixir fundamentals within the context of building an app. The animations were great and really served the course explanations well. And the sections towards the end dealing with Tasks, Agents, GenServers and Supervisors were all excellent!” Paul Fioravanti
“Really enjoying the @pragmaticstudio Elixir course. It doesn't waste any time. The notes add extra interesting tidbits and the exercises allow me to practice. I also like that the main thing built is a web server, which gives some insight into Phoenix. Highly recommend!” David Tang
“I have done all your courses, but I think this is the best one, which is quite staggering as all the other courses were top-notch, too. I liked how you unpacked existing libraries and especially the Phoenix framework. It was a wonderful experience to see how all the things you carefully set up came to together. Also, the notes were not just summaries but contained so much valuable extra information. So well done!” Johannes Rubenz
“Awesome work! Definitely the best resource that I've found on Elixir. Can't wait to start the next course!” Nathan Queija
“Really well done course! The recursion explanation was the best example I've come across for us newbs. I like how it was built step-by-step with output, never rushing the discussion.” Dan McHarness
“Even though I'd used a bit of Elixir / Phoenix before, it was super helpful to build these Elixir features from the ground up in your course. I got a much better understanding of how things work under the hood. Your attention to detail is unparalleled and the course was engaging and fun. Thank you for the great quality course..” Eleni Lixourioti
“Thank you so much for this course! I loved the graphics that were used to introduced concepts, the practical examples, and how it all demonstrated the features of Elixir in a way that removed the magic surrounding things like supervisors, GenServers and routing that is used in Phoenix.” Brendon Otto
“I've stuck my toe in Elixir before, but this course really made it click for me. I loved that everything was built from the ground up. So rather than simply saying, "Here's what a GenServer is and how it is used" we built our own version - running into problems, coding solutions, and eventually understanding the entire thing. Then, it was just a matter of moving it over to GenServer. I feel much more confident that I could jump into Phoenix now that I understand Elixir and OTP better.” Josh Cochran
“This is one of the best courses I have taken in my life! It's concise and covers the most important topics about Elixir and OTP and has a lot of exercises. The notes are fantastic and the instructors are so captivating, with a great chemistry between them. What a pleasure it was to take this course!” Francisco Breno Barbosa Soares
“The flow of this course was very well thought out, and the material was presented at a pace that was just right. Mike and Nicole did a great job avoiding tangents and minutia while still conveying the necessary information. I’m very pleased and glad I bought this course!” Ed Barstad
“I am a Pragmatic Studio alumn and have always thought the quality of their courses is top notch! Mike and Nicole's style is really friendly, welcoming and easy to follow. The pace is great with short videos that tackle one thing at a time. Very much like functions (wink).” Miguel Barcos
“I liked everything about this course: it was well organized, well paced, interesting, and fun!” Kevin Shank
“The material was presented in a really well structured way so that learning was gradual. I particularly loved hand-rolling the GenericServer before revealing that it was pretty much a GenServer, thus increasing understanding and making GenServer less magic. Everything was well-paced too!” Ben Booth
“What I liked best about this course was that we built our own implementations first, before using the built-in Erlang/Elixir solutions. Keep on making awesome courses and I'll keep buying them!” Bas Bloembergen
“I have been taking courses with The Pragmatic Studio since 2006 and I'm always amazed by the careful attention to detail that's displayed throughout all their coursework. I really like the animated diagrams and code examples throughout this course. Mike and Nicole totally knocked it out of the park for me! Thank you for being truly awesome educators throughout my educational journey.” Conrad Taylor
“I really like how you built up the different parts of the language piece by piece, dispelling the magic, whether that was a web server, Phoenix, or a GenServer. You are phenomenal teachers! Thanks for sharing your gifts, your passion, and your knowledge.” Monte Johnston
“I had heard good things about The Pragmatic Studio before taking the Elixir course, but now I know for myself that you two are top notch educators. Things were spaced out just right to help "exercise" my memory. I just absolutely loved the course. I don't think it could have been better.” Levi Kennedy
“Fun afternoon learning some functional programming with Elixir. Wonderful course from @pragmaticstudio. Highly recommended.” Ed Wallitt
“The content was well paced for someone like me with plenty of experience as a developer coming to a completely new paradigm. Your lightness of touch and humor make the material really appealing. I also really appreciated the way you hand-rolled a task or a generic server before going on to demonstrate the implementations in the standard library. That really helped to demystify these most "magical" of aspects of using Erlang/OTP/Elixir.” Dan Bye
“I jumped right into Phoenix but I was glossing over a lot of the details of how things worked, which proved troublesome later on. I now have a strong understanding of Elixir and OTP. Thank you! I can't wait to get started with my own project!” Tom McGurl
“If you want to learn Elixir in a practical way, I strongly suggest the @pragmaticstudio course. Definitely the best online course.” Bruno Dusausoy
“This is the best Elixir material I've used. You build a simple HTTP server using Elixir and learn a lot of the core language and architecture choices when writing Elixir code. It doesn't pester you with 'this is an int, this is a string.' You just start building this HTTP server out and learn about Elixir along the way. Thanks Mike and Nicole for writing such a tremendous course! It really cemented my Elixir knowledge and I feel much more comfortable in my Elixir role.” Sergio Tapia
“I love the pace. It feels more like a series of really good pair programming sessions with a mentor and less like a lecture.” Hunter Stewart
“This course by @pragmaticstudio cleared everything up for me 😀 ” Omar Bahareth
“I really enjoyed the thoroughness of your Elixir and Rails courses. I think you guys have the best programming courses on the web. Your explanations are consistently clear, the pacing is excellent, and I particularly appreciate the way you focus on conceptual understanding and orientation, rather than just rattling off how to do something. Thanks for offering such great training” Haiz Oppenheimer
“I loved everything about this course...the project-based approach, the realistic project in terms of technologies and choices, and how we built out things that also taught us how Phoenix worked. This course demystified a lot of things, and made approachable a lot of different concepts. Simply put, amazing work! I feel comfortable now looking at Elixir as a solution to problems. As a pair, you two do a great job. Hurry up and make more video courses! I'd serious learn a new language just because you two teach it.” Jason Lotito
“great elixir course! #myelixirstatus” Arif Yayalar
“I love the clear explanations as well as all the diagrams— they've helped me tremendously! The section on Sending and Receiving Messages in particular is wonderful.” James Schorr
“Superb job! The course has been very thoughtful in creating problem situations that iteratively lead to an ideal solution, with the benefit of helping the student understand the rationale (the "why and how") along the way. The experience has been fantastic!” Yong Bakos
“This course was awesome! In other courses, I just learn how to use Phoenix, GenServer and Supervisor like magic. Here I've learned the foundations, how those components were built and how it works under the hood.” Maxsuel Maccari
“Building from first principles in this course was very helpful. Solid course!” Kenny Parnell
“I liked the depth at which Elixir was covered. So many other tuts just cover the basic entry level things such as types and immutability along with building a toy application (no real world basis). Building the HTTP Sever was excellent because as it shaped up I was like, 'We are building a rough draft of Phoenix.' The real money of this tutorial was from Section 20 on. WOW! I was so impressed with what was covered and the ideas were really churning. This is by far one of the best tutorials I've ever paid for! I’m really impressed with your teaching methods and delivery; keep up the amazing work!” Cody Brunner
“Loving @pragmaticstudio's Developing With Elixir course #myelixirstatus” Kyle Oba
“The web server sockets and the whole OTP themes were amazing in this course! I now have a deep understanding of OTP and behaviors. You are amazing and I can't wait for more stuff!” Felipe Juárez Murillo
“A really fun course, presented stellarly! Your obvious mastery of both the language and tooling made for a smooth-flowing, informative course. The notes at the end of each section are also helpful and enlightening. Loved the course! I've already bought the Elm and Unpacked Bingo courses too. Excellent job!” Ohad Frenkel Keshet
“Want to learn @elixirlang (and you should), then you owe it to yourself to check out @pragmaticstudio. Awesome!” Napoleon Ahiable
“I feel like I have a much firmer grasp of things like process creation, spawning, linking, and how those lead to setups like OTP because of this course (after having read a zillion articles and at least one book already on the topic). I'll definitely be signing up my other developers for this course!” Donald L. Merand
“I have done a reasonable amount of Elixir & Phoenix programming and I’ve started to use OTP a lot more. The way this course builds up everything without Phoenix and goes through OTP step by step is really good! Lots of "gaps" in my understanding have been filled. I really liked the approach you have taken to build up an app!” Steve Forkin
“I absolutely love this course! You have one of the most complete and easy to understand tutorials on GenServers out there. Pragmatic Studio is certainly THE BEST site for online developer training! Thank you for all you both do.” Clinton De Young
“The way you designed this course to reveal the 'magic' behind the libraries is fantastic. The pacing was spot on. One of the best programming courses I have ever taken!” Aaron Graham
“Elixir is an itch I've been wanting to scratch for sometime, but having tried to learn it using manuals or website tutorials, I've not found the experience engaging. This course, however, has been so rewarding! The pace, level of detail, assumption of prior knowledge, and depth of explanation are all perfect. The video quality, font sizing, colour scheme and sound reproduction all add to the quality of the whole course. And your approach of developing a web server app in the course and getting to see how all the pieces fit together is so much more absorbing than trying to learn by writing bite size chunks of unrelated code. Well done!” Tony Sutton
“I love the logical, sequential way you build up an increasingly robust application and explain at each step of the process why things work as they do. Your visuals are thoughtfully crafted to illustrate important concepts. I wish the course hadn't come to an end. I not only would recommend this course, but I bought a 10-person license for my team!” James Lavin