 Tidak ada display di sini. Hai, semua. Terima kasih kerana datang hari ini untuk meet-up Ruby SG. Saya minta maaf tentang keadaan saya. Saya telah menghidup semalam tapi saya hilangkan keadaan. Semoga saya tidak hilangkan keadaan semasa berada di atas. Tapi mari kita mulakan, okey? Jadi hari ini kita akan berbicara... ...berbicara tentang metaprogramming. Yang baik, yang teruk, dan yang teruk. Jadi nama saya Enabelle. Dan dia adalah Don Erwin. Dan kami adalah penyelamat dari Rocker Dan Vicky. Jadi Vicky, seperti yang beberapa orang mungkin tahu, kami menghidupkan konten asyik yang diberi. Untuk keadaan seluruh dunia. Jadi kami tidak mempunyai prasensi dominan di sini. Jadi hanya sebuah pemeriksaan visual. Semua orang dapat melihat kode ini. Jika kita tidak dapat melihat kode ini, mari kita mulakan. Okey, bagus. Semua orang dapat melihat kode ini. Okey, jadi semua orang dapat melihat kode ini sekarang. Bagus. Jadi mari kita berbicara tentang metaprogramming. Dan kami hanya akan mendapatkan sebuah pemeriksaan yang baik di sini. Siapa yang di sini dengar mengenai metaprogramming? Wow, semua orang. Okey, bagus. Mungkin di atas atas. Dan siapa yang telah melakukan metaprogramming... ...juga pada hari-hari kerja mereka atau pada hari-hari kerja mereka? Kita mempunyai pemeriksaan yang baik. Tapi metaprogramming sebagai sebuah pemeriksaan yang cukup kontroversial... ...dan kami tahu bahawa di internet, ada banyak pemeriksaan... ...artikel dan pemeriksaan di luar sana... ...yang menarik setiap pemeriksaan metaprogramming. Tapi kerana kami hanya ada 30 minit di sini hari ini... ...dia tidak akan mencari menarik setiap pemeriksaan. Kita tidak akan mencari menariknya. Tapi apa yang kami akan lakukan adalah menarik pemeriksaan dynamis... ...dengan metaprogramming. Bagus. Jadi menarik pemeriksaan. Pemeriksaan adalah pemeriksaan yang menarik... ...yang mencari pemeriksaan yang menggunakan langkah... ...di run-time. Pemeriksaan yang lebih berbeza dan lebih berbeza... ...di metaprogramming adalah pemeriksaan yang menarik... ...di run-time. Jadi sekarang dengan pemeriksaan sekarang... ...saya boleh memulakan. Jadi biar kami berharap bahawa semua kita... ...saya adalah sebahagian dari pemeriksaan. Dan satu hari, produk kami datang... ...dan menyebabkan keadaan ini... ...untuk menjadi sebuah pemeriksaan digital. Pemeriksaan digital ini sangat istimewa. Ia adalah keadaan yang tidak berjaya. Ia suka membuat kerja. Apabila ia membuat kerja, keadaan akan meningkat. Jadi sebagai penyelamat, kita ambil produk ini... ...dan kita menyebabkan keadaan. Jadi esasinya, pemeriksaan digital... ...sebenarnya adalah sebuah objek... ...yang memiliki pemeriksaan publik. Untuk menarik, menarik dan juga untuk menunggu. Jadi ia tidak menarik... ...untuk memperbaiki pemeriksaan. Jadi di sini kita ada 3 pemeriksaan publik... ...yang memperbaiki pemeriksaan pemeriksaan pemeriksaan... ...seperti pemeriksaan. Jadi... ...kita sekarang memperbaiki... ...pemeriksaan produk... ...dan kita balik ke rumah gembira untuk tidur di malam. 24 jam nanti. Jadi produk sangat suka... ...apakah yang kita lakukan dengan pemeriksaan digital. Jadi sebabnya... ...sebabnya pemeriksaan digital adalah sebuah pemeriksaan... ...saya dapat melakukan lebih daripada 3 pemeriksaan. Ia dapat melakukan semua pemeriksaan ini. Dan untuk membuat perkara lebih menarik... ...kenapa tidak menambah lebih banyak rutin... ...untuk pemeriksaan. Jadi bukan hanya memperbaiki pemeriksaan... ...pembesaran, kenapa tidak memperbaiki pemeriksaan juga. Jadi sebagai penerbangan, kita sekali lagi ambil... ...pemeriksaan produk dan menerangkan kode. Jadi sekarang, apa ini bermaksud... ...sebagai pemeriksaan digital, ia dapat... ...membuat pemeriksaan pemeriksaan pemeriksaan... ...pembesaran dan pemeriksaan. Dan pemeriksaan publik juga memperbaiki pemeriksaan juga. Jadi ini adalah pemeriksaan yang terkenal. Pemeriksaan digital dapat membuat hanya tiga perkara. Sekarang, kita perlu menambah pemeriksaan... ...penerbangan. Jadi pertama kita menambah pemeriksaan... ...dan pemeriksaan. Jadi, pengalaman digital sekarang dapat meningkatkan... ...steminat dan finas menghargai pemeriksaan. Dan sekarang kita menambah pemeriksaan pemeriksaan. Saya perlu memenamkan kode untuk membuat semuanya yang menarik... ...tapi anda dapat pemeriksaan. Ia seorang pemeriksaan yang membenar. Ada banyak kode yang dipcabungan hanya untuk menambah 6 perkara. So, the question will arise, can we actually make the code shorter? So, let us take a closer look at the code. If you look at the code, we can try to identify patterns. So over here, it is very obvious to us that all the workouts do exactly the same thing. It increases stamina and fitness. The only thing that is different is the amount of increment of stamina as well as fitness. So this is configuration. So now we are trying to consolidate the configuration based on the workouts. So there is a data structure that we can use. Can anyone give a shout as to what we can use over here? Hash. Exactly. So we can use the hash to actually consolidate the workouts configuration. And by doing so, we increase the legibility of the code. Because if a new engineer comes along to a digital pad, it is able to just look at the first part of the code and easily grasp that, okay, we have nine workouts and each workout has stamina and fitness and different stamina and fitness points. Easy. And on top of that, we are able to change and make maintainability of the code a lot easier. If you want to add any new workouts, we just need to add the configuration into the hash map. So back to the static behaviour, so now we need to find a way to actually consolidate this static behaviour. One way to do it is to put the behaviour into another method. So in this case, if we do workout and do workout would be able to increase stamina and fitness. So by consolidating the static behaviour, we are able to change any of the product requirements. So for instance, if the digital pad now wants to increase health stats, for example, we can simply go to do workout and add the increment in health stats. But, sorry. But if we look at the code, it's actually not much shorter. In fact, it's actually longer because we have the configuration and we want to ask ourselves, is there a way to actually reduce this code even more? So what we actually want to do here, like maybe if there's some magical method, it will allow us to have the method name, the method behaviour, put it through some magical method and then it generates the method for us. So for Ruby developers, do you guys have like a suggestion as to what we can use? Louder? Exactly. So define method. We can use define method to actually generate the code for us dynamically. So for those of us who is not very familiar with Ruby, what define method actually does, it is actually dynamic method generation. So we simply need to pass in the method name. So in this case, it will be do boxing and the method behaviour, which in this case is do workout and it magically, it's not magic, but essentially it generates the method for us. So it's equivalent to writing, define, do boxing, do workout and the details. So with that application of dynamic method generation, we are able to shorten the amount of code that we need to write. In this case, by half. And with just 27 lines of code, we are able to accommodate products change requirements and we can then move on to our next feature. Except one week later. So we did a great job with digital pad and product like it so much, they decided to add in two new requirements. So the first requirement is instead of having all nine workouts, they're having the exact same routine. Why not make it mirror real life a bit more? So in this case, each workout should now have its own specific set of routine. So what this means is that previously we had nine workouts and we had a single routine. So now with the change in product requirements, we have nine workouts and nine specific unique routines. So if you look at our previous implementation of the code and the previous product requirements, using dynamic method generation would it be able to fulfill product requirements because all the nine workouts have the exact same routine. But with the change in product requirements and nine specific routines, we can no longer use dynamic method generation. Because the way we wrote it leverages on the fact all nine workouts have the same routine. So what can we do? Okay, unfortunately, we have to blow it up. So like you can see, we have nine workouts and then the code will become long like the previous case. But still we fulfill product criteria and we go home happy. I said not yet because product has a second requirement. Since digital pad is so awesome, why not move it from common line prototype out to the web? And in order to do so, we need to support remote calls So what this means is that we need to add in a controller. In this case, we choose the action to workout and in designing the endpoint, we have several options. One of which is to have nine endpoints because we have nine workouts, right? But that would introduce maintainability issue. So if we take a step back and we think about a better implementation, we could actually have one endpoint and pass the activity into the parameters. So now we have nine public methods each doing a specific routine and we have one pad controller with one endpoint. So with the model and nine specific routines and the controller. So if we actually think about what the do-workout action is doing, it is essentially taking an activity and deciding which method to call based on the activity. So if the activity is yoga, it will call do-yoga on the model. If the activity is boxing, it will call do-boxing. So with that behaviour in mind, can anyone suggest a way of implementing the pad controller? Anyone? No, no, don't. Don't jump the card. Okay. Okay, we go step by step. So the first step is switch case. We can use switch case in every single language and this works, it works perfectly fine. So depending on the activity that I was passing to the endpoint, we can call the respective workout method. So this works fine, but as usual, we're kind of nitpicky. It's kind of long, it's kind of verbose, tedious to write. And we ask ourselves, is there a better way to do it? And since we are Ruby developers, it turns out there is. But let us look at the code again. So if we look at the code, we try to identify patterns again. So in this code, we see that the method is always doing underscore activity. So with this pattern in mind, we can sort of generate a formula. So we can essentially generate the method name dynamically. But that is not all, right? Our job is not done. If we look at it like previously, we are able to call currentPetObject.TheMethodName. But now with the dynamically generated method name, we are no longer able to do that. So is there a way for us to do that? Yes, Sam. Awesome. Cool. So we can use Ruby's dynamic dispatch to call Sam or the object. Just to show of hands, how many of us use Sam in our day-to-day work? Okay, that's does, obviously. Ya, so with that, we can actually shorten the amount of code that we need to write. By how much? By a third. And I think that's pretty amazing. With just seven lines of code, we are able to fulfill product criteria. And we go home happy. But before I go home, I will probably pass on my code with dynamic method generation and dynamic dispatch to my tech lead, Donovan, for code review. It's really sad. You get your... Thank you. Hai, everyone. I hope you... Hai, everyone. My name is Donovan. I hope everyone has been enjoying the digital pad implementation by Annabelle so far. And have been enjoying the magic of metaprogramming, which allow us to perform a certain action with much lesser code. So with much lesser code, we can fulfill the same purpose. So that sounds like a very good thing. I think it sounds like a free lunch. But as all we all know, there's no free lunch in the world. So how much is this free lunch? Okey. So let's revisit the code implemented by Annabelle earlier. Okey. Okey. Beautiful code, right? Very readable. Okey, Annabelle actually, beside writing very beautiful code, she actually already added the unit test for the code. Actually, I'm a tyre engineer so we code without test, right? Okey. So by just saying unit tested, what we mean is for the model, we'll check for each of the individual method whether they're going to fulfill what they intended to do. For example, do jogging will be as we ensure do jogging will do warm up screen. Do boxing will do practice punches, footwork drills. On the controller side, unit testing means that if a value of the params activity being passed in, for example, yoga, the corresponding do yoga method will be triggered on top of the current pad model. Okey. So in this case, we are not doing our integration test with the controller which we developer love to do. And you won't have any concern about why we are not doing integration test. Okey. I'll just explain anyway. Okey. So if you're assuming we are writing integration test for this controller, assume we are okay, given the scale of what NREL has been describing, the product keep getting more and more feature into a application, the product. So assuming we're going to have 20 to 30 activities, it means that our controller the specs of the controller will keep going up. So every changes or updates to the logic of any activities will be the need to be reflected inside the specs of the controller. Which we already cover inside the unit test of the model. Okey. So basically we are doing double work without having any additional benefit. Okey. Cool. We are very region engineer beside writing unit test. We are also doing like manual testing. So we do a pose for activity yoga to endpoint. We got 200. So we have so take it live soaps good right. Let's deploy but cool go wrong. Okey. One day later. You can take one day for the spec to other step to come in. So actually live is not always good. It kind of like sometimes hit the bump similar to our monitoring graph. Okey. So as good engineer we're just going to check our logs. I think at this point of time everyone will know I already forcing it when I see your code. Like very naively suming live is very beautiful all the valid input will be passing in right. Okey. So so this kind of scenario happening is because there's an invalid input being passed into our controller. Okey. This we value input categorized into scenario so two categories one in typo. So like two guys passing instead of yoga or doxing being passing instead of boxing. So in this case will be our API consumer are very confident with the capability of our system. So they think we can support some further activity which we are not yet able to support. So kind of like jumping or punching. Okey. So for this kind of scenarios if an invalid input being passed in for activity the corresponding new activity which is in this case new toga being caught on top of the current path which doesn't have that method. In the no method error. Okey. That is very simple and it's very straight for work case. Okey. No surprise here. So technically because of this is result in 500 which is not going to be very good for our user. So thinking life is kind of bad but it can go worse. Okey. I can tell you how. Okey. Let me tell you another story. So you know our product very hardworking, right? They keep adding our product team they very very satisfied with what our free dupe yoga version is performing. So decided to add a subscription model. So basically any user who paid for a subscription will be able to enjoy our dupe yoga with some kind of additional benefit so you got like kind of extra stamina extra fitness and stuff. So as you can see dupe yoga is some kind of a premium feature so it shouldn't be directly triggered without the subscription check. And we are very careful engineer and of course we put it inside the private method sections. Cool. So kind of you're safe, right? You're safe, isn't it? Okey. Like at the end of the month our finance team have a fun audit. Okey, you can have like the monthly audit. So they will be figuring out our total revenue and our paid yoga class attendance doesn't add up. And we had a very fun time debugging. Okey. So one of the one of the thing we did was we what I'm saying is we are very efficient it's not really happening in Viki. Okey. Okey, so we we go back to and check our logs and we found something very interesting. There was someone who was really passing paid yoga into our API endpoint. Okey. I can very assure you that is not a typo. Like whoever can typo paid yoga, right? Okey. So instead when paid yoga being passed in the do paid yoga method will actually trigger directly using the method send. Because you know what send actually allow the allow an external object to trigger both private and public methods of another objects. Okey. So in this case because do paid yoga is a valid action in a method of the digital pad. So of course we got a 200. That seems to be a very positive indication and like no 500 life is good. But actually it's a security breach. Okey. So think Okey, never mind. So technically it's better for the code to be broken and do nothing rather than do successfully doing something that is not expected or allowed to do. Everyone agree? Okey. So this this kind of issue was because of the private method the private gate validation was was bypassed. So the very easy fix is we know that send will trigger both private and public methods. So we're going to use an alternate which is public send. This is kind of similar to send but it scoped down our method to only public methods. Okey. So now do paid yoga is safe. Okey. So I mean like those whoever doing send like your day to day work right? I hope you will start converting to do like public send so you're going to save your life for a lot of times. Okey. Cool. So let's start getting better. But let's not forget we still have another like all the input we mentioned earlier. Okey. So let's go ahead and review them. So at the moment public send fix our paid yoga actually turn into a 500 which is okay. Okey. So so like anyway everyone will start start thinking like if you already following the switch cases that we originally use that originally implemented by Anabelle we kind of like already like we shouldn't be we wouldn't hit all that kind of problems like in many input of typo unsupported input SOS like private method being triggered right? Because here we're using switch cases we explicitly declare what is supported and what's not. Okey. But I hope and we all okay switch cases longer but it's safe dynamic dispatch is concise but it's not so safe. But I hope during the presentation Anabelle has already persuade everyone that we're going to a set we're going to enjoy the consignance of metaprogramming so how about we're going to go ahead and try to solve the not so safe problems together. Okey. Okey so let's visit our error again. So the problem now is no method error we resulted in 500 which is fine because 500 means that there's some it means server error server error means that there's something unexpected happening with your system. It's an unforeseen thing. But as we've already because we already senior right. So it's better that we handle it properly and raise a more user friendly error or like more better error code SCP respond code so easy way is to catch to rescue no method error and raise with evaluate activity and then our controller upon them will respond with a different corresponding respond code to like unprocessable entity so much better for the system code Okey Okey. So like in order fast to do it it just take us 2 lines Okey. Okey it doesn't matter you just see there's only 2 line that different between the 2 implementation Okey. But like is there anything wrong with this code? Okey. As you can start realising no method error here no method error here actually is a catch all Okey. So it is equal to catch every single no method error happening within the above block Okey. So if so at the moment we are kind of very confident because we only have 3 lines above that line so we kind of like a visual check Okey. The first 2 lines there's no way it can trigger describe error so we just save so the only one can trigger is a public send one but how about as our product keep growing our logic will get more and more complicated we have more and more code and sub underline along the way might already start throwing no method error and by having this kind of catch all we will have very fun time debugging silent failure in the future Okey. So how about we do down a more more logical path a more logical path which is validation so like kind of like validate things first before we actually execute it Okey. Okey. So because of the because of the validation of activity are tightly coupled with the kind of activity that the digital path can perform how about we add it to the model instead so kind of like easier for us to reuse Okey. So this is like a very simple validation logic so technically it do kind of the same Okey. So like when the method doesn't exist it will throw invalid activities but it will be a validation instead of catch all Okey. Okey. So this is how we apply to our controller Okey. This simple right. Okey. So technically with validation we are able to safeguard against not supported as well as typo because if Toga Toga like do Toga doxings or jumping or punching being passed into a controller the validation already the method is no longer there it's not there so validation will reach action first Okey. So life is good so let's deploy one day later Okey. Okey. Let's check our logs the moment everyone is like what right this is very strange Okey. Let's look at our code Okey. So actually I forgot to tell you a story because our product we are having a very big product team so actually while we are busy working on and improving our work out features aspect of things we are going to squad Okey. Another squad I started working on a more like a education our education squad so we got like other features on the same model Okey. So we started using do homework which kind of like it coincident co incidentally the same pattern we are the way naming that our work out squad name it Okey. It's kind of lucky because like because this do homework method taking an argument that's why you that's why you throw the error for you imagine it is do homework doesn't take in any argument it will be executed successfully and kind of like you can do your homework while visiting your work out class it kind of like you can go to the canteen and withdraw money like very fun Okey. So what is this Okey. So what is it telling us so technically do homework is not an activity so technically but however do homework bypasses the validation because do homework is actually a valid method of current pact correct but however is it's not really a valid co-card activity Okey. So there is some mismatching in like our purpose and our implementation Okey. So let's call this kind of a public method attack so like kind of without private method attack Okey. I name it on my own so doesn't matter Okey. So so let's Okey. So how can we solve this kind of problem this kind of problem so like let's revisit our purpose again our validation method supposed to take in an activity and check whether the activity is a valid work out activity Okey. It got nothing to do with whether the method exist or not Okey. If we use like method missing we can have it out of the box So like it doesn't really need to matter to be there Okey. So how about we stick to the purpose Okey. So with this explicit check against a valid the list of valid activities we are able to safeguard against the value that we are not quite correct it's not a work out activities Okey. So this one is Okey. Okey. Let's move on Okey. Okey. So cool. So we are already solving one more problems Let's deploy Okey. One day later Okey. This is getting more interesting. Because earlier Okey. And you see Pilate was actually it was actually in our activity list So we come back and we check our code since our validation logic was correct The method name construction is correct Everything seem to seem to be all fine Okey. So actually we go deeper and look at our digital pad implementation and figure out one fact that do Pilate actually is missing Okey. So this happened actually because the engineer he commit when he implement the feature he added Pilates into the list of activities without implementing it because he forget to implementing it of course there's no specs for it Okey. But like that is not a very strange thing given we have like 20 to 30 activities it's possible I will not say easy I will say possible the engineer will miss out 1 or 2 but it's not the time for us to blame the engineer for being careless it's the company that will pay the price because the product is not functional So as part of the engineering team we suppose we need to find a way to be able to identify this kind of problems before being deployed to production Okey. Of course when you deploy to production the 500 we will know So anyone have any like suggestions Okey. Now my life is me let me recap the problems the problem we are having right now is because we have 2 sets of data the first set is the list of activities which we consider as a sort of truth The second set of data is the list of manually defined method for each of the activities So the problem happening because of the 2 set of data is mismatch Okey. So how can we solve these problems How can we detect it before we deploy to production Anyone I heard something Get the defined methods Do the main method Get the defined methods Get the defined method Kind of correct Ya. But like Okey. So one of the way we can solve it is to stick to the purpose right Our purpose is to be able to ensure that for each activities there are corresponding do activity method for it Okey. So we can just write as simple test cases and then going to cover our cover of the dark box Ya. Okey. It looks simple right but it going to save us a lot of time Okey. So sticking to the purpose really save your life Okey. So let's review again So by adding by using public send adding proper validation and test we are going to cover like this or this kind of problems introduced because we using dynamic dispatch But is that so? Okey. One month later Okey. So this is not a product requirement Okey I promise this is engineering requirement So for every engineering team what we usually do is clean up legacy code right So for those who doesn't know legacy code means that the code that written long ago for a purpose and that purpose for deprecated but the code is still there It means that the method is defined but no longer being used Okey. So this is a very common engineering task in every single engineering team So what our engineering we assign one of our engineer Okey let's call him John Okey. So John visited our favorite digital pad file and he Okey. Very fun. If I now do yoga it's a public method When you say a public method what does John think right? A public method means that the method supposed to be explicitly called somewhere immediately usable to search for you right So of course you go ahead and search for it and you can only find the definition by matching that string So what does it mean? So they have a legacy code right? So John go ahead and deprecate the code and of course our aspect break because we written our aspect earlier Okey But of course they actually show us one a very big problem which is the searchability issues This is actually a very big trouble for maintaining a code base anyone Does it sound familiar to anyone? Okey A very familiar problem right? So anyone have any suggestion for this or any past practices to handle this kind of scenarios Okey Okey So let's visit it again Okey because we already discussed earlier we all know that do yoga was actually called but in a dynamic way in our controller using dynamic dispatch But the problem is the do yoga was formed dynamically using do activity which is totally not searchable Okey Correct Okey So in Vkey what we do is we establish certain rules to support our searchability to improve our maintainability of the code Okey So the two major rules is same method should only be used Sorry I messed up Public sense sorry Can you forget this? Okey So basically if you want to assess a method across object you can should only use public sense but not sense because sense can actually trigger private methods Okey which is actually the security bridge that we mentioned earlier The second rules is only public only method to be explicitly called across context which is across files across objects should stay as public method Okey It means that if it is not going and it not being called anywhere like what I'll do yoga earlier it should stay private because it's not searchable Okey It's a rule clear Okey Okey so let's apply the rule to our scenarios So because do yoga is not being called anywhere that explicitly so we're going to bring do yoga private but if you bring do yoga private our controller will not be able to access it using public sense Correct So we kind of delay Anyone have any suggestion Okey so one of the way that we can do it is introducing a purpose specific abstraction layer So what we can do we can introduce a do workout method inside digital pack after we move all of the do yoga do jogging do paid yoga private So this will be our public interface the public interface will take activity in and use the magic of metaprogramming to trigger the corresponding methods It private methods Okey So what by doing this we are making Wait wait my encapsulation Okey so by doing this we are encapsulating the technique of metaprogramming within digital pack itself Okey So when we apply it to controller it look just like a normal method Okey So by encapsulating metaprogramming inside a single object We are able to enjoy the benefit of metaprogramming without compromising our search ability of the code because now our do workout is searchable Okey Okey So to summarize we are aware of there are a lot more techniques to do metaprogramming in Ruby but because of time constraint we will recover dynamic method and dynamic dispatch and I hope at the end of the session we already show everyone all the possible issues that we will face if we want to use metaprogramming in Ruby and we hope that our recommendation will help you minimise or eliminate all these problems so you can enjoy the goodness of metaprogramming Thank you Okey Okey