 Okay, okay. Hello, everyone. Hello. Hey, hi, hi, hi. Quite nice to be here, especially with the rain and stuff. So my name is Melvin. So this is my first time speaking on a PHP user group meetup. So my topic today, I guess, will be streamlining your Laval code base. Hopefully, it's simple for everyone. I only see a few hands up for Laval developers. So let's... Okay, just to introduce a bit of myself, I'm currently working as a web engineer at Tech in Asia. I have two of my colleagues here, Lester and YC, Yuan Chuan. So basically, here are my handles. You can screenshot or get it later. It will appear again later somewhere. So I've actually worked on Laval applications for about two and up to about three years already. So my first Laval application is something that I've done actually in school back in NUS. It's actually called NUS whispers. If you are not sure what NUS whispers is about, it's basically a confessions page where NMS people who actually post confessions into their website. And what we do is actually moderate these confessions and post it up to Facebook, to our Facebook page. Right now, NUS whispers has gotten pretty well, probably reaching about 18,000 lights already. And it's widely used within the NUS community for giving feedback to all the NUS administration and staff. There's a lot of sagas if you want to see. So basically, what Laval has to do with it is actually, what is powering it is actually the moderation admin where users, where we at moderators can actually accept and reject submitted confessions. Then you just automate submit to Facebook through by using the Facebook API. We also offer API for the front end to consume, which is actually currently on Angular 1.0. It's actually a school project. So right now I'm just maintaining and just keeping Laval up to date and try out new features and stuff there. After I graduated in NUS at the same year, I actually joined TechNature. And right now, I've been working on the TechNature's Laval app for quite a while. And what we've been using it is actually to handle the company database where our staff can actually manage startups, companies, investors' database where they can add and edit or insert funding rounds and stuff. And we also have recently launched jobs last year. So we use Laval to actually develop the jobs API where the front end, which is powered by React, consumes it and for applying jobs, finding jobs, sharing profiles with each other, connecting, rejecting, and all sorts of stuff. So if you can say that the Laval app in TechNature is definitely like five or six times bigger than the whisper set. So let's just talk about Laval itself. Laval is an MVC framework, like everyone knows. So this is the basic framework, basic structure of a MVC framework for Laval because there are so many different variants of MVC. So I'll just call it the Laval Edition. So what you have there is a browser going to the controller, goes to the model, the usual stuff. But some of the different things is that we have the model talking back to the controller. Usually for Laval's case, it may return back to the browser directly because it does not, for a view, for Laval, they will use something called a blade template, something like that. They may go through the view as a blade template and display it as a browser. That's assuming you're not using an API solution, base solution. If you are actually developing an API for it, you usually just send out the stuff through your controller without the need of a view as a JSON or whatever. I don't know XML if people actually use it. So the thing is that when you look at Laval documentation, you'll just see the controllers. They'll just give you a basic idea of a controller. Oh look, it looks very easy to use. They'll just show you this, show view controller and display all users with the profile and display it as a view or rather return it as a JSON if you are using an API. But in reality, the usual four of requests in Laval usually do more than just that. And then one example is like for handling a post request, you usually do something like you need to validate the post request. You need to check whether the user is actually locked in or whether the user is allowed to actually create a certain thing. Then after you are creating, you need to create, you actually do the real stuff and create the stuff in the database. Once you're done, you usually want to send notifications to other users, send email, then you may need to create more relations. Let's say you are creating a post, you may need to create categories if needed, if you want to relate to them. Or you need to log audits for data purposes. You want to know who is the one who actually edited the thing or who updated certain sets of stuff in the database. And that's a lot of things. So in reality, if you put everything together, most of the time if you ask me, I'm like, if you are new in just knowing that this is just an MV system, everyone would just say, let's just put everything together. Because you just know that, okay, you can't exactly put in the view, you can't exactly put in the controller. So most of the time, newer people like myself, like two and a half years ago, would just throw everything into the controller like this. I'm not sure the code is not actually, there's actually more than that. And this is just only the validation, but just trying to show that it can be good like this. So eventually, there's something like bloated controllers. Controllers that like 1,000, 2,000 lines long, all the time. I usually see it like when you have a, especially if you are doing in a fast moving company or an app for a fast moving company, by experience, you'll see that a lot, eventually one or one and a half years of time, you'll see your core controllers, controllers that deal with the core main resource of the, like for example, NUS confessions, NUS whispers confessions, that confession controller itself will probably be like more than a thousand lines, 3,000 lines long. So when you, when you think of this, eventually you realize that you actually need more than just a MVC to scale your application efficiently. Now, the problem is that there's two hard things in computer science. One is cash evaluation and naming things. So it's like when you want to refactor something, you need to figure out how do I name this thing? And most of the time you'll just figure out how when I'm trying to re-architect my software application, my lava application, how do I, what do I actually name all those things? How do I know how to do this? But as it turns out, we realize that how do you want to streamline and refactor your code in such a way that it works nicely and elegantly. You just realize that actually there's, lava has actually done a lot of things to like make sure that you are having one step foot right in the door. You don't really need to check like, there's a lot of things for you to help you to go and refactor application to more than just a MVC to be able to scale it. So a few things like events, middleware, observers, policies, gates, broadcasting, queue, email and notifications. They have, they have been trying to see what you actually, most of the developers really need and create a library and layer for you, everyone to like utilize it and create an application much more quickly. So I'll just talk about one of the things that are more important is actually more of like events. When, as in basically when I noticed that one of the core things like for NUS whispers, there's a moderation process of let's say a confession. We always have a state where it says, when it goes from pending to approved by a administrator and pending for rejected. So there's a case where when the time, when something happens, the proof, we will actually do something of it. For example, this time we will post to Facebook and for rejecting, we'll probably delete that confession in Facebook. For a more bigger app like Technasia, we have our jobs platform. So let's say someone applied for a job, we usually send an email to all the effect, all the job posting creators. We actually send a notification to the job posting creators as well. And we also create logs as well for the things. At the same thing for connected and skip, we also send notifications, different services like email or notifications at the same time. So when we realize that we can do that, we realize having a, we realize that you can have an event for each of the state. Most of the time you will want to do that in the sense that you can create a confession and the user. So while we will just do a create an event object and we'll just inject the, we'll say just inject the confession and the user in as well. So we'll just, in the end, we'll just refactor the code and just take out the, extract out the event itself and submit the, emit a new event call confession was approved for a sense of like annuals response in case, after approving, approving the confession. So eventually you have, you can split out each of the tasks that you need to do as its own listener. So you have like post confession of Facebook, where you can just inject the dependency inject the third party library that used, for example, this is Facebook and just submit the one. So you are like abstracting everything out and handling one dependency at a time. So even then you can just go and create a, or use the default event service provider and actually write all this down. So eventually if when you write this down, you'll probably, everyone can like have you see like what happens, what would, what did you actually do when you could do that event. So confession is approved. I will actually post the confession of Facebook. If I rejected the confession, I would delete the confession from Facebook. Now the thing is that when you are doing something like this, you are actually killing two boats, two stones, two birds with one stone. When, so for example, for us at Tech in Asia, one of the things is that when we try to send a notification, what the notification service is way over at Japan and sending one call is like eight, like eight to 16 seconds long, can be really long. So if you are doing everything in a single track, by default, Lava does everything in a single track. So you just, users can actually just wait like eight to 10 seconds just to wait for something like that to happen. So what Lava actually has is a really, really API to actually queue all this, default all these listeners to a queue task. So you can actually just set it up, create a message, connect to a messaging service right now. There's two providers that we mostly use for AWS, SQS, and Redis. For any listeners, we use Redis and for Tech in Asia, we actually use SQS. Both have their pros and cons, but SQS has a certain limit like, it's only restricted by a small packet size and you only can defer events like up to 15 minutes. But at the same time, when it comes to cost, probably SQS is cheaper because you only pay for what you send. Already you need to maintain and manage the server. So there's pros and cons, depends on what you need to see. So after that, you can actually have your PHP servers set up a supervisor instance, then have it listen to all these jobs that are sent from these providers. In a sense that you can have, you can have different instances, different instances to listen to this job. So it's a very scalable solution. If let's say you have like a few thousand over jobs being that need to be processed and you can split the workload out to different instances when you are in your production environment. So how do you actually convert that into a Qt listener? All you need to do is actually just add a trade in the event itself. So what this one does is that you will actually serialize the conversion and the user models such that if let's say the user of conversion is deleted, you will get it from the database again and when it finds it, it's like not found in the database again, you will just terminate gracefully. So in the sense that actually you are preventing race conditions from this. Then you actually add a implementation Q on the listeners in a sense that once you are just Q this listener into a Q this as a job and like this. In the sense that you can for event listeners, if you don't want to use the event pattern, you can actually dispatch this as well using the dispatch function. So if you actually want to go even one layer further for sending notifications for user, level 5.3 actually has a notification system layer API working for it. So you can actually use it to go and further abstract your notifications to send to different messaging parties like Slack or email or notification services, other notification services. There's a lot of custom notifications channels that they are available and we ourselves actually wrote a few like mandrel and actually get stream Iowl that use it for sending emails and notifications to. So what you just need to do is actually create notification class where you just create a same thing as a job application and create a function for each of these delivery services. So for email, I'll just create a new message. What you're trying to do is actually trying to interface with the custom notification channel to proxy what things you want to send to that to the notifiable which is probably the user. So you can actually eventually add this on for more delivery services in the future. Then for what you do, you can just change a bit of a code for a listener and have it to send the notification like this. So for example, you can actually send this as a queue task as well by using shoot queue and after that, send the notifications to all the notifiable. For this for example, for this is actually the function to get all the users to be notified and then send it as a notification. So testing is actually much easier now in the sense that you can actually create a controller test case that you only need to care what is the output of the response rather than trying to figure out whether everything else is like. You send the notification whether notification parameter is correct. You're actually doing things like that. All you need to do is just you can just mock the events to just expect events to go and say that expecting a confession was created event to happen when this API call was made. So you can just put a post API confessions content and check whether the status is okay or you can actually set more things like whether the payload is returning a correct ID or anything like stuff like that. Testing business is also easier now. You just need to mock the service class that you need when setting up. So for example, this time we just set up the Facebook mock and when we are handling the case, we can just create like confession. This is like a model factory that Lava provides. So if you define the model factory like a model should have this kind of fake data, then you'll create this confession and then you can actually check whether this thing will receive a post from this class and handle the create a listener to handle this. Obviously, this will fail because it should technically it should receive post. And we also can test notifications now because we can just mock the notifications. We can just fake them, then run the usual case and check whether the notification is actually sent to the user or with the correct notification class. There's also a third argument where you actually can create a closure to check whether all the data that is sent to the notification is actually what you actually expect. So tracing back all the steps, what we do step by step is that first we actually write events for each state, trigger the event at a listener and write each task as actually event listener, all the small things one part by part and attach this listeners to the event service provider. The fifth and sixth step is like quite optional but you can do it if you need to if that's like you have a lot of things like a lot of listeners that you that take a long time to process and stuff. So fifth is to kill the listeners and notifications at additional level if you will have a lot of like notification stuff to send. So here's a little cheat sheet that we do for all the crazy things that Lava actually provides already. So when you want to filter modify request payloads and you want to reach total there's middleware for that. If you want to control who have performed action or something like you want to know who can actually access like create a user or delete a user, where do you want to have all this logic to define all this you can actually create policies for this and use gates to actually control them a written error like a forbidden error for this and as soon as now we can select send you want to send to select or mail on other notifications you can use their notifications. If you want to validate your request you can actually inject a custom form request that you do into your controller. If you want to subscribe to events and listen to them like like what you do for sockets you can do there's also broadcasting and that's for this one this is actually our third party service that a library which we use a technician called Factory where we want to control how the model should like present on its response based on different little probably like based on different policies that we have. So maybe if it's an admin he probably see like he can see like certain things and certain hidden attributes and what's not. So so final tip for when working on a new feature what you do is like I will do is basically stare at the library logs for see is anything suitable or if not worst case in our research other third party libraries there's a library news where they showcase actually library packages or there's also a curated list in github that I was like I think has a lot of stars where we can see awesome level where has a lot of data where you can see a lot of libraries and code bases to where and like study and learn about them and stuff like that. So some of this code available is the real working code it's actually available at annual response github repository not all the stuff is new actually so you'll still see that bloater controller you see over there still over there so thank you that's probably all from me any questions any questions yeah um how do you just curious with your production experience with library right yeah so how do you track model changes and how do you track app usage do you use any third party libraries model changes within the library itself uh within library itself right there's a few ways for doing it uh one way to do it is actually something called model observers uh where you actually create a class that handles and even uh whether the guy is created updated or something like that but if you want to further abstract a layer of this you probably want to move uh add another layer up there and handle and observe from there at this day um what there's something called a l5 repository so you actually abstract the model into a repository repository itself and when you create uh when you create something you you send an event like the sound event code on the next one then you go and listen to that event all right so any so you impact an event that is emitted when any model changes are correct correct and then once that happens you deal with it by by persisting it a little bit yes you can do that and you can do it as a custom job so let's say i want to send a log to a log another log to audit log right let's say i change this model the database i can dispatch it as a event listener and as a cute event so the user does not need to wait for the load for that so what about application usage itself whether the model changes this person has logged in this person has uh has visited this route um for this one we actually track uh for this case it can be done on on the application level and actually on the server level what we done recently is more on the server level so we actually check the nginx logs to see what the user has done or if you actually want to have more detail like application details on like what what you uh what you want to know like who what user is using this api and everything you could actually quite write a dominatable middleware where you can actually just lock down all the things that all the things that you want to need on yet at the end personally what i work what i use is i use i use this tracker this laura stats tracker yeah available on github uh it's it's decent it's decent but i'm just wondering whether whether you've got a better solution other than hand coding in yeah tracking the all is that using this application thing is that you are adding the load to your user so your response time may be slower yeah okay thank you thank you