ElixirConf 2021 - Jenny Shih - Context Driven Development: Architect your Code with Phoenix Context

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] [Music] so the talk is context-driven development my name is jenny and i'm a back-end developer epicology a software company based in taiwan and it has a great culture as manifested by the fact that our production system has nothing to do with elixir while the company still sponsors and supports me to be here and the reason that i'm here today is because that i want to talk to you about um sorry i'm just going to take this out because i'm apparently too short for this okay uh the reason why i'm here today is because i want to talk to you about my relationship with phoenix we had a passionate start it was two years ago at a hackathon and i just learned about elixir then i was so excited so when the opportunity came at this hackathon i decided to build an application with phoenix and let me say the experience was mind-blowing i was able to put together a server that has an authentication scheme integration with third party api and it's hooked up with a database her response was snappy and of course big plus is written in elixir so what more can you ask for but as i tried to dig deeper into phoenix i found context and it greatly confused me it confused me to a point that i stopped the development of my project completely for months and i threw myself into this quest of finding out the perfect answer to the question what the hell do i do with context so this is what you can expect from this talk i'll first first explain what about context that makes it such a challenge and my journey to build a proper architecture with it and the result is what i call context driven development so let's get started first of all context is a concept brought up with phoenix 1.3 there's this nice page on the phoenix official guide that explains what it is and to code this page contacts are dedicated modules that expose and group related functionality so the goal of it is to provide guidance to architect your application code and to understand what role context plays in phoenix let's first look at the nvc structure that phoenix is based on so when a request comes in each component takes up responsibility and together they produce a response that to send back yes and this is how phoenix organizes its components so on the left is the file structure so suppose your app is called your app the role of controller and view is put under the your app folder and the role of model is put under your app folder and this is what context comes in it is a guidance to to how you can actually structure the model as part of your application so that's nice and clear but um when it comes to implementation i find some things particularly challenging so first of all uh it seems that a lot of things uh there's a lot of things that we need to learn before we can make this work so if we look at the the guide to context again you'll find that at the beginning there was like there were there are requirements and if we zoom in you'll see that we need to know how phenix works in general request to response journey and also acto the phoenix database layer so when i try to develop with context i was struggling with the concept of all context acto and my own business logic all at the same time that is to say when i write my business logic i have to think about the underlying scheme what the what ongoing schema looks like and the performance aspect of my database queries in the meantime and i also need to think about this if this piece of logic is its context of its own or it's another context and if it does what should be its relationship with other contexts so that's a lot to think about at the same time and the second challenge is that uh relationships between components are ambiguous so uh to code official guide again it says it actually gives us a flexibility to decide how big our contacts should be and and we can also decide the relationships between them and the guideline that it has on this matter is that when in doubt create a new context so um from what i've seen in many projects the guideline this guideline results in a really flat file structure and it has some amazing benefits but also creates the problem that the dependencies between each context can be messy that is if context a depends on depends on context b there's no way to tell from the file structure that this relationship exists and also it's hard to tell if two contexts uh share uh shareholder schema underneath so those are the reasons that i went to this friendship trip to find out how to work with context and there are a lot of methods that i've tried and which didn't work first of all if you want to learn anything learning by example is always a good way however that didn't work for me this time it seems each open source project has its own idea about the architecture so most of them are and most of them are the flat architecture that i mentioned earlier and it wasn't what i was looking for and the next thing i tried was ddd because of course i held down every piece of comment chris mccord has ever said and in in his introduction to context he spent some time explaining uh that this term comes from the bounded context in ddd so with the termination of barney in chasing hot girls [Music] i decided i will tackle this complex graph that is the concept of ddd and i spent more than a decent amount of time in that before i realized i was going in the wrong direction because learning ddd doesn't really help with explaining what context is because context in phoenix and the bounded context indeed there are actually quite different things in my opinion sorry i was i watched way too much how i met your mother when i was making the sides and also feedback and killing eve but after all um after all the trials and errors um and the long hours wandering in elixir forum i saw an unrelated threat where a person was uh giving an example of how the implement a graphical ddd ctr as hexagonal like architecture and i thought great architecture and that was when i realized where my frustrations with context come from so once again let's look at the code um so context the concept of it is that context is a guidance it is not a set of rules to be confirmed uh to be conformed to but the pharmacist it will produce a good application structure so the reason why that it doesn't answers my question was because it is those questions are not context concern that is um if i want to have a awesome clear super material structure in my application i need to build that myself instead of relying on context alone context is this um guideline that we keep in mind while we implement our awesome clear super mutable structure so my plan is uh simple i'll try to build this application with a good structure and then i'll try to squeeze in apply the idea of context into it so the question once i crack that the question becomes how do i actually do that i decided i'll just steal the clay architecture framework proposed by rob martin i chose it because it is proved to work and has a good layering and a good flow of dependencies and a good diagram and also because the main point of my of this talk is how to apply context to your application so whatever i chose was just a starting point i will quickly go through the concept of this design and just to make sure we establish a common ground before we move on so so in this design we'll have four layers at the innermost layer we have domain it has all the business logic and it's not dependent on anything for up we have a use case which we use case there which is the orchestration between the use the domain and adapter and also um it controls transaction management adapter is this translation layer that that will implement that translates between the the inner layers and the outer layer which is our infrastructure layer the infrastructure layer has all the technical details and also controls all the external dependency so if we slice it in a different direction this is the flow of dependencies where you can see domains where everything depends on and the file structure is straightforward it's just it just mirrors the four layers so no surprise so under domain layer we can further break it down to sub layers we'll use a model as the data structure that we pass around the store defines the interface for our outer layers like the database repo and service where is where our business logic lives and use is um again straightforward they are these are imaginary use cases that should be quite common for user facing application and likewise in an adapter layer we can have things like common line interface or a web layer which is where phoenix related code can go and a folder of database store of course this is where acto can go and our infrastructure layer is mostly application wire files so that was a really quick walkthrough of the clean architecture design now we have this base that we can later apply contacts to but let's first look at uh what we have built so far if that solved the problems ahead first of all now we have separations of concerns thanks to that four layers and secondly we have a clean relationship between components down and the bonus point is now very testable because of the two point above so um this is not bad right we now have built a software that future maintainers won't hate and this is a good exercise in itself by the way but as uh as successful as it seems we are not done yet specifically if it has nothing to do with with context and we have um so what is the role of context in this how can we apply it so again the code if we reflect it back to our current structure it doesn't really group related functionality together so that um so let's see an example a common scenario of application is that it will send notification to users so let's see how that how that will play out in our current structure so in the domain layer most likely we'll have a notification model and we'll also have a interface for the notification store and user sort and in our use case layer we'll have this method called notify user and adapter will implement the interfaces mentioned just earlier in the domain layer and also be the color of the use case and if we group them all together we have a list of files and the first layer that we see is its technical category and actually for some paths the second even the third layer is their technical category as well it is only at last that we see we can find something that has a meaning in uh in the business sense so so that was our problem and um and that's what context wants to solve and if we looked at the dependency diagram again and draw a line between them and fold it we can we can put them into two broad categories of external and internal and let's block the external part for a second because it's not the juice of our application and on the right is the juice of our application so how do i how do we apply context that's just a layer on top of everything so um so like this just um and let's see what the module names will look like and [Music] with our notification example it will probably look like this and the first scope would be the name of the context and use case would be this method inside of the context and the domain can be nicely placed into the next layer under context so that so this is this is a file structure again uh the file notification is our context and it's also our public interface or use case and this is what the code looks like so i created a simple app called elixir lab so let's have it is app name here we have one method called notify user which takes a user id and a message again and the method implementation is uh really straightforward first normalize input into a notification structure then we call notification store and user source separately to con to perform some actions and these are the dependencies we here we orchestrate the components in the domain layer to accomplish the set operation and the components are nicely placed into a folder of its name so let's look at the files inside the subfolder notification is quite straightforward it's a model it's a structure that holds the notification model and it gets but it gets interesting uh when we go to the store so first of all this is where we define the interface for the notification store we can use elixir's behavior to achieve this and now comes to the decision of where we would declare the implementation exactly we've got some options for example we can inject the implementation module at the layer that calls it or we can write like this where we use the macro dev delegate to delegate the responsibility to another module at compound time what happened okay and we also assign the default module for it so the color layer can remain blissfully unaware of of what the exact implementation is so the user store module is kind of the same we define the interface and assign default implementation module so that's it now let's talk about a bit about the cross-context relationship because however carefully your design you design your system it is avoidable that you will run into a use case where you need to use more than one context once again the example app name is elixir lab assume that this app has two contacts for now account and notification and it's a common scenario in user association that after successfully creating the user record we will want to send a welcome notification to the user so where do i put that code one option and probably the most instinctive option is to call the notification context in the account context but that will create this implicit dependency from account to notification and we don't want that i mean sure we can use dependency injection to make it explicit but that would mean that the caller of of this method would need to know that this dependency exists so not good either another option is to put this code in in their common parent which is the elixir lab module so that elixir lab serves as a public api or the use case in our previous structure and each context can remain free of dependencies from each other so this is the file structure of the internal layer and we put it under elixir lab folder and we will have this existed lab external folder that will have the outer layers and this folder will serve as an adapter and infrastructure layer in our previewers in your previous function so um this is the result of applying the context of the idea of context to clean architecture it still has the all the advantage of of a clean architecture but now it also is meaningful in the sense that apart from the technical concerns the business concerns are now very very clear as well so here we arrive at our final stop this talk is an experiment on how to have a proper architecture with the spirit of context and what context is to me is that we should separate our business concerns by grouping similar functionalities with module names and corresponding file structure and um it's important to point out that we can do that precisely because of the flexibility that elixir module gives us that is there's no magic behind those modules names like they are in say rails so there's no complex auto loading or behind the scene mechanism for you to mess up we are allowed to experiment as we want and group them into different business domains as we see fit without any cost but we should use it carefully because context only tells you to separate your business concerns not your technical concerns so it can get messy if you don't spend time thinking about those technical layers like i did when i first started that said i think context brings up an important aspect when we that we sometimes just overlook this is not a new idea either years ago again rob martin has famously broadcast the term screaming architecture and it's it's the same idea that's having context it reminds us that the code base shouldn't shouldn't not just be about the technical components but what this application actually actually does so at last [Music] um if you didn't take in any of the previous slides what i want you to take home is this what got me stuck with contacts for so long was because i was desperately trying to squeeze my idea of application into the framework well instead it should totally be the other ring around we should be like the conductor in the orchestra that has the total control and the framework should just be this player that conforms to your awesome super clean um super material application um so like so phoenix is in our application but it took me months to truly realize what it means that's it and those are the resources that that helped me along the way not in any particular order i just own so much to each of them um i didn't show a lot of code during this talk but i actually implemented a simple app while i was experimenting so feel free to check it out if you're curious about those specific specifics i need to spend some time on the documentation though there are two branches one is purely clean architecture style and the second branch is the result of applying context and jenny underscores codes is my twitter handle i'm trying to get myself into the habit of opening it more and when i do remember uh i post very random thoughts on it that probably doesn't sound like a strong agreement for you to check check me out but i i want to engage more so please talk to me okay that's it thank you so much yeah and uh i'm ahead of time so i guess questions yes umbrella app huh i have nothing to say about uh yeah i i personally have um haven't tried that yet so sorry i just heard about things but i have no personal opinions on it um any anyone else yes in your journey kind of learning about context did you come across or give any thought to whether nested contacts ever have um if that's a good idea can you give an example of uh so so the question is if i've given any thoughts on nested context i can't give any examples so you talked about you know if you have an account context and a notification context yeah that actually makes sense i think as the so this this this app i'm demoing is a really simple app uh but i do imagine when the app grows you will need um kind of a hierarchy of context but the the central idea is that you group your first level concerns by by business not by the technical components so yeah i think that's definitely doable but it always has to have the downward dependencies okay so that that would be like the use case the coordinator would be the use that would case into the user for the accounts and then the notify service or the notify context but the your phoenix app your phoenix controllers could call directly into the any context they don't have to call it coordinator so so the the role of the coordinator would be what but then your your controller doesn't really call a coordinator okay i see so it's a it's a extra layer for you for controllers to call but controllers can can still call directly okay yeah that makes sense um if no one else i think that's it have a good lunch thank you
Info
Channel: ElixirConf
Views: 930
Rating: undefined out of 5
Keywords: elixir
Id: vr-qhHrN5_4
Channel Id: undefined
Length: 29min 55sec (1795 seconds)
Published: Sun Oct 24 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.