Programming Throwdown - 144: Kotlin Coroutines with Marcin Moskala
Episode Date: October 10, 2022Today we go back to our programming language roots with author, KT Academy founder, and Kotlin rockstar Marcin Moskala. We talk about how Kotlin makes itself doubly useful for app and backe...nd development. 00:00:55 Introductions00:01:38 Java frustrations 00:09:37 Why a well-organized typing system is important00:11:59 What Kotlin is00:14:58 Obsidian 00:20:13 Learning new things can be a prudent future investment00:23:46 A pleasant coding experience00:26:41 Co-routines in Kotlin00:34:37 Where co-routines are best in app development00:44:54 Thread balancing in practice00:57:39 Kotlin’s integrated cancellation mechanism01:05:10 Getting started with Kotlin01:18:16 FarewellsResources mentioned in this episode:Marcin Moskala:Website: https://marcinmoskala.com/Twitter: https://twitter.com/marcinmoskalaKT Academy: https://kt.academy/Kotlin Learning ResourcesMarcin on KT: https://kt.academy/user/marcinmoskalaKotlin Coroutines: https://leanpub.com/coroutinesEffective Kotlin: https://leanpub.com/effectivekotlinFunctional Kotlin (Early Access): https://leanpub.com/kotlin_functionalMore Kotlin Publications on LeanpubInformation Organization ToolsWorkFlowy: https://workflowy.com/Obsidian: https://obsidian.md/If you’ve enjoyed this episode, you can listen to more on Programming Throwdown’s website: https://www.programmingthrowdown.com/Reach out to us via email: programmingthrowdown@gmail.comYou can also follow Programming Throwdown on Facebook | Apple Podcasts | Spotify | Player.FM Join the discussion on our DiscordHelp support Programming Throwdown through our Patreon ★ Support this podcast on Patreon ★
Transcript
Discussion (0)
Hey everybody, this is a super awesome episode.
Actually, it's been a while
since we did a language on the show,
despite the fact that that is our tagline.
We've covered a ton of languages.
We definitely want to go back
and do, for example, C++.
That episode is something like 12 years old now.
But we've been on a really long journey talking about user experience,
talking about, we talked about trees, tree data structures, a whole bunch of stuff. I'm really
excited to come back to languages. And for that, we have Marcin Moskawa here, who literally wrote
the book on Kotlin. He's the author of a variety of Kotlin books, including Effective
Kotlin and Kotlin Coroutines, Android Development with Kotlin. And it's a real pleasure to have you
on the show, Marcin. So thanks for coming. Thanks for having me here.
Cool. So we definitely want to get into Kotlin and what are code routines all that but let's start with a bit of background you know what kind of what's your path and what kind of got you to the point where
you are you know writing these books and you're you know really diving headfirst on a Kotlin you
know every day what kind of led you to that I mean my journey with Kotlin itself has started with frustrations from Java. I like to talk about it
a few years ago because I've built a huge amount of frustration back then and Kotlin helped me
release it. Now I barely remember that because I'm using Kotlin for over seven years, I believe. And I nearly forgot Java. I'm still using a variety of
different languages for different purposes. But Java is one of the languages I'm trying to forget
about. Okay, so what made you write all that Java in the first place? So did you go the college
route? Or did you go straight into industry from from high school or how did that play out oh that's mixed a lot so i
i was very into the college life i actually was doing two faculties so two different courses on university, having internships on both of them.
But then I just had this life-changing moment
when I decided to go to the Erasmus.
That's the program where I can go to the other country,
live there.
I spent half a year in Rome
and I decided that I just need to get independent
and start earning my own money
and live in my own way.
So after coming back, I started working,
which was quite crazy, having two faculties and also a job.
It wasn't full-time initially, but it was enough to survive.
In the meantime, I was working as a
developer. I finished those two degrees. And so my career mixed both of those paths.
What were your degrees? Were your degrees technical or was it something else?
One was computer science. Another one is closer to telecommunication.
Ah, okay, cool.
Nevertheless, the story with Kotlin
has started for me when I worked as an Android developer.
And I was one of the early adapters of Kotlin.
And back then, the community was, you know,
I mean, community is still very positive,
but it's absolutely incomparable what was then and what is now.
You know, our community grew so much that no one, I mean, you cannot know all those
people.
There are literally millions of people using Kotlin. Back then, it was a very small hipster community
where we all were passionates
and we were all supporting each other.
And it was so, so fun.
And I just wanted to give as much as I could.
And I was writing about Kotlin and speaking about Kotlin and I was truly
passionate about promoting it I still am in teaching Kotlin and teaching programming in
general but you know that's that's not the same yeah I was I did a lot of hiking yesterday and
so for some reason metaphor kind of comes to mind where if you're hiking this trail that's really common, maybe it's paved or something like that, then you can really hike it by yourself.
But if you start going out in the wilderness, then you kind of need a way to reach somebody if something goes wrong.
And so in the beginning, when you're riding Kotlin for Android, you're kind of out there. And so you need a lifeline,
especially if you're doing it for work
and it has to work, it's not just a hobby,
then you need a community.
You need somebody that you can go to
who is Uber expert and you can say,
look, I'm getting this really esoteric error,
please help me.
And now maybe the path is just so well traveled
that you don't have to really socialize to get your app done. So it's just, you know,
a blessing and a curse at the same time. Yes, that and that does change a lot. I remember when
Google announced that Kotlin is becoming the back back then it was another language for Android.
Right now it's the primary language for Android development.
But I remember the day when they announced
that it's becoming another language for Android development after Java.
And I was like, okay, we are opening Champagne.
It's a huge
day for us and a friend
of mine who was
a bit
older
for a bit longer in this
programming community
he was really sad and
he just looked at me and he said
we just stopped being
hipsters and
everything changes now and uh i believe like
a year later he left kotlin and he started another big thing so oh what is this big thing what is his
next big thing he he he got um into eternum and all those smart contracts. Oh, okay, got it. I'm not sure if this truly became a big thing,
but I've never truly researched that.
But he was very fascinated when he started that.
Wow, yeah, what an innovator.
I mean, I don't know very much about smart contracts either,
but it's almost a household name at this point.
Yeah, I mean, there are many people like
that um i i had a pleasure to work in quite a few startups and one thing that i truly enjoyed is the
mindset of people that people just want to work on the break changing things and and change the
world and do amazing amazing things and many of those people when startup finally becomes a serious
company many of those people can stay there and make a great money but they decide to leave it
instead to to work on another big thing yeah that's right wow as. So, okay, so you were finishing up university and you're building Android, you're working on Android apps and writing a lot of Java and hating life. And you had a life-hating factory and then a factory implementation factory and you're just, oh my God, why do I have a million different factories and like every callback has to be a class.
And so it's just driving everyone crazy, right?
So, well, maybe you could talk about, you know, I threw out some stereotypes there,
but what are the things specifically that really bothered you about Java?
I think that the Kotlin in its most basic form is nothing really new.
There are new things right now, like coroutines or multi-platform capabilities,
and they are big, okay?
But the base of Kotlin is just,
I believe, how Java should look like. It is how I think Java would look like, more or less,
if it were making hard decisions
and evolving as it should evolve.
You know, of course, the big problem of Java is backward compatibility.
They do not change to not break people's code.
So I'm not saying that Java made a poor decision.
I'm just saying that if Java would make the changes it should make, in my
opinion, it would end up looking something like Kotlin looks like right now. Plus it has some
things that were designed well from the beginning. So Kotlin has a really well-organized typing typing system, something people do not see as important, but it's extremely, extremely important
from the perspective of using our code. So when you say organized type system,
are you talking about like the type hints and the type inference? So you could say, you know,
val x equals three, and you don't have to go and find out, is it an int or a long or do you have a lot of that or what makes it organized?
So for instance, in Kotlin, from the beginning, you have a type to represent nullable and
not nullable types.
Ah, right.
What is extremely important, because only then you can have proper type safety mechanisms,
something that is still not very well implemented by most modern languages.
And what is more, Kotlin made a very strict relationship between those types.
So a nullable type is a supertype of not nullable type. What opens a door for many important use cases.
In Kotlin, everything is an expression.
We also have a nothing type, an empty type,
that is a subtype of all the type, but has no instances.
It's another thing that seems minor from people who do not use that,
but it's really, really important on some use cases
that allows language
to to truly behave well and those are those are small things that are very hard to repair in the
language once you publish that but that that were done really really well in in kotlin from the
beginning cool yeah that makes sense what actually happens under the hood when you,
is Kotlin a JVM language? So does Kotlin compile down to the JVM or is it something different
entirely? In general, Kotlin is a compiled language. So it is compiled to something more
simple. And in the version that is most often used, it is compiled into
JVM bytecode, just like Java. However, there are different flavors of Kotlin, or you can say
platform targets. There is a Kotlin.js that is compiled into JavaScript, and there is Kotlin
native that is compiled into the native code. Why is it important?
On Android, it is important because it allows us to make libraries
that are used both by Android and by iOS.
So we can easily make a common part.
And teams like to include more and more on those common parts.
Business logic, you know, this is generally the same for both platforms.
Even views, there is this new approach,
the Jetpack Compose library
that allows you to create views in a pure Kotlin
using a Kotlin DSL in a really nice style
with a nice auto completion and with
absolute type safety.
And you know, projects in Jetpack Compose can be compiled to JVM and run on Android
or on desktop, but they can be also compiled into JS and be displayed as a website or be compiled into a native code
and be a native application
for whatever system you want.
So that's a new thing
and very, very powerful
that comes from the fact
that Kotlin is a multi-platform language.
You can use Kotlin to write
on any of those platforms,
or you can use it to write a module
that can be compiled into multiple platforms at the same time.
How does the iOS work?
So you would compile to like a native library.
You'd have to somehow create some kind of Objective-C interop
or something, right?
Yes, exactly.
So you could say that the result code is the same
that what you would have
if you would compile an Objective-C.
And yes, Objective-C is used here
to interop with Swift or with Objective-C projects.
Oh, interesting.
Very cool.
Does it generate the interop layer for you?
Or do you have to write that yourself? It generates it. Oh, wow. Very cool. Does it generate the interop layer for you? Or how did you have to write that yourself?
It generates it.
Oh, wow. That's super cool. I'm learning things using a flashcards in a program called Anki. And I wanted to make a notes that are automatically generating a notes for this Anki program.
And I wrote a program for that in Kotlin.
I default in Kotlin JVM.
But to transform my notes into Anki or Anki deck into notes because it goes in both directions I needed
to start a JVM program every time I did not like that and then I figured out I'm using
the Obsidian note for it's a program for for a notes for quite a popular one recently where you write all your
notes in in markdown and i figure out that you can make a plugin for obsidian and if you write
a plugin for obsidian you can add a button that starts some process basically and i migrated this Kotlin code from Java into Kotlin.js and used it to make a plugin
for Obsidian from that. It was very easy. Practically no effort needed. I think the
only thing that I needed to change is that I was using the files API and I just needed to get rid of that. And that's it.
Everything else worked exactly the same way.
And I'm still playing with that,
but I do have it working.
So I now have a Obsidian plugin
where I have button, you know,
push to Anki or pull from Anki.
And it does work.
I'm still working on that until it is stable until i
announce that and publish it but for my own use it is already usable and and it did not take so
much time yeah yeah that's really really cool so yeah actually obsidian looks awesome i just went
to obsidian.md and took a look. I use Workflowy. I'm not crazy
about it. I'm definitely going to check out Obsidian. This looks awesome. But yeah, as someone
I've only made apps as a kind of a hobby. And so I've never had a strong desire to make an app for
iOS and Android. I mean, the same app.
And so I always kind of wondered how people dealt with that.
And this seems like a really clever way where you write in Kotlin and now you get your business
logic in a shared library that then you interact with from your main view code.
It's really cool.
So you were working on apps in Java.
And at some point, you either had to convince your company to switch to Kotlin or you had
to change jobs.
What happened there?
And how did that play out?
I needed to change jobs.
I mean, back then, there were maybe a few companies in Poland
using Kotlin and I sent resume to probably all of them. And you know, Kotlin was still in beta
back then and no big company wanted to use it. However, startups did use that.
So the company that accepted me was a doc planner.
But I probably don't know about it
because it's not present in the US.
It's present in some Europe
and a big part of South America.
That's a service where as a doctor, you can register and people can rate you.
You can have calendar and it's literally like an assistant for doctors and patients can,
you know, find the best doctors and can check their prices.
Yeah, that's interesting by, you. By being passionate about this early technology
and then picking companies that are using it,
you're kind of by definition picking companies
that are sort of on the cutting edge.
And for them to take a risk,
it means that their leadership must be pretty technical.
It's kind of like, it's really interesting.
It's like, I feel like it's a good signal
for picking companies to join, right? If they have this sort of same passion that you do
about some emerging technology, then I think it's a really good way to build alignment.
Yes. I even heard that it's a strategy of some companies that they intentionally use those new and untested technologies so they
find people who are kind of crazy, who are willing to have less money and probably more
work for doing what is their passion and what they love to do.
Also it's a good strategy for companies like startups because it's actually
easier to find people i mean i heard so it is easier to find people in those kind of
technologies because you know developers pretty often want to be ahead of others in terms of technology. And companies are more often unwilling to use something that is not yet tested and proven
to be working well.
All right.
So Patrick and I are taking notes here.
If one of these days we ever start a company, we'll make everyone write in Piet or that
language that's all brackets or something. I'm just kidding.
But that's amazing. I mean, the other thing too is it's a way for you to invest in your future.
So if you go to, let's say, maybe a bigger company and they're doing PHP, just like everyone else is
doing PHP and you learn php
that's great but if you can join a company that's especially if you believe like if you have a
crystal ball and you know this language is going to be really big um and you join a company that's
using it early on you're kind of investing in in your future self yes i always seen it as a as a bets we make you know they're like those waves that you
can go with um there are those old and lazy waves like java or python that i really like and respect
but it is also um not uh not pushing you much you, because there are already plenty of people who know those
languages, who have experience, who are teaching it, who have materials, etc., etc.
So it's a very safe way to choose a big language like this one, but it's not something that
will by itself push your career. But choosing something that is new and risky is,
you know, on one side, it's very risky because this technology might die, literally. But if it
goes far, it can push you together with it. By the way, another thing that I truly believed back then,
I remember one thing was Kotlin that really inspired me,
that I was really fascinated about.
But the second thing I was truly passionate about
was this multi-platform library called RoboVM.
It does not exist anymore.
It was a really nice idea that you can write
code in Java or Kotlin
that were supported and this code
worked natively on Android but it also
was compiled into a native code
on iOS
and so you could also make multi-platform applications.
So what happened to that?
I believe that Microsoft just bought it
and killed the project.
Oh, yeah, that happens.
And yeah, and so all the people who invested
their time and energy into this fascinating project,
you know, lost it.
I mean, you know, that almost happened to Java.
You know, I mean, when Oracle acquired Sun, there was a period of time where people were
uncertain about the legality of using Java and writing your own version of the JVM and
all of that.
And at that time, people were
wondering if Java was really going to survive this legal battle. And I think it's just at that
state where it's too big to fail or too big to fall or what have you. But I've seen a lot of
JVM languages, Scala, Kotlin. There's another one that I'm totally drawing a blank on. It was based on Scheme,
but there's a bunch of these that run on the JVM, but are slowly kind of eating away at Java. My
guess is Java is stable or on the decline, but I'd have to look to actually see the data on that.
Yeah, all the data indicate that.
Ah, okay. Yep. There you go. So yeah, the the type safety and what i noticed when i um so i
wrote a uh my own version of google photos so basically i have a s3 bucket and whenever i take
a photo my phone waits for wi-fi when it gets wi-fi it looks at all the photos that it doesn't
already have on that bucket and it uploads them. And so
I have just a simple Google Photos clone type thing. And when I wrote it in Kotlin,
there's a few things that really stood out to me. I mean, one was it was literally a decade
since I made an Android app. So the whole ecosystem is way, way better now than it was
10 years ago. But it felt like I really enjoyed the editor, the integrated
experience and all of the sort of quick fixes that were happening. And even the fact that I could,
one thing that really shocked me was I could actually take Java code from Stack Overflow
or Java files from other projects, and I could convert them to Kotlin. And it could even in line convert blocks of Java code
to Kotlin. That really struck me. It's just amazing how that, because it's not trivial to do that.
I found that really pleasant, really surprising. Yes, that's from the beginning. Also, you can
pretty easily migrate the whole project and that works. However, of course, it's far from being a good Kotlin code
because it's a javish code. And the next step is to start using Kotlin idioms to improve readability
and safety of this solution. But yes, a simple solution can be done
by this auto transformation and it works really nice.
Yeah, I mean, it's a great way to kind of get started.
And as you said, you can see what's going on there
and then rewrite it or update it.
Yeah, there is actually a cool tool
that many beginners use.
So if you have Android Studio or IntelliJ open, you can
just go into tools, Kotlin, show Kotlin bytecode, and you can see what your Kotlin code is compiled
to. So if you're a fan of JVM bytecode, you can read it there. If you are not, there is this
button decompile, and this button decompiles your bytecode into Java.
It's a strange journey because we compiled Kotlin into JVM bytecode then
they compiled it into Java and you can see how it works. That's a very useful
tool for those who come from Java. They are learning Kotlin and they are trying
to understand how something works.
You can just see how this code would look like if it were written in Java, any code.
Yeah, that is super, super cool.
If I remember correctly, or maybe I'm wrong about this now, but at the time, Java doesn't
have coroutines, right?
So if you write coroutines in Kotlin, how does that end up?
And you try to decompile it.
Do you get an error or
what actually happens there? Okay. So maybe I will start with what are coroutines? Yeah. Okay.
Yeah, that's true. It's a good point. So people often say that coroutines are like lightweight
threads. I think that's, I mean, it can be a good start as it might be a useful metaphor to understand that they are lightweight and they are kind of like threads.
But it's also very confusing because coroutines are not threads.
So coroutines are already present in many languages in some limited form.
Coroutines are present in JavaScript, in Python, in C Sharp.
Any async await block is a coroutine.
Any generator is a coroutine, but a very limited use of a coroutine.
So now what a coroutine is. Coroutine is a piece of code,
some kind of block that can be suspended at any point. You know, later you can resume it from that point. So the word suspended is very important because it's not blocked. It is suspended. So it means that when
you suspend a coroutine, what you have is a continuation object. This is an object that
has all the local state, literally something like call stack. So all the local variables
of this function, of the function that called it, of the function that called it, etc. etc. So that's what continuation has. And this object is like a save. You can
keep it in your local memory. Formally, you can even serialize it and later deserialize it.
Nevertheless, at any point you can resume it and continue from where your
function stopped. So it means that you can literally jump in the middle of the function
and, you know, start from there. Perfect implementation of coroutines requires a
control of platform to, you know capture this this stack and restore it
kotlin does not have it because it does not control the platform so it simulates it by having
those continuation objects that that that store it wait hang on let me let me dive into that because
that that blows my mind so so how does kotlin able to store all the local variables?
Is that part of the Java JDK where you can get all of that?
It's a simpler concept.
So in Kotlin, the functions that can be suspended are suspending functions.
They have suspend keyword.
Such functions under the hood are passing this continuation object that is a reference to their local state.
And this object is used to keep this local state when someone suspends it.
The very important thing to notice is that this is not an additional cost.
Because I mean, it is, but a very small one.
Because we are not copying this state.
We are only adding another reference to it.
So if you have a local variable with a list
that is placed somewhere in the memory,
you know, the variable is a reference to a point in the memory,
then the continuation does not have a list.
It have a reference to the same point in the memory.
So creating those continuation objects is super cheap because, you know, you're not
copying the state.
It's like a shallow copy.
Yes.
It's like a shallow copy, but we want it this way.
Yes.
We want it this way because, you way because if the continuation is suspended,
then the local variables are gone because your execution is finished for this coroutine.
But you still have a single reference to that in the continuation. And that's how it works. And that's pretty
smart. Of course,
because Java has
plans to introduce coroutines.
And I believe that
they will introduce
them in a century
or two from now on.
And Kotlin is designed
to support
that if they finally introduce that.
Yeah, that makes sense.
One place where I found myself needing to use coroutines, and this goes way back, I wanted to make an RPG game.
And this was a long time ago.
I was actually in high school, I i think and i only knew c++ and um you
know if you've ever played any of these rpgs you go to the town and there's people walking around
in the town and you can walk up to them and press the button on the joystick or a keyboard or
whatever and start a conversation right and they have some dialogue that they'll say on command
when you're not talking to them they're kind of wandering aimlessly? And they have some dialogue that they'll say on command. When you're not talking to them,
they're kind of wandering aimlessly
or maybe they have a path that they follow or what have you.
And so, you know, each person is kind of, you know,
operating on their own timeline.
Like you don't want every person in the town
to move at exactly the same time.
It would look very robotic and weird, right?
So you want to have each person sort of with their own timer
that says, okay, you know, a few seconds have passed, let's move to the bookshelf and let's
take some steps. Or, you know, I just took a step, now I have to wait a second. And so,
you know, again, this is very early. So I thought, oh, I'll just have each person become their own
thread. And when they're not not walking the thread will just be sleeping
and what i found is yeah you actually can't create thousands and thousands and thousands of
literal threads because there's so much overhead there and even a thread that's asleep you know
consumes a lot of resources and it turns out if you have a ton of threads that are asleep you end
up running out of cores and it's just kind of a mess right so you end up having to uh do something else or you kind of like visit all of these characters and wake them up
and say hey are you ready to do anything and they say oh no i need to sleep for another
you know cycle i'll walk next cycle so you go to the next one so every cycle you kind of round
robin go through all these villagers you know kind of waking them up letting them do a
cycle and then going to the next one and it becomes really cumbersome because as you said
if a villager has some internal state it needs to like wait uh you know 27 cycles before taking the
next step you have to go and update that internal state and everything now has to be in uh like a you know c
plus plus has to be in like a dictionary or something and so you lose type safety and it
feels very unnatural right what's much better is if you could actually have like a you know a
not literally a process like a unix process but have like a you know separate routine for each uh uh you know
villager and in that routine you could say you know sleep for a second and take a step and do
this forever and not have to worry about all the overhead um and let let let the os handle you know
keeping the state of all those people and everything and so so uh you know at the time i i
didn't know about coroutines, so
I had to implement a really ugly way. But I've always found coroutines really elegant,
kind of beautiful way of handling many, many objects that all need to have their own
internal state at the same time. Sure. But I will probably synchronize it with a single timer anyway.
I haven't done a big game project, but in a small one I wouldn't like having independent timers for different parts of a game, because then your game is overloading your computer,
some things are getting slow and now all the elements are, you know, living in their own time.
I generally believe there is a tendency to rather synchronize everything with a single clock.
And I would rather use objects.
However, the actor model seems like something that could be helpful in here.
And in Kotlin, we use coroutines for the actor model.
Yeah, why don't you dive into that?
So like there's a lot of folks here
who have maybe never built an app.
They do web or they do backend or something like that.
So kind of connect us from sort of the app development
to coroutines.
When are they used?
What's the kind of best use for them and
why are they a good idea okay so there are a few typical use cases so the the most typical one is
that let's say that you on your application you need to fetch some data from the internet
and you need to wait for those data because it takes some time to get them
from your API. The question is, how do you wait for that? So if you block your thread while waiting
for the response, you need to well manage threads because there are some threads you should not
block. Other threads you can block, but they are expensive and you should not block too many of them.
So that's problematic.
So coroutines solve that problem.
You just suspend the coroutine when you wait for something
and resume it when you got it.
Then using coroutines, it's pretty easy to implement as in Kawaid.
I mean, they are built into the Kotlin coroutines library.
And there are two parts of Kotlin coroutines.
There is a built-in support that gives you the capability to suspend, start coroutines,
et cetera.
And there is a library that gives you tools like async await or sequence generators, et
cetera, et cetera, with yield.
And so then pretty often we use async await in a similar way as in other languages,
but they are implemented using coroutines. Another thing is that if you are implementing
a backend application, as Jason mentioned in here, if you start too many threads,
it's a huge cost for
your computer. So if
you have a pool of threads
that you use on your
backend system and you have
lots but lots of requests,
then
you need to start
a lot of threads on your
pool or you need to make your requests wait,
what is not optimal.
Each thread is at least one megabyte of data.
Each thread allocates one megabyte of data.
It is also a significant cost from the perspective of processor
or operating system synchronization.
So if you start having, let's say,
thousand threads,
it's already a visible burden
on your processor time, you know,
the energy used only to manage them.
And it's already one gigabyte of RAM at least.
If you have 10,000 of them,
that's very's very very unlikely your application will will work fine and you know in a in a big systems you know the having those numbers
of requests is not so hard to reach yeah the other thing is you can really shoot yourself in the foot
i have a couple of stories one um patrick and I worked together a really long time ago.
And we worked on a project where we were doing some image processing.
And we were trying kind of a new way of doing image processing.
And basically, this was all we were prototyping something on the desktop.
And I'm pretty sure you can correct me on this, Patrick, but I'm pretty sure what we did was we we created a new either a new thread or a new process for every frame.
Again, this is us not knowing what we're doing.
And so we couldn't figure out why, you know, right around around 20,000, 30,000 frames, the Python program died.
And then we would have to run it again on the next 30,000 frames.
And it's because we didn't really know what we were doing.
We didn't realize, OK, there's this huge overhead.
And what I really need to do is use a thread pool or even better, use async await, which has a thread pool under the hood and takes care of that for you.
A similar story, there was actually a period of time where, you know, the street view, which is the Google Maps where you can go down to the street level and see the photos of the street.
That service actually leaked threads.
So there was some part of that service that was creating
threads and not releasing them, like not cleaning them up. And so there's a period of time. Now,
when I say period of time, I'm talking years where the Street View service, a single instance of that
service could only live for a few hours because it would eventually allocate too many
threads and get killed by the hypervisor. And so the solution for maybe not years, but definitely
for about half a year, the solution was to just keep enough services, enough instances up and
running. And so for like half a year, Street View limped along with that.
And AsyncAway solves all of that.
I mean, you still have to do tuning and all of that if you're performance conscious.
But it's much harder to shoot yourself in the foot with AsyncAway.
Yeah.
So in Kotlin, we use coroutines.
We use coroutines. We use coroutines. We start a request.
The typical approach right now is to handle each request in a separate coroutine.
And those coroutines have their own pool of threads
because the Kotlin coroutines library has a default built-in support for pool of threads
so that when you start a coroutine,
you can decide on what pool of threads it is supposed to run.
And in this case, it will run on the optimal number of threads
for your machine.
And that is, of course, the number of cores on your machine.
So if you have a 16-core server, it will start 16 cores
and probably tens of thousands of requests will be on tons of thousands of coroutines.
That is practically no burden at all that are running on those 16 threads interchangeably, only when they are needed.
Whenever they are waiting for something like response from database or from another service,
the coroutine is suspended.
But suspending and restreaming is a very cheap operation.
So it's very, very close to the optimal. That is, you know, the theoretical way where, you know, processor only does what it should do.
So business logic of yours.
Yeah, one thing I always wondered, and I never took the time to do an experiment to find this out.
You probably know this offhand.
Let's say you have 16 cores and I create 17 coroutines
and they all have a lot of work to do.
Does it share time between those 17
or does it finish the first 16 and then do the 17?
So coroutines can only switch at the suspension points.
So if those coroutines never suspend, what is very unlikely, because
we generally use coroutines to do things that are suspending. So if they never suspend,
you know, you said 16 and 17, so 16 of them will work until the first of them is done and then the 17th will be able to
start. However, even in such extremely rare situations, there are good practices like using
there is this yield function with no arguments that is only a suspension point, only a place where you can have a switch and give other coroutines a time for processing.
I use it extremely, extremely rarely, probably only a few times in my life, because
it only makes sense in processes that are blocking threads without suspension for a very, very long time.
So either doing a lot of work or doing some waiting.
But in such a case, there is also a different case
because if you have a coroutine that is waiting,
you are not using the pool of threads that is designed to be efficient,
but instead a different
one that is called dispatchers IO that is designed to be blocked. So there are, as I said, there are
different pool of threads for different purposes. If you have things that are blocking, there is a
dispatchers IO to be blocked. If you have things that should be CPU intensive, that are doing processing, there is dispatcher's
default that has as many threads as you have cores on your CPU.
And on Android, the most popular is dispatcher's main, that is a pool of threads that only
has one thread that is the main thread, that is the most important thread on Android.
So by the way, actually, that's also funny because people think that coroutines
means multiple threads and it can mean that. But pretty often, that's a lazy development,
but nevertheless, many companies do that. Pretty often, Android projects run only on a single
thread that is the main thread. And it's perfectly fine because it's never blocked
so i mean it's not perfectly fine if you do too much work but if you if you are not doing any cpu
intensive things only you know a thin client you know fetching data and displaying them
it's generally fine because with coroutines you never block the threads you only only use it when you when you
need it before you need to use it and that's a that's a valid approach for a very simple
applications with no cpu intensive operations that makes sense so so yeah totally makes sense
i think let's use the photos app example you know if i i do a scan using the sqlite i think it's called room the wrapper around sqlite
on android but but i have some sqlite query i compare it to my media and i'm forgetting all
the jargon here my media service and it says okay i have these 400 images to upload and so i can
start 400 coroutines right off the bat. It'll only start maybe eight of them
at a time. If I say eight cores, you know, should be or eight threads should be, you know, allocated
for this, wait for those eight to finish and do the next one. But I can start all 10,000 of them
because the overhead is so low. And then, you know, and then eventually it'll chew through all
of those and finish.
What about if something is really CPU heavy?
For example, I want to detect faces in the photo on the phone for some reason.
I don't actually do this, but let's say as a thought experiment.
So it sounds like, correct me if I'm wrong here,
it sounds like what you would do is you would create a thread pool
uh that's maybe not all the cores because you don't want to you know maximize someone's phone and then you would put these 10 000 requests into that smaller thread pool that's not the main pool
or anything like that and then those those coroutines will you know monopolize that thread
pool until they're all done,
but it won't make your phone burn a hole through your pocket or anything.
Yes, there are tools for that.
You can limit parallelism for your usage.
The whole chapter, Dispatchers, in my book Kotlin Coroutines is about that.
Basically, there are two typical use cases.
One of them is exactly what you described.
So if you have CPU intensive things, use dispatchers default.
That uses as many threads as you have cores.
However, if you think you might use it too intensively,
you might starve other processes.
What is not good and for such a case we use dispatcher's
default dot limited parallelism and we set up a limit and it can be one or two or four or whatever
and now you are still using the same threads okay to in the end not use for CPU intensive operations
more than you have CPU in your processor,
but you limited your concrete kind of use
to a certain number of threads to not starve others.
That's the suggested way to do that.
Of course, it's not the only one.
You can pretty easily create a new pool of threads
with a new thread. But if you do that,
then if you use your threads to the maximum and dispatcher default is used by someone,
but by some other process to the maximum, you are using more than number of cores in your CPU,
what is suboptimal for your processing? I mean, it's not a big problem if there is only a few more threads
than the optimal one, but it's less optimal than it could be if you would restrict your CPU
intensive operations to the number of cores on your CPU. There is also another case. So another
case is with blocking calls. So as I told you, there is a different dispatcher for blocking calls.
And this dispatcher also has a limit.
It has a limit because it's pretty dangerous to not give any limit at all, you know?
Because let's say that you are using some library that is blocking your thread when it fetches something from the internet.
And then you start 10,000 processes and you start 10,000 threads.
That's what would happen if you would have no limit and probably your app would crash or something like that.
So there must be a limit.
And so Kotlin team was thinking about the limits.
They've been meditating in the wild for years.
And then the light came from the sky and there was the number 64.
And that's the default limit.
And that's a good limit for Android applications, actually.
If you need more than 64 applications for blocking operations on
Android, you probably do something wrong. However, it's not such a big limit for backend
applications because sometimes in backend we just need to use our memory more to speed up some processes. And for that,
we also use limited parallelism.
I think it should have a different name for that,
but it actually is the same function
that instead of adding a new limitation,
it transforms this battery into a new one
with a different independent limit.
And so you can create a new pool of threads with your own limit.
So now why I'm saying about all those pool of threads, why not creating a totally independent
one? So the point is that those pools I mentioned in here, they are part of one big pool, like one lake.
So the point is that creating a new thread is a cost and keeping it is also a cost.
So the point is that you might need a thread by dispatcher's default and then switch
to a coroutine that uses dispatchers.io.
And the point is that you are not changing the thread.
You can stay on the same thread, but this thread does not count as a default anymore.
It counts as an IO right now.
So we are reusing resources.
We are reusing the same threads.
What's a trick to limit
the cost of creating
threads? We are just reusing
the same threads.
What's a perfect mechanism? Because we still have
limits that we set up
before.
This
dislike is infinite.
So you can
use, IO can use 64 of their default, I don't know, 16. And our custom
limited can use 100 and other, and that's perfectly fine. But if there is no need,
they are reusing the same threads. They are just, you know, switching them. And that also makes it
possible, and it actually is how it works,
that pretty often you switch with your operations. So you do something CPU intensive, then you switch
into with another coroutine on the, or even the same coroutine into dispatcher's IO, because you
do blocking, then into another one, into another one,
and you can do many of those switches while still staying on the same thread. So you are
on different moments, you are using limits from different pools, but you are still staying on the
same thread, so you do not need to really switch. It's very well optimized in terms of performance
on many levels.
Yeah, I found that to be, you know, from a developer experience to be extremely pleasant
once I figured it out.
There was a bit of a learning curve, but just to give an example, you might want to detect
faces in the photo.
And then once you've detected faces, you might want to, say, draw a rectangle around them.
And so, you know, that second part
lives on either, I guess, main or rendering or some thread that isn't sort of this off board
process that's going to take a long time, you need to go back to the user interface process,
and draw those boxes, or at least tell the system that the boxes are ready. Yeah, it's all done with
through this with keyword right it's
it's uh been a while since i saw this code but you kind of say like with this context with that
context and you're able to in the same coroutine jump context do different things and then jump
back yes with context function allows you to to jump into a different context. So it formally starts a new coroutine,
but you might not even notice that.
Yeah, I find like anything
that avoids message passing is good.
Message passing just seems to be really problematic
because you now are not writing coding
where you're kind of sending data back and forth
between threads.
And it's just very easy to mess that up, to have sort of the wrong thread, read the data
and starve another thread.
And I've just had so many issues with message passing that this sort of like eliminates
all of that.
The fact that you can jump into different contexts and do work without having to sort
of pass a lot of messages back and forth. And when you use a with context, you are suspending the coroutines.
So from a with context, you can return something
that will be used on the continuation of the previous coroutine.
I mean, I think if you take a big picture
and compare what Kotlin has, comparing to what we have
on JavaScript or on Python, the async await and sequence builders, I think there are a
few things.
Because of course, the big point is that Kotlin implemented that so that with this approach,
we can implement a lot of things. The support is very,
very powerful and generic. That's a nice thing. Maybe someone will take it in the future,
make a new, amazing approach. But now if you compare the Kotlin coroutines library,
so the actual tools that we use, The main differences between JavaScript and using Kotlin coroutines in practice
is that first of all,
Kotlin has a much more powerful built-in synchronization
so that if you start a bunch of suspending functions,
by default, you are awaiting for them
because they do not start a new coroutine.
They are just suspending functions. They are just, you know, suspending function.
They are just functions that can be suspended.
You can always make them async, but you do not need to.
You know, in JavaScript, it's the opposite.
Everything is async.
You need to synchronize directly.
And the synchronization mechanisms are present on many different levels.
What is a very nice power of Kotlin.
Another thing is that we have these dispatchers mechanisms, so managing threats.
That's a huge, huge power. I haven't seen that on other languages implemented this way.
Another thing is cancellation, a very important thing on Android, because pretty often on Android,
you open a window, an activity,
or some other kind of window,
and you immediately close it.
So when you open that, some processes start,
and when you close it, you should cancel them.
Because if you don't do that,
then some processing happens,
some processing that never will lead to nothing because it has no views to update then it will try to update those views what will lead to some
exceptions in background because those views do not exist so you need to cancel and that's a that's
a problem of many other approaches kotlin has a built-in cancellation mechanisms how does that
work so so if a coroutine gets canceled,
what happens inside the coroutine?
It throws an exception, a runtime exception or something?
There is a chapter about that.
All right.
It's not easy to write.
It's not easy to implement a good exception handling mechanisms,
you know, because people, if you ask people how to do that,
their first intuition is to just stop the process, which is a terrible idea,
because pretty often you need to clean up after yourself. And so your intuition is actually really
good, because what does happen is out of a suspension point,
there is a special kind of exception thrown,
a cancellation exception that propagates
and kind of closes everything.
That's one thing,
that's the part that stops a current process.
Also in coroutines,
we have this parent-child relationship,
the structured concurrency,
another very powerful thing of Kotlin coroutines, we have this parent-child relationship, the structured concurrency, another very powerful thing of Kotlin coroutines.
And so when you cancel the parents,
it cancels its children.
So it also propagates this way.
And together with this, you can,
first of all, if you have a finally block,
it will always be executed when you cancel.
So it's guaranteed.
Second of all, you can easily set up some callbacks on cancellation.
And we set them on many different layers.
So for instance, the libraries that do network calls,
they also set up callbacks on on yours on their suspending functions cancellation
um because they they probably need to to also clean up some resources
to to inform some processes that there is no need to wait for that etc etc yeah i mean one thing i
i noticed about doing phone development is how the the os plays a much bigger role like for example the the one that
comes out to me is um you know i'd set this up where i didn't want somebody on a metered oh i
didn't i guess i'm the only user here but i didn't want myself on a metered connection like on a 3g
or 4g connection to be uploading these big photos to to the s3, right? So I asked Android to set up this, I think it's
called a service, and the service only runs if I'm on Wi-Fi. And so if I get off of Wi-Fi,
and I have some big upload, maybe I'm uploading a large video, I need it to stop doing that so I
don't end up with some big bill, you know, at the end of the month. And in practice, the way this works is by canceling the coroutine that is doing that big upload. And so in this way, the OS is
sort of aware of your Wi-Fi state, and it can go and cancel your coroutine. And so as an app
developer, I noticed I had to be much more in tune
with what the OS can do
and how to handle that appropriately.
Yes, that's right.
I mean, I was always saying
that you need to choose your poison
depending on what discipline do you,
what kind of development do you choose to do.
So of course, in backend,
you are mainly fighting with your databases
that they are changing structure
or that you need to make operations on databases
to make them more efficient.
And also with your API,
so that how does it look like?
What versions do you support?
And of course, the spread it
and often weirdly packed business logic.
On front end, you generally fight mostly with different screen sizes,
with CSS and with reusability of your components. And on Android, I also see that
there are two kinds of things you are fighting.
One of them is communication with your operating system.
Another one is designing your views.
So, you know, of course,
designing views for different kinds of screen sizes
that can be, you know be time consuming and annoying sometimes.
And the second thing is communicating with operating system on many layers.
How you handle notifications, how you handle network,
what happens in some different situations, you know, is that there are many,
many things that a good Android developer should know. I remember there was this function that
where you should clean up your resources. But the truth was that in some cases, it wasn't called, it has never been called.
Because if your application was stashed,
if it was moved to background,
and then the memory has stopped,
then it could be killed without invoking the lifecycle. So that people needed to know that
they needed to do special tricks to properly clean
up some important resources on earlier lifecycle functions.
So there are many, many things that are part of fighting with operating systems on Android.
Yeah, totally. I remember, you know, years and years ago, the user experience on Android
being so jagged, you know, so glitchy, where it would freeze all the time, because people were
just doing things on the main thread. And, and I think on iOS, something about Objective C,
or there's something in the language where if you did things on the main thread, iOS just wouldn't compile. And so they forced you to keep the main thread smooth.
And then at some point, Android, I don't know if they force you now, but at some point,
Android apps became smooth as well.
At some point, Android creators started throwing an exception when you made network operations
on the main thread.
But that's far from perfect.
There are still many things that people do on the main thread
that they should not.
Yeah, definitely.
But yeah, it was a good start anyways, at least.
It seems like apps are much more responsive now.
Yeah, also phones are faster.
Well, that's true, yeah.
We have more resources to waste.
Yeah, Moore's law rises all all interfaces cool so this is this is really fascinating how can people if someone wants to learn
kotlin you have a lot of a ton of folks who listen in who are high school students college students
they might be learning their first language in college and
likely not going to be Kotlin.
I mean, most colleges are teaching, I guess, Python or Java or C++.
So if someone's just getting started in the field and they hear what we're talking about,
maybe they want to make an Android app or a backend app and they want to use Kotlin,
what do you recommend is the way they get started?
So it all depends on from what level do you start.
So if you start from knowing other languages like Java or C Sharp, and I think there is
a really nice Coursera course made by Andrzej Breslav,
initially the main
creator of Kotlin,
later co-creator,
but head of design team.
And also Svetlana
Izakova, who is a really, really
great evangelist
and a great person
and extremely, extremely
competent in teaching Kotlin.
And I also would recommend a book she co-authored,
and that is Kotlin in Action,
that pretty well describes all the Kotlin features
together with their use cases
and some essential information about using them.
If you start from the beginning, there should be soon a course on Coursera made by Mita, Facebook. I cannot
tell you who wrote
content for that,
but I think it will be
a really good one.
It's part of Android
path, but it's written
so that it can be
started by anyone.
And it's, I believe,
Kotlin Essentials. I believe so. I also write a book
that is Kotlin for Developers. It's actually a series of books because I couldn't match everything
I wanted to explain on a single book. So I split it into three books. It will be Kotlin for developers essentials.
I am working on at the moment the functional Kotlin, the second part of the series
that I practically finished. It is reviewed at the moment and the different kinds of
correctors are applying their corrections. It's already available on LeanPub,
but I think it will be available on Amazon
no sooner than maybe on November or December.
We are waiting for a surprise host chapter.
I don't want to tell too much about that,
but we will probably have fascinating topics
written by really nice people
co-authoring this guest chapter.
And there is advanced Kotlin
that I'm planning to write
at the beginning of the next year.
My books, if this is time for my books.
Yeah, let's hear it.
My books are not for beginners.
The effective Kotlin is now for Kotlin users.
So it's for people using Kotlin already. And it's a recipe for getting better
in Kotlin. I hope for understanding Kotlin more and for, you know, I included there a lot of good practices and a lot of ideas for a good development.
And also Kotlin coroutines is also not directed
to non-Kotlin developers.
You need to know Kotlin at least a little bit
to understand this book.
But Kotlin coroutines deep dive is a position, a child of mine that
I directed for Kotlin developers, teaching Kotlin coroutines from the beginning until
everything I have to say on Kotlin coroutines. I'm very proud from this position.
It's based on a workshop of mine
that I conducted for,
wow, probably at least 30 iterations.
With every iteration,
it was changing a bit.
And so I think it's a very well designed
and very well thought through book.
By the way, the first series of books, The Kotlin for Developers, is also based on a
workshop of mine that teaches Kotlin from the beginning.
And that's also pretty well thought through.
Very cool.
And so you have the workshops and the books.
Are the books available on like Kindle or Amazon?
Or what's your primary vector for getting the books out to people?
So my preference is for people to use a LeanPub
because it's a platform where I generate those books.
So they are most up-to-date over there.
And it's also a platform where I have 80% of income from sales.
Sorry to interrupt, but is it LINPUB or is it L-E-A-NPUB?
Lean, like, you know, like lean startup.
Ah, okay, okay, LeanPUB.
Okay, yeah, so we'll definitely put this in the show notes.
And, oh, yeah, there's a ton of amazing books here.
Actually, it's my first time on this site.
It's very, very cool.
There are many amazing authors there.
And I think it's a really great service for writing books for developers.
You write your code in a modified markdown,
and it generates a really nice output file you have all rights for.
So you can print it and distribute it. You can also get this printable version and sell it over there on the KDP.
Or you can sell through the platform where 80% of income goes to the author,
which is pretty nice.
And on Amazon, you know, the money from e-books are funny,
are really, really small.
Nevertheless, I see that the sales are much bigger there.
So it's important for me that, you know,
the books can reach people and that people can read them and learn from them.
And that always makes me happy.
Yeah, I mean, this LeanPub, I just typed in PyTorch,
which is what I seem to be spending most of my time with lately.
And yeah, it's extremely great.
It tells you directly what the author will learn,
what the overhead is.
And it has a bunch of details on the book.
You can see the contents. You can get all the previews.
Yeah, this is super cool.
I'm really glad you shared this with us.
There is also a money back guarantee.
So if you buy a book, you don't like it, you just, you know, ask, give me your money back.
It automatically happens.
So, and I believe you have 45 days for that.
Yeah, very cool.
Yeah.
As someone who, you know, my overall philosophy to folks is to just build something
when they want to learn.
And so following sort of eating my own dog food there, I did just jump into Kotlin by
building this Photos app.
And what I found was that, you know, now that we've talked, I realized that the way that I was setting up their coroutines, I was probably creating a lot of unnecessary thread pools.
I think they're called executors.
This is this was like two years ago.
So I'm drawing a bit of a blank.
Yeah, we generally avoid that.
Yeah, I mean, this is really fascinating.
And so this is so, you know, I think, you know,
get started by diving in, we just shared with you some resources that will put in the notes,
almost every podcast listener app should have the notes. If not, you can go to programming
throwdown.com. And, you know, when you dive in, you're probably going to make all the same
mistakes that all of the rest of us made when we wrote our first code. You can go back and read Kotlin coroutines, some of the more advanced
texts, and make your app super responsive and fix other sort of developer landmines and all of that.
I think it's a constant learning cycle. Yeah, I actually see it as a problem of coroutines.
That's probably the biggest problem of Kotlin coroutines, that they are very easy to jump
in and start doing something that somehow works.
And it's perfect because coroutines are, I believe, extremely intuitive.
So if you try to understand the general idea of how your program works,
they do not disturb you.
And when you see the code of coroutines, it seems quite intuitive.
That's perfect. But from the other side, it's very easy to do something that makes no sense in coroutines.
And you do not know about that.
And people often do that.
The one thing I pretty often see is people creating jobs.
There is this job object.
You know, people use it as a context.
And this way they break their structured concurrency.
So the cancellation does not work anymore and they have memory leaks.
But they do not know about that because they are not tracking their memory.
And there are many traps of this one.
So it's very easy to use that without understanding that.
And as a result, there are many people using that incorrectly,
thinking that they are using it okay.
And that's the biggest problem of coroutines.
I think that the point in here, I mean, there are languages that are forcing you to do things intentionally.
Like by forcing that using a typing system or by the the structures
that that that you need to use you need to use things intentionally and that forces people to
to understand that to to not use it incorrectly that's that's good but of course one thing is
that it makes um makes it very much harder to start with those solutions.
Right, right.
Is it good or is it bad?
You can discuss on that.
But the second thing is that it makes that extremely unreadable.
And that's my biggest problem with Eric's Java. I can use it, I can understand it,
but it takes me much, much more time.
And if you take a student and make him or her read Eric's Java,
it's very likely, sorry, that does not make any sense.
If you make that person read code using coroutines,
it probably might have some question marks,
but it will generally be quite clear
of what's the meaning of the program.
Yep, yep.
Yeah, I mean, it's so true.
I was thinking about when I started using Next.js,
which is this JavaScript Node.js
kind of front-end, back-end hybrid tool.
Yeah, I found it very opinionated,
and so I struggled a lot because
it would say, oh, you can't do this. You can't do that. But then what I found was that when I was
done, initially you want to say like, oh, how can I sort of hack this to get around this limitation?
But then after you're going to Stack Overflow and other sites and finding out, oh, no, actually you
can design the same thing you want in this other way and that's sort of what the intent is kind of puts you on
the right course but you're right you are sort of fighting it the whole way until you reach your
transcendence there and so and so the the having it extremely open-ended allows people to get
started right away so it's it's a real double-edged sword. Um, but yeah, I found Kotlin to be very approachable. And, um, and so now I think if I
did want to release my, my photos app, I would probably have to read your book and, uh, and
rewrite a bunch of it, but at least, you know, getting that first version kind of can give you
that sort of dopamine, that adrenaline, you know, that you need to, to feel satisfied
and then make the better version.
Great.
Thank you.
Cool.
Thank you so much, Marcin.
This was amazing.
Really deep dive.
I mean, I can, you know, we can tell that you are clearly an expert in this language
in this area, and it's been a real honor having you on the show.
Everyone should check out Marcin's books.
We're going to post all the links in the notes. He also has workshops. You could go to kt.academy and see
what sort of workshops are available there. And he's also available on Twitter, twitter.com
slash Marcin Moskawa. So for the spelling, definitely check the show notes.
I get this all the time where people put an H in my last name and all of that.
So definitely check the show notes, click the link a lot.
A lot easier than trying to spell either of our names.
It was a real pleasure.
And I look forward to kind of staying connected and seeing what the latest is with Colin.
Sure, great.
I will be happy to appear here again.
Thank you for the invitation
and hope to see you again. Cool. Thanks, everybody. And everyone, thank you for donating
and supporting the show on Patreon. We really appreciate it. It is kind of crazy economic times.
We take a whole hour for us to talk about that. But it is kind of crazy times. Every time I look at the news, it's a little wild.
And so I know it's tough out there.
I really appreciate everyone's support for the podcast.
We put all of that money back into trying to get more kids and young adults on Programming Throwdown and learning about it.
And thanks, everyone everyone for writing emails.
We get so many emails from folks who,
maybe they started listening 10 years ago
and now they're in the industry.
It's pretty spectacular.
So keep sending those emails.
It's a real treasure every time we,
Patrick and I get one of those.
So everybody, we will see you in a couple of weeks. Commons Attribution Share-A-Like 2.0 license. You're free to share, copy,
distribute, transmit the work, to remix, adapt the work, but you must provide
attribution to Patrick and I and share alike in kind.