Since we introduced Camunda Platform 8, migration has been a hot topic among Camundi and users. For us, this is an ongoing topic that continues to evolve as we receive feedback from our community and customers, and as new technologies emerge.
On this episode of the Camunda Community Podcast, Senior Developer Advocate Niall Deehan chats with Senior Consultant Manuel (aka Manu) Dittmar and Consultant Jonathan Lukas about the three main pillars of migrating to Camunda Platform 8 from Camunda 7: model migration, business logic migration, and data migration. This is a lot to cover, so we’re breaking it down into two episodes.
In Part 1, Niall has plenty of questions for Manu (aka Manuel) and Jonathan regarding the strategy and practical implementation of migrating models and business logic. We start off discussing a brief history of Camunda 8; our key consideration points including documentation and tooling for helping customers and users migrate; and how the architecture of Camunda 8 better aligns with modern software architecture and service orchestration, creating a much faster workflow and decision engine.
Listen to learn more about:
- [github] Camunda Platform 7 To Camunda Platform 8 Migration Tooling
- [guide] Migrate to Camunda Platform 8 in 6 Steps
- [docs] Migrating to Camunda 8 from Camunda 7
- [blog] What to do When You Can’t Quickly Migrate to Camunda 8
Visit our website.
Connect with us on LinkedIn, Facebook, Mastodon, Threads, and Bluesky.
Check out our videos on YouTube.
Tweet with us.
Camunda enables organizations to orchestrate processes across people, systems, and devices to continuously overcome complexity and increase efficiency. With Camunda, business users and developers collaborate using BPMN to model end-to-end processes and run sophisticated automation with the speed, scale, and resilience required to stay competitive. Hundreds of enterprises such as Atlassian, ING, and Vodafone design, orchestrate, and improve business-critical processes with Camunda to accelerate digital transformation.
Camunda presents this podcast for informational and entertainment purposes only and does not wish or intend to provide any legal, technical, or any other advice or services to the listeners of this podcast. Please see here for the full disclaimer.
[MIA MOORE] Hello and welcome to the Camunda Community Podcast where we discuss things about Camunda like BPMN, DMN, and orchestration topics of all kinds.
I'm Mia Moore, senior technical community builder and podcast contributor here at Camunda. Niall is currently out of the office, enjoying the last remnants of summer, most likely hiding from the sun, and he asked me to cover for him. So I am your podcast host now. Hello!
Before he left on his vacation, Niall chatted with Camunda consultants Manuel, aka Manu, Dittmar and Jonathan Lucas about migration, which has been a hot topic not only among Camundi but also among our community and customers.
Manu leads the migration efforts for our consulting team by defining the overarching strategy and being directly involved in migration projects.
Jonathan does a lot of work with the tooling that helps our customers and community when it comes to actively migrating.
This conversation explores the 3 main aspects of migration.
First, there’s model migration: how do you get your BPMN and DMN models from Camunda 7 to Camunda 8, what kind of things should you be looking out for, and also what kind of tools exist to help you do it. The second is business logic migration. There is a big difference between how Camunda 7 was able to orchestrate business logic and how Camunda 8 does it. So we'll be discussing what those differences are, what kind of things might make for a tricky migration, and what will make a smooth transition, how to spot the differences and again, the tooling that is available.
Finally, we'll be talking about data migration. And if, how, or why you should be migrating your data and what tools exist for that to happen for you.
As you can probably tell, or hear, it’s a lot to cover so we’re breaking this into a two-part series. In this first part Niall, Manu, and Jonathan discuss model migration and business logic migration. Let's listen in.
[NIALL DEEHAN] Manu (aka Manuel), would you like to introduce yourself?
[MANUEL AKA MANU DITTMAR] Yes, Hi! My name is Manu (aka Manuel). I'm a Senior Consultant at Camunda, based in Stuttgart, Germany.
And I'm here today because I'm responsible for the migration topic within Consulting. That means I'm currently quite busy with talking to customers, working on well creating workshops, and yeah, making sure that we have a concrete plan how to support our customer base.
[NIALL] Yeah. And the reason, of course, I brought Manu (aka Manuel) here is because I like someone to blame with any sort of migration issues. And now we have a scapegoat. So that's great. Thanks for joining, Manu (aka Manuel). But also just in case one scapegoat isn't enough, we also have a a second consultant joining us today. Jonathan, would you like to introduce yourself.
[JONATHAN LUKAS] Yeah. Hi, my name is Jonathan. I'm also a consultant, also from Germany–Ingolstadt. And my, my role here today is that I'm one of the contributors to the Camunda 7 to 8 Migration project which we use internally for migration and which is also provided to the community, of course. And at some point we stole it from Bernd and developed it further.
And I also saw that it was heavily used during our our Hackdays. And, yeah, it was in favor of many people. And I love seeing the progress. And of course I'm a bit opinionated about it.
[NIALL] Very well. I love having a very opinionated people. Lovely starting off by stealing things from Bernd. Anyone who does that is a friend in my book. So that's a good start. Thanks, both of you folks for joining now.
Before discussing sort of the the facts around migration, I wanted to start with a little bit of sort of let's call it history, I guess. But let's not start with the dinosaurs. Let's go slightly closer to the present and begin with the original decision-making internally, which I recall quite fondly around what the impact of Camunda 8, knowing its design, would have on Camunda 7 customers. Internally, obviously, we had a lot to consider with all of our customers being on C7. Can you folks talk a little bit about the kind of considerations the consulting team in particular had when it came to sort of taking into account that migration strategy?
[MANUEL AKA MANU] Yeah. I think the baseline for everything is making sure that our customers are well educated about Camunda 8, how it actually works, and that they understand what are the advantages of it, and why we actually made that move. And I think we were quite open about that, no matter if it was in a blog post, in the documentation, or also on presentations.
And of course, making sure that, in the end, we're still doing BPMN, and we're still working with processes, and that it's actually doable to perform a migration.
Also that there is a concrete path that you can follow for the migration. So it doesn't need to be a big bang. You don't need to migrate tomorrow. There's a path that you can follow. And also that's why we are still continuing supporting Camunda 7. And also, yeah, we are, I think, also quite open about feature parity, where we need to have a look at what is still missing in the Camunda 8 context.
[NIALL] Cool, yeah, I totally agree. It was, I think, being open about what was about to happen, and having a long lead-up before anyone needed to make a big decision about changing was really important to that. But also we needed to create a lot more material and collateral. Jonathan, you talked a little bit about some of the planned, let's say, collateral that we actually needed or we recognize we needed around the migration.
[JONATHAN] I think, one of our very big topics today is getting people educated about Camunda 8 in general, regardless whether they are still on C7 or well, whether they gonna start off directly with Camunda 8. So here we we definitely need more. So I think we have quite decent docs already regarding their their age. We still need to figure out which which content is is still relevant for Camunda 8, I think.
For example, in Camunda 7, we gave guides on how to set up the engine on an application server, set up the engine on a Tomcat, set up the engine inside Spring Boot, how to use Camunda Run on like separate distributions which have several technical dependencies.
And this is not relevant anymore for Camunda 8 because of its architecture. Moreover, now it's relevant to know other technologies. For example, Docker, Docker Compose, Kubernetes, maybe OpenShift, maybe AWS which which has a very much broader context nowadays over over Java.
[NIALL] Yeah, I completely agree. Actually, it's one of the main differences the company has moved in when it comes to C8. Initially with C7, it was a Java application that was for Java developers that to orchestrate Java code. That was the first initial goal of C7. It grew a lot. And when the external tasks showed up, you could use it still as an as an orchestrator for internal Java code. But then it became more and more obvious that external services were the way to go. And I guess the problem–what makes migration quite complicated with C7 is the sheer amount of options people had when they were going to use it.
There were so many different technologies, and also it could be a small component within a single microservice, or it could be a huge component within the architecture of the distributed system. You could choose which way to go, which was making it very hard to maintain, but also meant that it wasn't the best at either of those two things.
I think, choosing to to make Camunda, as an engine in the future, be that architectural component meant that Camunda 8 needed to leave behind some of the legacy compatibilities C7 had. So it's, it's nice that we get to address Camunda 7 from a best practice perspective rather than from a “Here's all the things you could possibly do with it.”
The docs you mentioned are important, because I think, before even going into all of the details we will today. It's important to know the by far the most comprehensive part of the docs.camunda.io page is the migration from C7. It's incredibly detailed and gives a lot of really good hints. So if people really want to get into the depth of it. That's a really good place, especially after hearing some of the high-level stuff we'll be talking about today.
So, as mentioned in the intro, there are 3 main components to migration. We're gonna talk about each one, both in terms of strategy and in terms of practical implementation. Those 3, of course are: migrating models, migrating business logic, and migrating data from your process. So those are the, the 3 pillars to migration, and I've ordered them in, I would say, order of complexity.
Modeling is probably one of the easier ones–depending. Business logic is probably the next easiest–again, depending. And data is probably the hardest, no matter what.
[NIALL] So let's kick off with a discussing some modeling migration issues. I want to start with you, Manu (aka Manuel). I'm just interested in, strategically speaking, how do people start? Like what, at what point if I'm brand new to Camunda 8 as a thing. I have a model, I'm now wondering, “Should I migrate? How do I migrate? What kind of, what kind of aspect should I be considering when looking at that?”
[MANUEL AKA MANU] Yeah, so I would start with having a look at the BPMN elements that you use in your existing diagrams. That of course, you could either scan manually or use the tooling in the Community Hub for that, and that already gives you a very good overview of that. First of all, is element even supported yet in Camunda 8?
Or is the element implemented slightly different, like, for example, how messages are being sent, and this already gives you a very good overview. And I think, and it's an area where you are using elements that are not there yet in Camunda 8, it’s totally fine to wait. Our goal is to have feature parity, and instead of doing hacky work around and your BPMN elements, I would just wait. And yeah. But probably make sure to also communicate that to Camunda, that you are waiting for that feature. So we can change the priority for that as well.
And when it comes to how elements are implemented differently, like sending messages, I would have a closer look into the implementation. But quite often that can also be an advantage. If you're not fighting, fighting with message correlation anymore, so you can maybe even simplify other layers of your logic. So, for example, business logic.
[NIALL] I agree. There is one interesting thing about having built a lot of models over the last few years for Camunda 7 is the workarounds we would need to make, based on the very strict implementation of a transaction-based process engine.
Camunda 8 again, is built purely on the backs of the knowledge that we had from Camunda 7, and knowing that it has an internal buffer for messages, for instance. So, in the past, I would have always suggested people to say, “Hey, make sure you're always waiting for a response to your message before you send the message that you're going to send. Otherwise you could miss the response because of the, of the thing.” Yeah, which was not great. But now it's quite nice that in Camunda 8 you have a much more concrete way of being able to expect and send messages without needing to worry about race conditions like that.
I'm also glad you mentioned the feature parity of the symbols. I think it's important to know that if someone says, “Hey, this symbol, like compensation–as of time of recording–compensation is not yet implemented.” Now, while that is a symbol that's not commonly used in a lot of models. It's super handy. It's one of my favorite ones to implement, because it does a lot of work for you without needing much implementation. And it's coming. So that's a nice thing.
And you mentioned for people to let us know. So where do you think, where's the best place for folks in the community to say, “Hey, I've got like I've used compensation on every single one of my models. how long are you going to take to get this done?” Where should people be telling us that?
[MANUEL AKA MANU] With our enterprise customers, for them, they can raise a feature request. But, as far as I know, for Zeebe itself as the engine, they could also just put it in the GitHub repo. Or maybe upvote an issue that exists already. Yeah, just to to let us know.
[NIALL] Yeah, exactly. We do have a public repository for Zeebe. And, in fact, people have implemented, from the community have implemented symbols for us that they really need. I think Signal was implemented, I think, by by the community, and so was the branching OR gateway. So if anyone out there wants to take on the challenge of compensation events–what a what a fun couple of evenings that would be! So yeah, absolutely… and other symbols, of course.
On a more practical sense, looking at, rather than looking at just what you've modeled, Jonathan, can you maybe talk a little bit about aspects of, let's say, the implementation that people have used in a model that might be the kinds of things that would help indicate whether it's a difficult or easy migration for them?
[JONATHAN] Okay, so in general, you can migrate any kind of implementation. So we have a adapter to support delegate expressions, to support delegate classes, to support expressions. and also to support external tasks. So every possible implementation can be migrated. The only thing we do not actively support is Camunda 7 connectors. But they are also not not in favor, and we do not recommend to use them in, in production
Other than that, we recommend to keep the delegates as clean as possible, which means they are only used for data mapping from the process instance to a service call and then from the service response back to the process and for element control like throwing an exception for an incident, throwing a BPMN error to control the process instance, actually. And if you do not do anything more than this, your migration will be quite easy.
[NIALL] Yeah, I was wondering–so you would suggest to people that they first look at their business logic. If they've like, crammed a load of stuff into a Java delegate, they should first abstract that out into another class somewhere. And then just have the very basic, as you said, data mapping, error handling stuff within the delegate class, and then everything else external. Now, obviously, we would have, we often suggest that when people, when using Camunda 7 anyway. And I agree it's a very good step when migrating business logic, for sure, is to start with that.
But looking into the model itself. And let's say one of the key differences of stuff stored in the XML to model between 7 and 8 is the Expression Language. So now, can you give a little overview, Jonathan, on the kinds of things that people should like if they're looking at their expressions on their gateways, or on a script task, or whatever, what kind of things will be red flags, or what kind of things will be green flags when it comes to migration?
[JONATHAN] In general, the JUEL expression language used in a simple way just to evaluate values of some process variables can be transformed to FEEL quite easily. Actually, we have a migration tooling that does this for you, for these simple cases. The red flags, as you said, are massive invocations or service invocations that refer to, for example, beans–beans being registered in a context. And this context is evaluated by the expression.
If you're using Spring for context, you will have hard times transforming your FEEL expressions, because you will then need to extract this actual service call to a separate service task, for example.
[NIALL] Yeah. And I wanted to ask Manu (aka Manuel) just about a question that I get from the community quite a lot. Why did we change expression language. On a high level, if you would consider JUEL, the Java Unified Expression Language against the new language FEEL, the Friendly Enough Expression Language. Manu (aka Manuel), how do you feel that the choice we made there between changing that that expression language, and what sort of benefits and things do you see with that?
[MANUEL AKA MANU] So first of all, as you said, in JUEL, there is also the word Java. So once again, we are kind of platform-specific. And also as FEEL is already a standard that we implemented in DMN, and it's already known by the community and provides a lot of flexibility, I think there was actually a pretty good move, right? To give this flexibility of FEEL also on the expressions on our BPMN diagrams and relying on actually an official standard like FEEL.
[NIALL] So they're both expression languages obviously. Can you, just off the top of your head, think of one of the things that, for instance, FEEL does much better than JUEL used to? Let's say, for people who have used to using JUEL all the time as their expression language. What kind of things should they look forward to when they're put into a scenario where FEEL is the common expression language?
[MANUEL AKA MANU] I would say, FEEL is very good in working with JSON. So it's just very natural, makes it very easy. And it's also all process variables in Camunda 8 will be JSON. This is a very good fit. And also the functions that are provided out of the box in FEEL are quite heavy also working with business rules, for example.
[NIALL] Yeah, I found exactly the same thing. I have very horrible nightmares about trying to parse JSON with JUEL, especially complex objects. FEEL’s incredibly easy. In fact, I tend to suggest a tool that I tend to use quite a lot if I'm interested in trying to get my head around FEEL is–there's a bunch of FEEL playgrounds: one made by Nico, one made by Philipp Ossler, and those are really good places to be able to test your expressions before you even need to deploy anything.
And also it's a great place to learn FEEL if you're interested in really–‘cause it’s not much to learn, really, if you know expression language. But it's more about understanding the power of it. And I think, as Manu (aka Manuel), you mentioned, the built-in functions are fantastic and are kind of key to the, to the differences.
Is there anything else about model migration that you think we should discuss?
[MANUEL AKA MANU] So I would maybe add that a migration can also be a chance to actually refactor your processes. So if you have something shady in production, and you just did not touch it in the last years, because you did not want to break it, this is your chance now to have a look, and maybe you improve your BPMN knowledge over the last years. So also, that could be interesting to think about. It is also the option to refactor your processes.
[NIALL] Yeah, I thought, it's very good point. I think a lot of people can see the stuff they would have built in BPMN a couple of years ago and be thinking, “Oh, man, if I could start again, I would do that so much better.”
So moving on to the second pillar of migration, which is a business logic, Jonathan, you already touched on some of the aspects of a business logic migration when it came to the model. So the the model itself can have, and in Camunda 7, there's 2 options you have: a service task can either contain your business logic and be attached to a Java delegate, which is a local Java class, running usually on a Spring Boot application, or maybe on Tomcat or something. Or you can have an external task that essentially communicates to the engine over network and does the work in its own environment.
Can you give a quick overview of the different types of ways that business logic can be attached to a service task, and maybe the ease with which those might be migrated? And you can make, you already made reference to the tooling that exists, so feel free to to to drop some hints around there.
[JONATHAN] We offer compatibility with both ways of of implementing things. From my perspective, if you plan to migrate your architecture first, because you might be missing some features that you require in Camunda 8, you should move to external tasks because they have the same behavior as jobs in Camunda 8. And the reason are the transactions.
So in in Camunda 7, you could handle multiple delegates in the same transaction, and, for example, use one database transaction to perform several statements in the same transaction context. And, if something fails, you could roll back 3 or 4 tasks, and it's like nothing happened. With external tasks, this is not possible, of course, because they run completely detached. Every external task creates its own context, is offered by a REST API called from there, and the result is returned asynchronously. And the same thing will happen in Camunda 8 as well. So if you want to get your execution semantic as as close as you can to Camunda 8, use external tasks.
[NIALL] Yeah, I totally agree. And you pointed out probably one of the key things to consider with with business logic, which is transactional versus nontransactional. Maybe Manu (aka Manuel) can give a little bit of of background there into the benefits of the 2 approaches.
Because Camunda 7, as you mentioned, had the ability to run multiple steps of business logic in one transaction and Camunda 8, we’ve decided will never do that. It's a nontransactional engine that will always run everything sequentially and will always commit state as soon as it happens. On a conceptual level, Manu (aka Manuel), what kind of benefits did that change from 7 to 8 give us, and what kind of things should people consider that they can now do that they maybe weren't able to do with 7, considering that change?
[MANUEL AKA MANU] So I I think the biggest advantage is that you do not need to think about transaction boundaries anymore. And I think also in the Camunda 7 community, a lot of people were not really aware of those. They just use the default ones or nontransaction boundaries. If they did not have any any natural wait states in the process. And of course, that can highly influence the process, right? So, for example, if you start a process, it fails somewhere, and you don't have any commit to the database yet, the process instance doesn't exist. You will not find it in Cockpit.
With Zeebe, as soon as the process instance is started, it will be there, right? And you will see immediately where it actually failed. And you can also then try that specific activity again, and not by accident, retry multiple service tasks in that scenario.
[NIALL] Yeah, I think all of us here have done the training right? And we remember going through the transaction stuff. Yeah, Jonathan, what do you think?
[JONATHAN] I think that nowadays the database transaction from my application becomes more and more irrelevant, as you basically tend to orchestrate services that usually have REST APIs or similar ways of APIs that do not use any kind of transaction context or two-phased commits.
So in in the end you will probably do the same thing with Camunda 7 already. You will just call REST APIs and put an async before on each user on each service task. And the behavior will, in this case, basically stay the same. And in in very rare cases where you might actually require something like a transaction from one service task over the next, over the next. You can think about a workaround to implement this. So there are ways to implement it. It's not that easy, but it's still possible.
But I think, not using transactions brings us closer to nowadays reality of service orchestration.
[NIALL] Yeah, I-I completely agree. I think anyone listening to this kind of can understand the the way that modern software architecture is going is nontransactional. And that's mainly because I think–one of the the key reasons Camunda 8 exists is because C7 was hitting a road block, really, with the amount of performance it could get. And we looked at why that was, and it was always came down to database connections, commits, and number of commits we were able to do per second or per millisecond, or however longer.
And for a long time we did a lot of good work in trying to, let's say, limit the number of connections needed by the engine, and well, so like to be able to define where those connections can happen or were they really necessary.
But actually removing it completely from the equation means you have a much, much faster engine, because we no longer need to worry about these, that that limited resource being used up– there's a huge benefit.
Manu (aka Manuel) made a very good point that I really did enjoy about knowing where transactions are in C7 was fundamentally important to both error handling to a scaling to everything. And most people didn't even know what it did. And it's nice that we can now ignore that essentially in the new engine, where error handling will happen, where it exactly where the error occurs, and it's much, much easier without needing to to learn all this stuff about transactions. I think it's a really big benefit.
Business logic in C8, can only be done through external tasks or job workers, as we call them in C8. And Jonathan, you already mentioned that the best option is to try and take the the job workers, so to take the service tasks in C7, make sure that they are implemented with what the C7 equivalent, which is external tasks, and then try and, like move forward.
On a practical level. Jonathan, how easy are those steps, and can you just talk through each step of the way going from, “I have a let's say, a a Java delegate on my Spring Boot application.” Talk me through going from there to a Camunda 8 job worker. And the complications involved
[JONATHAN] First of all, I think you will have to decide whether you’re gonna take our spring-zeebe framework for implementation or whether you are going for the plain interface implementation because there is a big difference in them.
While the plain interface works just like the external task interface, which does provide you with a service to interact with the engine in the end, and the job itself. spring-zeebe will allow you to define just the method, and this more behaves l like a delegate, actually, because here you can use the you, you you can inject yourself variables, for example, and you can set the job to be auto-completed after the method has passed.
So what you can basically do as a starter, given you decide for spring-zeebe, which I would almost recommend, because it makes things easier and less bootstrapping, less overhead and stuff. And you can just start off by copying over the method content of your of your delegate, inserting it into the into your job worker method, and then you will, of course, face some method as, some some field not found, and stuff like this because you have the execution that is part of the method. And then you can replace, for example, the variable discovery.
You can either inject yourself the job and get the variables from there, or you can use handy annotations like variable or variables as type, which is my personal favorite! And you can define the import for variables and replace all execution.variable with it. Then, of course, the service call will stay exactly the same. And after that you will have to, you will have to return the results. And here you would use execution.setvariable before. What you will do now is, you can either return a POJO containing the variables you want to return type safe, or you can create a map string to object, which is the classic implementation for C7 as well, and instead of calling execution.setvariable, you can call variables.put, and in the end return this map as return value of this function.
And that's how you would migrate a delegate that is already cleaned up. So there is nothing nothing called except the thing you wanted to call There is no invocation of any engine services and stuff which, which, I said before, would have to be cleaned up first.
[NIALL] Yep, and at that stage, you’re still using C7 but at least you know you’ve removed every dependency that makes migration harder. So from that point you have a job worker. And is it just a matter of replacing the job worker code with C8 Code? Is it similar?
[JONATHAN] Yeah, that that's very similar in this case. You could, of course, go for the for the native job worker interface which would, instead of the external task and the external task service would offer you the activated job and the job client. And from there you can just transform, transform the methods. Because some have been renamed. There's also this get variables as type, which is quite handy.
And of course there's no, no typing in a process variables anymore in C8. So what you will have to look into is, for example, if you are using some kind of Java object, it will not be a Java object. If you fetch it from Zeebe, it will be a JSON. And, after all, a Java object that is mapped from JSON to an object is a map from String to object. So I will always prefer variables as type, because this allows the object method to use an explicit type, mapping everything type safe and presenting you the variables as POJO as they are, and being reusable as well.
[NIALL] Now, Jonathan, has jumped into a very important change between C7 and C8, which of course is around variables and data. And that is brings us very nicely to the the final section of of migration, which is data.
[MIA] This is also, of course, the perfect cliffhanger for this episode. Since data migration is arguably the most complex pillar of moving from Camunda 7 to Camunda 8, we want to have plenty of time for discussion.
So I hope you’ll tune in to the next episode of the Camunda Community Podcast to hear more and check out the show notes for additional information.
If you have any questions about model and business logic migration or migration to Camunda Platform 8 in general, head to our forum which is linked in in the show notes. I'd also love to hear any success stories that you have, so please come on over and share your stories with us.
Before we wrap things up. I'd like to highlight some awesome contributions from our community.
This month, over at the Camunde Forums, we added a just-for-fun Leader Board, which shows you who has been participating the most over the last month, quarter, year, all-time–whatever you want to do.
This episode, I would love to shout out our top 2 on the leaderboard for July. There's William R. Alves, who has been super active in the Camunda Platform 7 categories, providing help and solutions, and being such a nice person along the way.
And then there's GotnOGuts who has helped answer lots of questions across both Camunda Platform 7 and Platform 8 topics. Thank you so much for your hard work and for hanging out in the Forum and answering people's questions. These are just community members that decided to share their knowledge. So we wanted to say thank you, and we appreciate all your hard work.
And same with everybody else in the top 10. If you want to learn more about the leaderboard, head over to the Forum and look for the monthly shout-outs post!
To be among the first to hear our latest podcast episodes, be sure to subscribe.
Thank you for listening, and I have not been Niall this whole time – I have been Mia. Until next time!