[00:30.000 --> 00:59.560] All right, so let's continue with one of our favorite topic, which is dependency injection. [00:59.560 --> 01:02.920] We talked about it this morning. As you can see, we have a lot of topics. We have even [01:02.920 --> 01:11.240] more topics until, what time do we finish? 6.30 p.m., right? So, 6 p.m., 6.30. So, we still [01:11.240 --> 01:16.680] have a lot of stuff coming in. But for now, please welcome Arnaud, who is going to talk [01:16.680 --> 01:30.360] about COIN. Thank you very much. Let's talk about new COIN developer experience in COIN. [01:30.360 --> 01:39.120] Just about me, I'm Arnaud Juliani, the lean maintainer of COIN project and also COIN GD. [01:39.120 --> 01:44.920] COIN is a dependency injection framework, and the idea is to help you structure your application [01:44.920 --> 01:52.000] with ease and efficiency. And this is the challenge of providing a DSL developer experience [01:52.000 --> 01:58.480] for you to make your app very, very easy to build. I tried to explain COIN in just two [01:58.480 --> 02:04.520] minutes to explain how finally we improved behind that. As we have a dependency injection [02:04.520 --> 02:11.840] framework, we want a bunch of classes here, one A and B with the dependency. And we have [02:11.840 --> 02:18.520] a DSL keyword here that make the configuration space for us. Then this is the module keyword [02:18.520 --> 02:25.280] that introduce the way that we have definitions for the application, single keyword with a [02:25.280 --> 02:31.960] lambda function to create what we want to, the class that we have here, and the second [02:31.960 --> 02:39.240] one to declare the second component, and then we are done. We have declared our components [02:39.240 --> 02:46.120] inside the COIN container. The thing here is that it's working directly with your [02:46.120 --> 02:52.640] Kotlin code. That means that here, if you follow closely, we are using constructor directly. [02:52.640 --> 02:58.920] And then it's not compiling. Then that means that this class B is needed a dependency to [02:58.920 --> 03:05.160] class A. And then this is where we need the last keyword that is get. And then the challenge [03:05.160 --> 03:12.280] was that in three keywords, I can manage to write an application configuration to manage [03:12.280 --> 03:19.840] my dependency. The thing is that then COIN can create everything by constructor for you [03:19.840 --> 03:27.600] and also run any kind of Kotlin code directly behind the functions. The other side of COIN [03:27.600 --> 03:35.080] is that you can inject any field easily just by unlocking an extension with the COIN component [03:35.080 --> 03:42.640] interface. That means that you can access to the by-inject function that helps you retrieve [03:42.640 --> 03:48.840] a dependency out of COIN container. Then you have both components, those one that are created [03:48.840 --> 03:55.120] directly by COIN. And when you can't have things created directly by COIN, then you [03:55.120 --> 04:04.960] need to inject in fields. This will perhaps remind you some of the Android activity things [04:04.960 --> 04:09.520] like you can't create activity by yourself. You can't create Android component by yourself. [04:09.520 --> 04:16.160] You are called by a lifecycle. Then you need to retrieve things from the outside of the [04:16.160 --> 04:21.960] container. And then that's it. You mostly have all the tools to have your dependency [04:21.960 --> 04:30.120] injection. You need just to run and start your container. But finally, the experience [04:30.120 --> 04:37.760] is interesting and the community raises many things like problem of verbosity. Because [04:37.760 --> 04:44.560] sometimes in application you tend to have like dozens of dependency. I would say perhaps [04:44.560 --> 04:49.440] look at your code, perhaps you have kind of potato effect where you can have everything [04:49.440 --> 04:58.040] inside one component that try to gather everything. But yeah, not that great for us. This is where [04:58.040 --> 05:04.680] the story starts for us and how we can improve this for the Kotlin developers. And then from [05:04.680 --> 05:11.200] this really simplistic example here, what we have here is we would like to avoid our [05:11.200 --> 05:18.600] developer to write manually the GET things. From the idea and the need of GET is that [05:18.600 --> 05:26.400] COIN is made to be super efficient. We don't use reflection. We don't use any kind of meta [05:26.400 --> 05:31.720] information over your code. We just run the thing. And then the configuration seems to [05:31.720 --> 05:38.720] be a bit manual over there, but then you are manually writing the things for COIN. The [05:38.720 --> 05:46.920] new magic way finally to write this with COIN is having a new keyword, single and single [05:46.920 --> 05:54.240] off. That is the same semantic keyword, but it's a new function. And then instead of asking [05:54.240 --> 06:00.200] you a lambda, we want to ask you a function directly. This is why you have the double [06:00.200 --> 06:07.080] semicolon character. And then for us, you don't have to write things with GET. It's [06:07.080 --> 06:14.360] still readable, still very easy to use with the COIN semantic, the sense, the meaning [06:14.360 --> 06:21.200] of the DSL. And then also, it's consistent with changes in the meaning of, for example, [06:21.200 --> 06:27.040] if you change the constructor of a class, your DSL can break because you didn't update [06:27.040 --> 06:35.920] it. Then for us, it's a very great improvement to go over a DSL that is using lots of functions, [06:35.920 --> 06:43.520] but finally not a voodoo to write those functions directly as a lambda, but directly with parentheses [06:43.520 --> 06:52.320] and this pointer kind of pointer function stuff. The other side of COIN, of course, [06:52.320 --> 06:58.880] is having dynamic behavior that are interesting is that you can pass that directly to a definition. [06:58.880 --> 07:05.360] That means that in this class, we just want an ID. And what we want to do is pass this [07:05.360 --> 07:12.720] ID dynamically to this component. COIN offers you the way to do that directly when you inject [07:12.720 --> 07:20.160] a field by using the function parameters of. And then magically, your data is going into [07:20.160 --> 07:27.120] the graph and then is injected in your definition directly by this function. This is very visual, [07:27.120 --> 07:37.960] interesting, but then this compact way of having the DSL also is capable of dealing with your [07:37.960 --> 07:45.960] lambda expression. Then you don't need lambda anymore. It's quite interesting because finally, [07:45.960 --> 07:52.760] this was this feeling of having COIN as a really compact DSL and compact way to describe everything [07:52.760 --> 08:00.200] without to invade your implication is that now it avoid an annoying side effect of the DSL [08:00.200 --> 08:06.920] and then now you can just write directly your class constructor like that. There's, of course, [08:06.920 --> 08:15.520] some warnings. If you have qualifiers, name parameters, like if you have two components [08:15.520 --> 08:20.120] that have the same type but have not the same implementation, then you want to have the [08:20.120 --> 08:28.440] different name for them. Then here we can guess which one you want to use directly. Function [08:28.440 --> 08:33.080] and classes that have default values, we don't know. We don't know if we, if you want to [08:33.080 --> 08:39.640] use the default values, if you want COIN to use this, then up to you to use again the lambda [08:39.640 --> 08:47.640] expression thing and also any kind of complex Kotlin expression like builders. Yeah, it's [08:47.640 --> 08:54.280] still Kotlin then for you. You can just still use the lambda when those expressions are [08:54.280 --> 08:59.640] needed else go with this double semicolon character expression and then just use the [08:59.640 --> 09:07.200] class and then you're done. Mostly keep the things up going in the easiest way to write [09:07.200 --> 09:15.640] for you. It's opening a door for us like we are a framework maker, then we try to understand [09:15.640 --> 09:22.160] what kind of DSL and options we want to offer you. For example, when you define something [09:22.160 --> 09:30.680] in your DI, you can give it a name, a qualifier. We can say that it's created on start. For [09:30.680 --> 09:34.880] example, the container is starting, then you can create it on start and also you can say [09:34.880 --> 09:44.800] that it's binding another type. All of this is interesting but it's not really easy to [09:44.800 --> 09:50.840] extend in terms of keywords and binding. For example, you don't know if there is other [09:50.840 --> 09:56.640] keyword after the bind because we are already using some lambda, then a function to express [09:56.640 --> 10:04.280] something. Then do we open a new lambda block after the lambda block? It's a bit weird things. [10:04.280 --> 10:13.600] Then with this new DSL, we can open a new way to write this function. That means that [10:13.600 --> 10:20.160] we can directly open a lambda theory for this option. Like we have a name, we have created [10:20.160 --> 10:28.840] a start and we have bind. This is the same word but not implemented in the same DSL style. [10:28.840 --> 10:35.360] Here this is functions directly out of the definition thing. Clearly, you see it's a [10:35.360 --> 10:41.200] bit more readable for us also. It's clearly more maintainable and allowing us to add more [10:41.200 --> 10:49.680] features at time. Then it's really interesting to provide a new way to write things and also [10:49.680 --> 10:55.600] feedback of the community is super interesting for us. [10:55.600 --> 11:02.120] One of the things also is that coin is really simple and keep the things really simple in [11:02.120 --> 11:07.960] terms of DSL. That means that you declare anything in terms of module. You can scale [11:07.960 --> 11:12.640] in the way you want by features, by layers, by everything. Then up to you to organize [11:12.640 --> 11:20.400] yourself. Really, the idea is that the tool shouldn't impact your mind, shouldn't impact [11:20.400 --> 11:26.680] your way to build your application. You should even forget that you are using coin. This [11:26.680 --> 11:32.720] is really important for us to continue in this way. [11:32.720 --> 11:41.880] In coin, the framework never had the need of gathering modules, other by list or by, [11:41.880 --> 11:49.280] let's say, something more convenient by a plus operator, but it was really simplistic. [11:49.280 --> 11:56.440] The problem is that with scaling application development, scaling around all the development, [11:56.440 --> 12:01.600] we need really strong links between definition, between reusability of this component, this [12:01.600 --> 12:12.600] layer and this stuff. We finally introduce something that can be seen as really simple [12:12.600 --> 12:18.480] to add as a module is that we add the includes function that help us really understand what [12:18.480 --> 12:23.640] kind of module we want to reuse and then flatten everything and optimize your loading at start [12:23.640 --> 12:38.120] for you. It may be visually, it may be really easy to use, but when finally at the beginning [12:38.120 --> 12:45.280] for coin, you only have a list of modules to play with, it's kind of really hard to reuse [12:45.280 --> 12:54.040] and really hard to figure out where finally you can build your configuration. Then we [12:54.040 --> 12:59.000] are unlocking a really big door that means that you can begin to reuse parent modules [12:59.000 --> 13:05.720] with child modules and then you can begin to dive into really, really complex, big and [13:05.720 --> 13:12.440] complex configuration things. Then for you, we are flattening all the graph, we are loading [13:12.440 --> 13:22.240] and optimizing all the stuff for you. Then all those Kotlin multi-platform, all of these [13:22.240 --> 13:27.520] features are Kotlin multi-platform ready and to get those superpowers, sure, you can grab [13:27.520 --> 13:36.720] this directly in your Gradle file. It's not 3.2 versions, time is flying by 3.3 and if [13:36.720 --> 13:43.760] you are making a Kotlin multi-platform application, use the coin core module, Gradle module and [13:43.760 --> 13:53.320] if you are using Android, then use the coin Android module version. Coin has been made [13:53.320 --> 13:59.320] to make your development super easy and super simple and this is why your coin configuration [13:59.320 --> 14:10.440] should stay really simple for you. I let you meditate on this quote from Chet Hazer and [14:10.440 --> 14:16.720] the transition for us is we are trying to use another kind of expression in terms of [14:16.720 --> 14:22.240] framework is that until now we were really people that pushing a lot for Kotlin DSL, [14:22.240 --> 14:31.520] stuff, et cetera. The idea of perhaps introducing annotation is also to not reproduce what you [14:31.520 --> 14:41.280] can find in other frameworks like Dagger and other, but really point something, we want [14:41.280 --> 14:48.920] to bring value and the problem of also the DSL is that we clearly have some limits over [14:48.920 --> 14:54.920] that. We can't understand really what you are writing, we can't trigger any static [14:54.920 --> 15:00.800] analyse of your code directly. That came to magic to the Kotlin compiler plugin. I won't [15:00.800 --> 15:07.000] dive into details for that because I believe some people already talk about KSP and everything [15:07.000 --> 15:13.200] about that, but let's say that Kotlin compiler is everything we could do for you before we [15:13.200 --> 15:18.720] are compiling your code in Kotlin. Then we could rewrite things, we could make code generation [15:18.720 --> 15:27.120] of course, analysis, et cetera, et cetera. What we will do with Google KSP is provide [15:27.120 --> 15:34.520] you a way to avoid the DSL and go really straight forward with annotation and keep all the coin [15:34.520 --> 15:42.880] semantics, all the coin API for you. We don't want to reinvent the wheel. What we want to [15:42.880 --> 15:49.720] do here is that we want to generate what the DSL you would have to write and then it's [15:49.720 --> 15:55.000] really, really, really a small piece of code that you would have to write. Then if we can [15:55.000 --> 16:00.960] still avoid you to write things in your code, this is still a good experience for us to [16:00.960 --> 16:10.320] let you understand how far we can go. In terms of definitions, what it means is that if you [16:10.320 --> 16:16.640] have a class, then you can just add directly an annotation. You see that this is the same [16:16.640 --> 16:25.640] keyword we have the add single on it. Then you see that we are extending an interface. [16:25.640 --> 16:31.600] The idea is that with just one annotation, we will understand that this class is having [16:31.600 --> 16:38.560] a constructor and then we will also bind directly the type migrate history. The idea is that [16:38.560 --> 16:44.000] we allow you to have, not to type anything in this. We detect things for you. We detect [16:44.000 --> 16:50.080] the code and then we can say, okay, coin, just write this definition for my repository [16:50.080 --> 16:59.800] type with the implementation of my repository. We have another component. We target add factory. [16:59.800 --> 17:05.960] Factory is another keyword of coin. It's the opposite of a single ton. Factory is something [17:05.960 --> 17:11.920] you want to create. Each time you want to ask a definition for that. Then if you want [17:11.920 --> 17:17.840] an instance of my presenter directly, you just tag it add factory and then coin will [17:17.840 --> 17:24.840] generate the DSL and then coin will manage to go and get the definition for you. You [17:24.840 --> 17:30.960] see finally you don't really care about the DSL and the complexity behind that. Finally, [17:30.960 --> 17:38.760] we can detect many, many things for you. Finally, for those who are making Android development, [17:38.760 --> 17:46.120] we have an annotation dedicated for coin that lets you understand that. Let coin understand [17:46.120 --> 17:53.120] that. We will create an instance of view model. Then we are reaching all the dependencies. [17:53.120 --> 17:57.440] We understand that this is a view model and then we will bind everything for you. You [17:57.440 --> 18:04.560] see that here we don't speak about DSL. It's just that we tag something here. The idea [18:04.560 --> 18:10.160] is that we can have automatic injection and binding. We can detect everything, all you [18:10.160 --> 18:15.880] need here by default. We can deal with new label type. That means that if you use the [18:15.880 --> 18:20.480] question mark in parameter construction, then we will understand that this is something [18:20.480 --> 18:25.840] that can be new label and then for you, it's completely transparent and then it will be [18:25.840 --> 18:37.320] taken into account. Also, as you have seen, we can tag a parameter in a function or in [18:37.320 --> 18:43.600] a constructor as injected param. That means it will be something that come from the application [18:43.600 --> 18:50.760] that is sending a data, a dynamic data directly to the definition. Then the natural way to [18:50.760 --> 18:58.320] do that will be to tag a parameter as injected param. You see that finally, the experience [18:58.320 --> 19:05.440] for us is to try really to let you write the minimum and the minimum things for you. Like [19:05.440 --> 19:13.640] for example, with dagger hit, we still have lots of things to specify. For example, in [19:13.640 --> 19:18.560] the spring framework, this is the kind of opposite because a spring is scanning everything [19:18.560 --> 19:24.840] for you and making all the class pass analysis for you. Then we are in between where finally [19:24.840 --> 19:34.960] we allow you to just tag your code with just a bunch of annotations and then you are ready [19:34.960 --> 19:42.880] to go and you can manage any kind of tip-off injection with your constructor things. [19:42.880 --> 19:47.080] The idea behind of the magic is that just you use annotations and you are ready to use [19:47.080 --> 19:54.360] the standard coin API is that you can use bi-inject or bi-view model field injection [19:54.360 --> 20:02.400] style here. Then we don't break the experience of people that are already using a coin and [20:02.400 --> 20:08.240] then we continue, then we allow people that are using annotations directly to use those [20:08.240 --> 20:17.520] extensions as regular extensions. For the modules, then for definition, we just [20:17.520 --> 20:24.240] tag annotations. We annotate classes, but for modules, we can't directly tag something [20:24.240 --> 20:32.160] in the DSL. How works KSP is that we are scanning for many classes or functions, then it will [20:32.160 --> 20:38.320] be kind of hard to tag around the DSL. The proposal for now is to work directly with [20:38.320 --> 20:45.440] class module to let you have an organization module for that. Then how you do that, you [20:45.440 --> 20:50.200] declare a module and that's it. You have a module, you have a hard module and the idea [20:50.200 --> 20:55.320] is that you put add component scan and then we will scan any kind of component that has [20:55.320 --> 21:05.200] been tagged in your application by package. Then it's really specific in terms of scan [21:05.200 --> 21:10.720] then that means that you can really filter by package, filter by layout, filter by features, [21:10.720 --> 21:17.480] how you want to organize yourself and then you just have this annotation here. Also, [21:17.480 --> 21:23.880] if you want, you can declare things directly inside a function. We will understand that [21:23.880 --> 21:30.120] if you tag something inside your module class, it will be a definition that we can bind for [21:30.120 --> 21:38.080] you directly. You see it's still very, very natural to use and really super compact. Then [21:38.080 --> 21:44.760] the idea is for us to let you go super fast for your dependency injection and keep everything [21:44.760 --> 21:54.440] aside for you. Of course, between two modules, you can have the includes of other modules [21:54.440 --> 22:00.640] that will generate the right things for you. That means that it will use the includes function [22:00.640 --> 22:09.600] that has been introduced just above in the new coin DSL site. Then we just need to start [22:09.600 --> 22:16.800] coin. That means that you have your module, you have a function where you want to start [22:16.800 --> 22:22.400] to start coin and then the idea is we just run the module with the new instance of my [22:22.400 --> 22:30.880] module here. The only thing we want to generate for you is that it's just a simple extension [22:30.880 --> 22:37.800] that will generate the DSL and this is where we just want to make boundaries for us. We [22:37.800 --> 22:42.080] don't want to reinvent the wheel. We don't want to reinvent things to generate code over [22:42.080 --> 22:48.560] code over code. We want to keep coin as it is, something that is super efficient to make [22:48.560 --> 22:55.400] dependency injection but allow you to use the annotations. This is why with such approach, [22:55.400 --> 23:00.360] you can mix both. You don't have to write a new project with annotations. You can already [23:00.360 --> 23:06.360] use coin annotations inside your project and test with it. The only thing you have to [23:06.360 --> 23:12.800] care is be sure to have the right import. That means that we are generating all your [23:12.800 --> 23:22.600] coin contents inside our coin.ksp.generated. Then you can use both DSL module, class modules [23:22.600 --> 23:27.880] annotated and everything, everything. Then up to you to express yourself and use the [23:27.880 --> 23:35.000] right tools that is great for you. What is interesting for us is that we don't want to [23:35.000 --> 23:40.960] reproduce what we have seen and why we have made coin is that we don't want to expose [23:40.960 --> 23:46.720] you to tools that can take dozens of minutes to recompile your project. The idea is that [23:46.720 --> 23:53.680] it should run for thousands of components really quick. The other good thing of that [23:53.680 --> 23:58.800] is that it's cutlin behind the scene, it's cutlin generated and this is something you [23:58.800 --> 24:07.600] can clearly debug step by step if you want. Up to you, that means that we don't want [24:07.600 --> 24:13.960] to replace DSL by annotations. It's another way to express yourself. Ksp is a good technology [24:13.960 --> 24:20.960] for us to help you write less, less quotes, less bugs. Then up to you to choose the right [24:20.960 --> 24:29.000] tools and the right solution to make your app structure. To finish then about coin and [24:29.000 --> 24:36.280] some improvement of this year, what's next? If you want to throw now about coin, we have [24:36.280 --> 24:42.960] many tutorials on many kind of cutlin application from a cutlin, cutlin multiplatform and Android [24:42.960 --> 24:52.480] application, also Cator if you want. This is the roadmap for 2023 where we have end [24:52.480 --> 24:58.280] of track coin 3.2, 3.3 is the active track, this is the current application that is still [24:58.280 --> 25:07.880] maintained before the next release where we are in 3.4, where we want to focus on compose [25:07.880 --> 25:14.080] for the jet brains multiplatform side, be sure that we want to bring better experience [25:14.080 --> 25:19.840] for cutlin native and we have also the verify API that is a new verification API that lets [25:19.840 --> 25:25.520] you make a compile time verification. Of course, we are really keen of Cator and we [25:25.520 --> 25:33.040] want to push new things about Cator. Especially today at FirstDem, and this is my first session [25:33.040 --> 25:40.120] at FirstDem, I'm really happy to show all the people that are really sharing and contributing [25:40.120 --> 25:46.600] to coin and I clearly want to thank them. Thank you all the community to work on coin. [25:46.600 --> 25:53.360] I believe some of people can find themselves on this board. If you want to chat with the [25:53.360 --> 25:59.960] coin community, then you can either find us on Twitter, on Slack, the cutlin on Slack [25:59.960 --> 26:06.400] and also you can go on the website that is inside coin.io to find all the related sources [26:06.400 --> 26:13.920] that you want. And also Open Source is great, but you need a strong company behind that to [26:13.920 --> 26:19.280] help you and have support on your project that is helping with coin technology and cutlin [26:19.280 --> 26:24.960] technology. This is why I founded Cozilla last year to work with people that are using [26:24.960 --> 26:33.560] such technologies. Then you can find all the resources on Cozilla.io and write on time. [26:33.560 --> 26:34.560] Thank you. [26:34.560 --> 26:41.560] Then we have time for questions. No question there. [26:41.560 --> 26:47.840] No, sorry. We don't have time for questions. We are so strict on timing. The next talk [26:47.840 --> 26:54.840] will start in four minutes, actually.