 Okay, so, if everyone is warmed up. Okay, so, afternoon everyone. So my name is Wei Ting. I'm actually a software engineer at Ministry of Education Singapore. So we build apps for schools to help them teach better. So today I'm going to talk a bit about metaprogramming. So first I think I want to talk a bit about why I want to talk about this, right? So I wasn't a computer science student. And three years ago actually I got a job as a software engineer. So of course the first thing you do is to write code. And this was my face when I was reading real apps code, right? So I don't really get what's going on. The next best thing you do is just copy what's existing, modify a bit, and then submit a pull request and pray, correct? So over the last three years, there have been some very nice things that have gone my way, a very helpful team. One of the other things that happened was also that the team that I worked on actually circulated a book. So metaprogramming Ruby. So at that point of time it wasn't a priority for me. I took one year to finish this book. So that's where my priorities are. But in fact over this one year, I think after reading through and rethinking about things, I learned a bit more about Ruby. It's quite similar to how Jinci read through the CCOS code. But for me reading through the concepts in a story-like manner is more palatable. And six months ago I actually attended the Ruby SG Meetup and Dregos was down there trying to give a talk about submitting a call for proposal. So I was sitting down there thinking about whether I should try for something like that and six months later here I am. So this is my first talk for Ruby. Dregos, thank you for your presentation. Okay. So I think the other thing that I realized is that for metaprogramming is, for me if I don't do it deliberately, it comes in bits and pieces as intuition. So what I want to do is to try to actually identify certain key tips or concepts and hope that both the junior developers and senior developers can also pick up some of this and at least benefit and teach the team as and when you can. So today I'm going to talk about why we do metaprogramming, some tips and how not to get yourself cute while doing metaprogramming. Okay, so let's first start with the definition of metaprogramming. So Google reviews many kinds of definitions. The one I like, I really like, is code that writes small code. But the more accurate version of this is actually the writing of programs that write or manipulate blah blah blah. What it means is that if you, as of now we write Ruby methods which accept data and we give an output to that. So metaprogramming means that you accept the program that you've written as a piece of data or an object and you modify it. So what you are doing is you are inherently modifying the application behavior at runtime. Everyone got that? Okay, so the next question is that oh this is such a complex concept. So why do you ever metaprogram in the first place? So what I will try to do here is to convince you that it is sometimes better to metaprogram and I will try to show some examples. So we start with a very easy one. Suppose I have an object called A and I need to define the standard getters and setters. So the easiest way to do this is just to define the Ruby methods as follows. So you just have an equals get and set. Correct? So this is quite a few lines and actually what happens is that you can actually rewrite this in a nicer and cleaner way by using attribute assessor. So I think everyone is very familiar with attribute assessor and if you want a very naif implementation of this this is how it's going to look like. But overall what you have is that you have actually abstracted some of the logic away. So when developers read class A they instantly understand what full and bar actually mean to the class. So one of the benefits of metaprogram is actually that you get slightly more readable and concise code in the class methods, in the class definitions. Okay so another example would be on my2metaprogram is that in certain cases we might want to extend this attribute assessor even further. So I guess okay. So if you actually include active record base in this manner, you realise that Rails actually includes all the attributes for you. You do not even need to define them. And as you dig into the code you realise that what Rails does is that it actually digs into the schema, the database schema, it identifies this set of attributes that this model has and so what this does is that it gives you very automatic behaviour and when you define active record classes these are things that would help you along the way. So you do not have to spend a lot of time writing it. You do not really need to read it because all these columns are actually listed in the schema and actually all the developers are aware of this. So another value of metaprogram is the following. So suppose we have a report model and this report requires three states. So you have a draft, a review and a public state and then you want to transition between the different states. So what you have is you want code that looks like that on the left. I hope everyone can see. So you have a state, you create a new report, it is in draft state. What I can do is that I can try to submit it it moves into reviewing state and so on. So it's like a state machine. A naif implementation of this would be to just code out the methods as we can. But what happens is that as business requirements change, you start to introduce a lot more things. So for example, the boss comes to you and says, no, I think 3 states is not enough. We might want to have 5 states. So what you can then do is to go back to the class redefine even more methods. But if you look at it carefully okay, so again so what can also happen is that the boss could also ask you for things like, you know, I want pre and post transition hooks. So for example if I were to submit a report can I actually send an email out to everyone to just notify them of this and so on and so forth. You want to raise errors so some of these are very common repeatable logic. So what you can then do is to actually meta-program this. So if you can actually define the states and the transitions programmatically then what happens is that you can actually write code to actually generate these methods for you automatically. And the hooks in there will be a lot easier. So what I'm going to do here is I've actually copied what a gem called workflow has done. So what workflow does is that it wraps up all this logic into a very simple, what you will have is that you define the initial state let me try to have the laser point up. So what you have is that you define state, draft, reviewing and publish and then you define transitions between them. What you get here is that go agrees that this code is more readable for everyone. So I think it's beautiful because currently we only have 10 states. If you have 10 states and 20 transitions between the 10 states this will look a lot more readable than having probably about 20 times 100 or 200 methods in there. So what you then do with meta-programming is then so what you do is that you define domain-specific languages and then you then hide the logic elsewhere. So this is definitely readable, concise and of course more reusable. So now you can take this workflow DSL and you can actually bring it to other models and reuse it. So just to sum up I think these are just some of the very basic examples of why meta-programming will help you. So they are more dynamic. They provide dynamic behavior, it's readable, concise, you don't really repeat yourself. But I think all in all it provides code that's a lot more readable. I'm sure all of you know that reading code that's not done by you is actually quite painful. So the more readable it is, the less pain you feel. So I'm going to give 3 tips to start meta-programming. So the first is what GTS covered. So when I saw a talk I was quite happy but essentially what you need to do is because for meta-programming what you are trying to do is to modify the behavior. In essence you are trying to modify the behavior of the object or the class. So it is very important for you to get your mental model right. So if you are to define classes, include classes, subclass, and so and so for create objects, you must be very clear on what you are creating and what you are observing. So this is really ugly but you get the idea. So the first important thing is actually for people who want to meta-program is to get this mental model and if you don't get this right, it's very hard for you to implement proper code in the meta-programming sense. The second step to actually doing meta-programming is to learn how to modify the behavior. A subpoint of this is actually to understand how Ruby is evaluated. So things like how are methods being called, how do messages pass between the objects, how to catch missing methods and things like that. So a very good start for me, I feel, is that you should read the call Ruby docs. I would like to point to a few sets of functions that I think are quite useful for everyone. So if you do need to understand a class, if you need to understand a class, you can use methods, instance variable, get the methods, what are the instance methods, single-turn methods, class and single class. And if you need and once you have if you need to understand this and you need to modify the behavior of it, then you can go on to the methods on the right. So these are things like defining method so you can program it typically define new methods, you can add methods or you can even undefine methods. So just a trivia for those who are quite experienced, so you need to do some hunting if you want to find them. Okay, the last thing is that if for you to do render programming is to actually figure out what's the DSL that you want. So I can't really give much advisor because it's very contextual, depends on the team. But what I've learned is that the first copy is never the best. You can always iterate to get slightly better DSLs, and what I would suggest is actually that you copy from others. So I think Rails has very good implementations you can look through. It's very, very complex even for their attribute assessor definitions, but you can looking through some of these libraries will give you an idea of how the DSLs are done and how they are implemented. Okay, so the problem with method programming is that if you can modify behavior you can knowingly you can also modify behavior unknowingly and that's where it gets very dangerous. So simple things like that can happen. I have been caught many times where my teammates have written code hidden in a very small folder somewhere which results in very implicit behavior which I don't recognize. So it takes me a few hours to debug so I'm going to go through 3 big things so some of the gotchas. So I think the first thing is as you method program, try to keep the method programming code independent. So if you do modify a class or modify an object, please try to keep it towards that object and not introduce more dependencies. The second thing is don't method program, method programming code. So what what can happen is that you can have a set of defined methods that look very similar and go oh why not let me just group them together and then I can do meta-meta-programming. The issue I have with this is that if you remember reading the method programming code it is actually very hard to read method programming code in itself. There's actually an extra load on your head to try to figure out what's going on what you're creating, what you're modifying. So try not to make it more unreadable, less necessary. The third thing I want to say is actually that after this talk, I don't think it's right to just go and say let's go method program everything. So imagine the following case where you have a class and you have 20 includes just after you define a class. So if you encounter it's very hard for you to identify which piece of code actually defines this behavior or modifies this behavior. Okay, the second thing I want to talk about is readability. So I have kind of shown you ways in which method programming can help in readability but there are also cases where it might not help so much. So let me give you an example. I actually found this code online is from this gem called we have a method programming kind of example and we have on the right a more explicit example. So who prefers the method programming way and who prefers the right side, the more explicit example. Okay, so from those ways that I have actually so this is a very interesting question. I presented this to my team. I also got kind of a half half at the end of the day and it's about what the team feels. Certain people if you have a team that has very experienced developers who are working on the same app for a very long time it is okay to have more method programming code versus a team which has more turnover or prototype app, maybe explicit it's much better, it's a lot easier to get it out to speed. So I want to say here is that short is not always readable and sometimes at some point you have to choose between whether you want more implicit or more explicit behaviour. Okay, the last thing to note is always remember to document and test. Because method programming is quite hard to read it's very important to actually explain what you are trying to do. So I think we all understand this if you have done a lot of rails you should know that you are using a lot of method programming in there before actions, after actions, all the callbacks and things like that. So the documentation helps a lot in identifying what you actually want to do. The other thing is also to write test. So when you introduce some method programming code when you write a test it also number one it guards against your behaviour so you can commit with confidence it's also important for you to write it so that you kind of tell readers what you are intending to do with this piece of method programming code. So if you see the test below here you can actually tell the behaviour that you are trying to bring out in this particular model. So for people who don't really like to read documentation and if they prefer to read test this is a much better platform for them. So I think all in all say that actually method programming is still a tool so it's not really a silver bullet for everybody but in certain cases it does work wonders and it's quite magical when the code you have refactored is a lot more readable so I just want to share that also be aware of some of the risks that this might have so when you have a lot of method programming there's a lot of implicit behaviour it's hard to debug in fact it also takes a long time to actually define it and to build this. Okay so if everyone has enjoyed this I hope you did but and if you want to look more into it I can introduce you to this book in the book they will go more detail into some of the possible spells or design patterns that you can use and I hope part of this answers so we get more readable code. Okay so far then I think thank you everybody for listening and not falling asleep and any questions if possible Cool so we take questions now anyone Thanks for the cameo basically my feeling about method programming is that you say it makes more readable code but in a way it seems like you're just shifting the readability to it makes it readable for the user of the API but you have additional complexity and where the code is being written which is why Reels is so easy for beginners to pick up but it's so magical so how do you actually integrate the method programming part of your application into your project do you manage it as a separate library Okay so how do we do it actually I have the slides let me check okay I think I was actually working on this example to just try to show some examples of it for example in our app actually we have many models and suppose in one of these models you want to attach certain models have files reports have pictures and you have articles which has many pictures and these things have attachments one way of doing it is the following where you can define it so it's still part of the application code but it's hidden off in I think we keep it separate in the app but separate from the rest of the models and then we just test that so I agree with you that it does hide some of the complexity away but so that's why I think if you have tested that I think it's fine so yeah I think that will be the easiest way to answer alright thanks Thank you so much for your talk I was curious to know you mentioned that depending on certain teams metaprogramming might be a wise choice and sometimes not so I was curious to know in your own team how do you determine whether something to be metaprogrammed and when it should not be ok ok so for us what happens is that when the best kind of candidates are those where you find yourself repeating the same things over and over again so for this example of attachments we actually had this we had to repeat this and I think that was when it made more sense to actually do metaprogramming on this right for things that are very well defined and the behaviour is understood really you should do this for things that are very unclear because the design portion takes quite a long time to do to come up with the DSL and to implement it so for unclear requirements it is better not to involve too much of metaprogramming so cool, thank you I was wondering what's your approach to method missing because all of these examples that you shown here were like defined methods so this is pretty safe metaprogramming as you're defining some method and you know that this method will be there method missing is like the double X word that you call it whenever the method doesn't exist so I was wondering if you think that it is recommended by you to use this approach or you should be extremely careful and use it only when you have no other choice excellent okay so I did want to talk about method missing there was an anti-pattern on it online but I think it got in too much into details but for me if you ask me if you can avoid method missing you should avoid method missing at all cost right because method missing is I would see as a global catch-all for all missing methods but to implement that correctly you need to also implement respond to missing if I remember correctly because that will identify whether a method is actually missing or not so you can implement you can catch some of these missing methods but Ruby doesn't know that this method is missing or not so that's why I think you have to understand the object model little bomb and see how the message passes so if you can you should avoid it and know how method missing is implemented one more question do you have any favorit DSL out there in the open source some that you particularly like how readable it is so I think I really like workflow because I think we have about we deal with about 4 in out so the app I work on is actually like an assessment app so we have answers and which has 4 or 5 states rotate between each other so actually the workflow DSL is a very nice example there was one more recently that I came in contact with which I really like which was it had to do with some passing I forget I can't answer that just tweet later when you remember awesome thanks hi anymore thanks for the talk for the example of the ACTP actions and metaprogramming what would your approach to testing the methods defined in the public API would you just do separate tests for defining the explicit method like have a test, forget, put, post and delete or test one test one of the possible verbs if they exist what do you do usually when you metaprogram public methods in objects okay there are different examples for this case what I might do is actually to sort out the possible verbs with just one verb let the file run and see if R is executed R receives the method call so something like that the workflow one where it's slightly different I'll probably have a concrete so I have a dummy class I include some workflows define the workflow and states and transitions then I just test that we can take one more question before we move on thank you very much Weicheng let's give it another round of applause