Hey everybody Forest here ripping 2021 illusions basketball team all addition 10 box number 13 tiered random teams I'm going to look at the results one more time here. I dropped you a link in chat You can always find them in the website late and sports cards comm as well. Let's see. We got everybody good look See I read in yellow. I think you're number to 25. You can hit autos in here. They're not guaranteed Let's see hard to see Turn your phone Plenty of space for personal guys just Chronicles football hobby six bucks later We're starting off with the rookie signs warriors Michael Mulder. You're warriors Auto start off got Ricky Nathan Knight Kira Lewis Nice yellow rookie Najee Marshall six to 25 pelicans Go Career lineage I'll roll the die for all of these acts I'm gonna roll die right now for all these because they're gonna be a good amount Got blazers and pistons on this one one two three left four five six right for the whole break on these career lineage Unless there's like a really the number low number one then we'll random it I'll put the base will go all one way here. That's gonna be right Pistons on this one going right side for the whole break Jamal Murray clear shots Not numbered on the red There's a wise men rookie. Yeah team all like groove look there Angela Russell red Skyler Maze rookie not numbered for Atlanta. It's red Simons Killian Hayes Von Dotson Cole Anthony Jay Sean Tate rookie Omar Stevens all the depot Top of bottom here. So let's see So do one two three top four five six bottom for all of these So you're one two three top sixers four five six bottom thunder just like that that landed on the pack But it is a three Well, the two heart is a three upright on the pack that goes top top on these Living legends Jason kid for the Nets not numbered Coro sex and the is on a new team. He's a jazz Mark Moses Brown Danny Green Chris Boucher Maladon Jim Mike Conley Chua and oh Kong Wu Mike Flynn Murray Giannis insert living legends Kevin Garnett for the Celtics not numbered Duncan Robbins and Tim Hardaway and an Anthony Edwards rookie Anthony Edwards Sam Merrill red Rajan Rondo Clippers Kareem Abdul-Jabbar lineage Gordon Hayward and Denny of Dia Pat Williams and Killian Hayes This one goes top that which would be wizards on that part. All right. You got Aaron Nessmith Emmanuel quickly Got Gary Tran, Jr. I'll be topping mystique Collins section for the Cavs numbered Scholar Mays rookie Siddiq Bay Pistons rookie Paul George Malachi thin and Van Vleet that one's Raptors either way and a maxi Maxi for the Sixers box three Falsito their auto see a big auto Zignagi Desmond Payne and as cancer Anthony Davis on these shining stars Lakers not numbered And an Okong Wu Dale Malladon read for the Nets Kevin Durant Siddiq Bay Chris Middleton that one goes top Pistons Jalen Smith fresh to Chua read Alexi Pokersevsky career lineage Zach Levine They mean fluid clear shots for the Blazers Make a puzzle rookie Guys excited for optics tomorrow optic basketball. I'm excited as a bouquet. Well, Braun James Steph Curry Okoro and his Xavier Tillman favorite tanking team. Yeah, I know the MOOC. I'm sorry Nike or a Lewis Your shots Larry birds Yeah, they won't be cheap. They'll be drafting a hive forever But it's cheap now Get the jet get the jazz breaks what you can. Yeah, man, they're gonna be like the magic James Wiseman Like the magic or like the Rockets John Morant's red Marcus smart for the Celtics To I Leonard this one goes Thunder was the top on this one the rookies always the top I believe There's been Bane rookie for the Grizzlies Jay Sean Tate Lamar Stevens. There's a Yolk it's Edwards insert T Wolves Incident impact living legends Jerry West Lakers They go mallet on Moses Brown Luka This one goes Cole Anthony the magic good luck, man. Paul Reed. I like to focus have ski Thank you for joining Ben. Good luck, man. Maybe we'll get you a nice year one rookie auto Those nice quarterbacks of receivers from the draft Haven't had a big bet already the vet auto's unlimited are really rare though the big ones We're all really low numbered RJ Hampton Saban Lee Dame Westbrook mystique not a Mitchell jazz jazz no longer Jalen Smith sons yeah calves are for sure a top four team in the East They were pretty good as is they were gonna take a step forward anyway, and there's a little mellow rookie for the Hornets They add one of the better guards in the league Kiki red Alfred Payton for the Knicks Kyrie career paths that one goes top Warriors Wiseman and the rookie is always top. I believe Who to Manchester City clue this weekend Cole Anthony rookie for the magic Not a force play Bournemouth who I think is in Relegation zone, so they better beat him. God Jordan to Laura Don't have a Mitchell again amazing for the jazz Nazi Marshall Yeah, I'm like checking out the schedule like every week now There's like seven games on Saturday or something like that. I'll be watching all morning I already have it planned out. I'm gonna open my open the soccer boxes that I bought and watch soccer Ediworth season highlights with the T wolves Killian Hayes Anthony Edwards Right I Haven't opened a personal box of my own Have money going towards other things So we've been talking about kind of all day Cavs gave up a lot. I Like it for both sides. I mean, I don't know why the jazz tried to rebuild right away anyway But they're doing a good job with the trades at least There's been an incident packed for the Grizzlies the steep well in bead for the Sixers Is this steward shred for the bulls Nicola boots of it speaking of the trades for teams that were tanking Goes top RJ Hampton magic Top in the mellow ball magic and win it all win My god, man, I bet everybody seems to take us then I'll be part of it. Wow, they're cheap exactly You honest career progressions James Harden amazing for the Nets. That'd be awesome. Pull Anthony The All-Star Games in Utah interesting Nathan Knight Portis Pocasevsky Okoro For more boxes Yeah, plus sexy come off injury. I mean it's it's I think it's a good trade for the Cavs So yeah magic are expensive now. We got number one picks. We got number one overall pick We got a bunch of other lottery picks a lot of young talent Kevin Porter Jr. Rockets 1 to 25 Grizzlies on that card no matter what living legends Isaiah Thomas Pistons Anthony Edwards again for the T Wolves Yeah, I'm going on some magic games here for sure Sam Merrill Red rookie for the Thunder they'll mall it on Magical Anthony incident impacts career lineage Russell Westbrook Cavs are really good James Nice Jess. I Might have to look into that. Just got to make sure I can get like the days off I guess if it's outside like my schedule or like on days that I typically would break Nessmith quickly Roby Steak Steph Curry and Skyler Mays That is very cheap in today's MBA. It's a deep Bay rookie for the Pistons John Collins buddy healed KG career lineage Goes the mellow side for the rookie goes top Hornets Kenan Martin Tyrese Maxie. Oh really Jess. I'm gonna have to check that out. I'm gonna check that out tomorrow I'm gonna that tomorrow Stevens James Wiseman Got a yellow Paul George for the Clippers 8 at 25 quite Leonard is that Levine on these shining stars of the Bulls How the auto the first box hasn't seen one since come on. Let's see some more Jay Chantate Lou Williams Killian Hayes red for the Pistons Anthony Edwards incident impact for the T Wolves Savin Lee Moses Brown Goes Cole Anthony magic side there clear shots Chris Middleton bucks Hampton Rozier deer and Fox quickly Chris Paul career progression Composito and Jalen Smith. That sounds nice. I gotta get rich in on that Rich needs to just get season tickets and like Like rich if we all if we all chip in and I'll get season tickets and just pick our games He's a little busy though, so I'll get to go to more games It was just scheduled me on the day like oh, sorry for it You're not gonna go see the Celtics that's not amazing. I'm not a Celtics fan We're all fans of like different teams though for the most part, so it would kind of work out You have a basketball team Pazzo red rookie for the Nuggets Jamal Murray or sorry, Zeke Najee Zeke Najee Jamal Maria is a nugget, but he's not a rookie. We'll just get our own group We'll buy like seeing tickets together. We'll go to like two game two or three games or something. That'd be cool Najee Marshall Cole Anthony season highlights magic shining stars Damian Lillard Blazers Why Stefan? Oh my god, Anthony Edwards rookie team all parallel for the Grizzlies Halliburton rookie Last box. Good luck everybody. Come on. Let's see another auto here. I'm surprised. We haven't seen more than one. I Didn't think they were this rare. Maybe we're just unlucky tonight Patrick Williams rookie team all for the bowls Killian Hayes Steph Curry clear shots Warriors Skyler Maze red Brandon Ingram Pelicans It was bulls Patrick Williams on this one top Desmond Bain Grizzlies rookie Big pack. Just a lot of base cards, maybe Kenny Martin Jr. Tyrese Maxey Living legends Tony Parker for the Spurs There's a lot of base. It looks like Yeah, why he's been there? Hey at least someone's getting into a game this year Well, but my fantasy game That's true That is true. Someone's getting one game at least the uh Instant impact the mellow ball and most brown on the back. That'll do it everybody. Thanks again. We've got more basketball coming up next


In this video I'm going to tell you three ways that I use peppermint oil and the benefits that I get out of those uses and I want to talk about how old mate peppermint has infiltrated my life to a point where I now use it on a daily basis. Before we go deep on these three things I wanted to talk about the thousands of studies that have been done on peppermint oil. I think sometimes we turn to chemicals and pharmaceutical products just because that appears to be the norm because of what doctors are telling us but we forget that natural remedies such as peppermint oil can actually help cure and improve our health and well-being. If you go to PubMed which is the biggest online publication of medical studies there is over a thousand compelling studies that have been done on peppermint oil and I'm going to share some of those with you today. Now peppermint essential oil is made up of two core components one is menthone and the other one is menthol which is the most active ingredient and essentially these two things combined are antimicrobial, antibacterial, antiseptic and anti spasmodic.  Now disclaimer before we get into this video my wife Alice she sells essential oils including peppermint oil and she works for a company called doterra. Now we're going to go speak to her in a second about why doterra versus another essential oil brand because I think that is important but I need to be fair because I actually personally had roadblocks up when she came home two and a half years ago raving about these essential oils doterra including peppermint oil despite the fact that she goes deep on the way things are sourced and if they're as organic as they possibly can be and if their natural benefits are proven multiple times I still had blocks up and that's because not I didn't want to not support her but it was more so I have a slow burn nature it takes me a while to adopt things so it took months for me to go deep on peppermint oil in fact years but in the last six months we've gone super deep together and there's three things we're going to drill into in a fair bit of detail let's just go up a quick chat with Alice first though to understand why you would do a doterra peppermint essential oil versus just any regular one you can get off the supermarket shelf so let's go have a chat she is I come to ask you a question is that all yeah so can you tell me if someone was going to use peppermint oil why would they use doterra's peppermint oil versus somebody else's peppermint oil uh okay so essential oils the quality of is largely related to the quality of the plant okay so the essential oils house within the plant as a way of protecting it from pests diseases illness it's like the immune system of the plant essentially what can vary the quality of the essential oil is things that can oftentimes be seen as so minute like when the plant is picked for instance the essential oils can travel through the plants like blood through a human body in certain times of the day it will be in a different part of the plant if the plant is harvested during that time then the actual quality or efficacy of the oil is going to be higher so it's not just subject to the time of day that the plant is picked or harvested it's subject to the climate the conditions and the place in which the plant grows it's such a huge part of it so if you're talking peppermint oil like we could grow and we do peppermint out the back here in Australia and it seems pretty nice but the peppermint that's grown where we harvested in washington is going to be of a much higher grade the best quality plant harvesting it at the utmost perfect time to have an oil where the constituents are balanced in a way that's the highest therapeutic grade and then we bottle that up and present it to you in a way that's a relative you know such a low low cost for such high value so that's why more people in the world trust doTERRA as an essential oil company than any other essential oil company in the world i told you she was passionate no yes all right so we're in my bathroom for the first use of peppermint oil i want to talk to you about and that's hair loss i have been losing my hair since my late teens and fighting the hair loss battle and it's an absolute prick of a thing now there's a couple of ways you can fight hair loss through chemicals and that's finasteride and rogaine so one you put on your scalp another one you take orally which i still take but i try and mitigate my use of those things through natural remedies so in order to maintain my push forward recido i use peppermint oil and the way i use it is through my shampoo and conditioner a couple of drops in which i'll show you in a second the way it basically works is it's got anti properties in it so antibacterial antimicrobial antiseptic and essentially according to the research what it does is it gets into the hair follicle and it helps fight the DHT and stop slow down mitigate hair loss so it's not going to grow your hair back or give you an afro but it's going to help in your fight towards hair loss hair loss hair loss now if you've got dandruff apparently it's very good for dandruff too or if you're just like a really nice cooling effect in the morning it's really good for that too essentially what i do is i put two drops of peppermint in either my shampoo or in my conditioner and then i rub it into my hair and i'll leave it there for a couple of minutes now be warned one morning i went to wipe some water away from my eye in the shower i still had some residue of peppermint oil on my fingers and it's really powerful stuff and i almost ripped my eye apart so be careful of that now the second thing i use peppermint essential oil for is diffusing and i diffuse it for concentration so when i'm working from home during the day i'll have a diffuser blowing and what it does is it blows peppermint into the air and you inhale it aromatically and it gets into your system that way and the way you do it you get your peppermint oil you put five drops in a diffuser and then you turn the diffuser on you put it in your room and it blows this peppermint oil which smells awesome as well by the way into your room and then it gets into your system there's a couple of studies that i'm going to walk you through and i'm just going to pull up my notes for this well there's two studies done right there's one was done by the university of Cincinnati and the other one was done by willing juiced university i think that's how you say it just juiced squeezing the juice so there that's a university i think it's a religious university based out of pennsylvania somewhere so the university of Cincinnati they found that the peppermint scent prime primarily the menthol component so we talked about that earlier stimulates the hippocampus area of the brain which is sort of back here and that controls mental clarity and memory the odor triggers you to wake up and pay attention so that's pretty compelling stuff right there now the willing squeezing the juice university found that drivers exposed to peppermint health benefits were more alert less tired more motivated and less irritable i think we could do with that for drivers in australia when they're driving past cyclists we need a little bit of a peppermint oil spray we can get them with they found that peppermint slowed the release of stress hormone cortisol and kept drivers calm yet awake so i haven't personally used peppermint oil on a long drive but it sounds like it's something that i should be doing so that is number two concentration and blowing it through a diffuser in your home or work environment so if you go on a google and type in peppermint oil and improve physical performance you'll get an absolute shitload of information compelling information which points to peppermint oil improving performance now i'm going to pull up my notes again because it does get a little bit technical and i want to make sure i get it right but i've been doing my research this is proven peppermint oil relaxes the bronchial smooth muscle now look that up the bronchial smooth muscle your bronchial goes down here and the smooth muscle is sort of like the inner lining of your bronchial and it relaxes it so what that means is that it enables you to get more oxygen down into your lungs now it also causes an increase in the ventilation and brain oxygen concentration and a decrease in blood lactate levels you know because it's called these anti properties the anti antibacterial anti microbial obviously lactate is something the body doesn't want tries to get rid of so what this also means is that it improves muscular energy metabolism because it's helping mitigate the onset of fatigue by reducing the levels of lactate in the blood so that's pretty compelling stuff now i'm going to pull up another study here this is from ATP scientific they did a study which revealed significant improvement in a number of physical variables after oral administration of peppermint essential oil so they had 15 in the experimental group and 15 in the control group okay and here is statistically they did some tests with grip force standing vertical jump and standing long jump now the grip force test was quite compelling 36.1 improvement in the amount of force they could put into their grip standing vertical jump increase seven percent on average and standing long jump 6.4 percent now they also did additional tests i'm going to link to this study below the video on the respiratory system which showed increases in the flow rate of oxygen in and out of the lungs okay no brainer there and when i think about my own personal use of peppermint oil okay so i put two drops under the tongue before i go out and do a ride and immediately i feel my whole airways open up even my sinus area now that sensation lasts about 10 to 15 minutes and then it sort of starts subsiding but then what i notice because i ride for long periods say three to four hours is you really feel the effects when you go into an anaerobic state so anaerobics when you're breathing more and that's where i could really feel the peppermint oil and its impact on ventilation and my body's ability to deliver more oxygen to the working muscles now to go a little bit deeper on this in february this year i did a vo2 max test now link to that video below this one but before that test i took two drops of peppermint oil okay and in that test i scored a vo2 max of 84.2 which is pretty significant for comparison Chris Froome in his tour de france peak is 88.4 and Lance Armstrong was 84 now i personally have deficiencies in my ability to reach my vo2 max at threshold so that's why i don't ride in the tour de france but it certainly demonstrates that i've got a very good ability to take up oxygen and deliver it to the working muscles now i can't prove that by taking two drops of peppermint before that test i got a much bigger number or a slightly bigger number but it is quite compelling to think of all this information that i've just shared with you and the research that i've done today and to think that i used peppermint oil before that test and scored a very high number so it's for all those reasons that i will continue to use peppermint oil for eternity one dropping in my shampoo and conditioner for hair loss two diffusing in my work environment and thirdly dropping it under my tongue to open up my respiratory system improve my cardiovascular health and also my alertness when i'm doing sport if you want to go deeper on peppermint let's have a conversation below this video and thanks for listening


Hey guys, Thundee here and welcome to the video you've been waiting for. I am talking about gaming on the Seuss ROG Phone 5. Now, the ROG Phone series is well known for its gaming prowls but this video we're going to find out if the ROG Phone 5 is truly taking back the crown as the king of gaming phones. Welcome back guys. So if this is the first time watching videos on this channel, definitely hit the subscribe button and notification icon. If you care about gaming on smartphones or just gaming in general, we do that right here. So in my hand is the Seuss ROG Phone 5 or the ROG Phone 5, whatever you want to call it. And a Seuss has done many different things on this device and we'll be looking at them in different sections. We'll cover audio, we'll cover gaming, we'll cover accessories and we'll cover just the overall functionality of this device including of course battery life. So let's start off with the aesthetics of the ROG Phone 5. In size it's 6.7 inches to some that might seem large but again that's pretty much similar to your S21 Ultra or your Galaxy Note 20 Ultra as well. So size wise, you've got something that is standard within the smartphone realm. It comes in two different colors, you've got the white and you've got the phantom black and I do like the fact that it comes in white now instead of the stereotypical gaming colors that are usually just black and red or whatever the case may be. It's a bit different, it's got a nice curved back to it and of course you do have RGB lighting with the ASUS logo at the back of the device. This of course is very customizable, you can do it directly within the software and that is really nice to see. Now in terms of the display, as you know as gamers we want something that gives us the best amount of functionality and this display is 144Hz, of course it's got an adaptive refresh rate so you can set it at auto and of course we'll set the refresh rate to match what you're doing at the time or you can manually change from 144Hz down to 120 or 60Hz if you choose and the big question is does it eat up battery life? The short answer is no but there's a much better answer so stay tuned for that within the video. Now it's not only 144Hz display, it also has 300Hz touch sampling so while you're gaming and your fingers are gliding across the screen it is so much easier to tap and move and doesn't feel stiff which is something you find with a lot of gaming smartphones. Now you have a couple other functionalities I really geared towards the gamer, you've got two USB ports, one at the bottom and then the other one on the left hand side with of course a proprietary port for the cooling fan. Now that cooling fan has a lot more functionality to it, it's got also a built-in 3.5mm jack which is great so you can do pass-through but the ability to have this side port is great so while you're gaming you can charge your device while gaming at the same time. Now at the very top on the left hand side of the device you do have your touch sensitive trigger buttons they've been more tuned to the ROG Phone 5, they've got better tuning so they feel more comfortable and also the triggers feel really solid while pressing them and of course they are quite remappable overall. When it comes to audio this is where the big part is with this device because you've got a headphone jack back now and you've got some stereo speakers which we should take a look quickly right now and then we'll talk more about it. So you just heard these speakers off the ROG Phone 5 and they do a fantastic job, they are crisp, loud and clear, I mean I put them back there and you can still hear them within the room that's because they use two symmetric super linear drivers that are powered by a mono amplifier so you're giving you that really rich loud clean sound probably the loudest I've heard from any smartphone and also the clearest I've heard from any smartphone in a while and that's that's really good. Now it's got a built-in amplifier app so you can of course change different EQs, music, gaming, movies, you can also manage your EQs in the custom fashion if you want to but the other cool thing about audio on this phone it's got a 3.5mm jack which you know I love right but that jack is also powered by ESS 92, 9280 Pro DAC and as well as also a built-in amplifier as well from ESS Sabre allowing you to drive your headphones to the best so whether you're using ASUS's Centera 2 headphones which are their gaming headphones they do a really good job actually they are really nice or you can drive something a little bit better like the DT9090 Pro which I absolutely love to take your gaming experience to the very next level the audio is so good and I like that they've done some work they're giving you that audio experience that you should definitely get as a gamer. Now how does that audio mixing with gaming you know it's time for us to go check out some gaming performance so let's take a look. So when it comes to gaming performance you can expect the best from the ROG Phone 5 powered by the Snapdragon AAA processor and a whopping 16 gigabytes of RAM in the model I have or 18 gigabytes of RAM in the ultimate edition you can expect the best performance from this device now do we need 16 or 18 gigabytes of RAM I don't think so but ASUS is giving the opportunity to have that on this device. Now when it comes to benchmarks you're looking at a Geek benchmark score of 1118 single core and of course multi cores 3661 so the multi-core performance beats out what we have with the Galaxy S21 Ultra both Exynos and Snapdragon but the single core comes in between the Exynos and the Snapdragon numbers but that is numbers and we don't care about that we saw some of that gameplay it looks smooth it looks fantastic it looked great so what kind of performance can we get with this device this is a real important part with the ROG Phone 5 so starting off with the most basic easy game that we all like to play call-duty mobile runs well runs at 60 frames per second each gameplay session I had I did multiple shorter gameplay sessions and it ran fine and it ran well the one thing to note it's not updated yet so it's not running at the max setting just the high setting it's something because this device while testing it was not available out yet so you can expect that now moving over to PUBG mobile we played roughly around 15 to 20 minutes of gameplay now what you will note is that the game setting is smooth extreme I do not have ultra HD ultra available yet so I could not test it out because again we need an update for that but playing at smooth extreme solid 60 frames per second temperatures while on this hand stayed at about 94 degrees which from roughly I believe around 32 or so so it stayed nice and cool pretty much that whole gameplay session now of course the game we've been waiting for Genshin Impact what kind of gaming performance can we get from this so when briefed by ASUS they said Genshin Impact for about 30 minutes to an hour gameplay we should be getting about 55 frames per second with X mode on so I tried that out I had X mode on I took off the cooling fan which just so you guys know it is really important and I played for about 30 minutes and 50 seconds and we got about 56 frames per second and of course Genshin's highest gameplay mode with you know 60 fps on it ran really solid really well temperatures on the other hand did ramp up quite extraordinarily here so by the end of my gameplay session at 30 minutes the screen itself was about 120 degrees Fahrenheit so that's about 50 degrees Celsius while the rear of the phone was also between 118 to 120 so it ran right a heart on this device that's something that happens now I did the same test again play Genshin Impact with the cooler on the device for 30 minutes and at playing this way I actually got 59 frames per second so pretty much close to 60 frames per second which was good to see the impact of that cooling fan enabling better performance and in terms of temperatures the display still was between 118 to 120 at its maximum while the rear of the device dropped down to about 94 to 98 degrees so it promises about a 10 decrease and that definitely shows it means that look where the processor is where cooling is most needed the fan does work and I was able to get better performance from Genshin Impact so that is something to take note if you're looking at the kind of performance you're going to be getting from this device in terms of any game you want to play it will play well it will play really smooth you can check out the gameplay clips they look absolutely gorgeous very smooth great performance a quick note on game streaming services like Stadia and Xbox Game Pass I will say using the Kinect controller it was a seamless experience it played fast smooth very responsive of course you've got Wi-Fi 6 built into this device so you've got a very clean and fast gameplay experience now with all that gaming performance you're asking how is battery life on this device so Isuzu has come up with a very interesting way of implementing battery on the ROG45 it's got a 6000 mAh battery which sounds absolutely fantastic but it's split into two 3000 mAh batteries there to effect faster charging and also better performance in the long run so with that 6000 mAh battery it comes with a 65 watt charger and Isuzu promises about zero to 151 minutes we got about 58 minutes within an hour which is fine I mean that was actually great to see in terms of battery performance and I was glad that you could actually fast charge this here but it's got a couple of battery modes that are quite interesting overall so when you look at the device you can actually schedule your battery charging if you want to which means that instead of you taking advantage of that full charge it full fast charging you can schedule the time that it will actually fully charge for you so when you're going to bed you can plug it in and maybe between two to six a.m. in the morning that's when it does this full charge and you're good to go you can also slow down that charge process so it doesn't go to zero to 100 all the way it can actually slow down from 80% and then trickle charge all the way to 100 again extending the life of your battery but the best feature that I love for gamers is kind of like this steady charge I believe is the name it's called it gives the ability to do a power pass through so when you're gaming you plug it in right using that side port and you don't want to basically use your battery and you don't want to charge the device while you're gaming because of course that might all affect performance overall what you can do is basically stop the charging and stop the use of the battery and pass do a pass through power from the charger so basically it's running from the charger you lose no juice on your device that is great for battery management it's great for sustaining battery life on this device I think they've done a really good job there so when it comes to accessories asus has done a really good job with the ROG 5 giving you enough accessories that you will definitely need and wants to use now the first one is the aero active 5 cooler we know the asus phones come with coolers in the past for the ROG phones now with the ROG phone 5 you don't get this by an accessory if you get the pro ultimate edition you will get this cooler what's interesting about the cooler it is that not only does it cool and it comes with the 3.5 mm jack it has that port for your usb type c cable it also has two extra paddles which are great because they are remappable for your gaming experience so once you use it you have four extra buttons to use while gaming on your mobile device you've got the two top touch sensitive buttons as well as the extra paddles which makes your gaming experience absolutely awesome playing games like call of duty mobile as well as also pubg it is so great to use it and it's very easy to set up now the next accessory I do like is the konai 3 and this is what it turns into when you use it together with your ROG phone 5 I love it because it gives you a full mobile gaming experience that allows you to play of course your mobile games all the way through but also your game streaming services like stadia as well as also xbox gamepass what's great is that this gives you full button layout you've also got extra buttons at the back that are remappable your ROG lights up at the back of your phone but you can take this off you can slide it back into its dock and then you've got the konai controller as a controller this is pretty good altogether this makes the gaming experience on the ROG phone pretty much to the next level and these are accessories if you want to use them to enhance your gameplay performance these are absolutely worth it now before we round up some of you are asking okay fun to eat it's got it's got cameras on there right how the how's the camera performance well simply put the cameras are okay honestly this is the part of the device that I am really bummed out about because of the pricing we should expect to see here asus has put in a triple camera system one with a macro lens that really isn't worth it the camera steels are okay and decent the front facing camera does a good job at it but I think overall the experience here is something that I expected to see better especially when asus has devices like the zen phone series which hasn't really saw the camera system I was hoping to see that here you've got video with the device as well which has a steady mode which apparently if you turn on video stabilization it cuts all recordings to 1080p or basically super steady if you will but it can record up to 8k 4k 60 and so on and so forth I would say you're not buying this device for the camera we'll give you distant photos and video but if you want a game then let's talk about it before we round up this video the ROG phone 5 we mentioned a bunch of things in this video the things I like and I don't like but overall what do I think about this device I think it's a solid phone I think it's a great gaming phone with great gaming features and all the gaming capabilities you could ever dream of in terms of taking the crown as the gaming phone I think it's back I think asus has taken that crown and they've held it strong and are calling our competitors to challenge them I think if you want to pick this up yeah definitely go ahead if you're a gamer you like to game you want something that will last you the whole day and more the ROG phone 5 is definitely worth it for you if you want to take pictures not so much anyway guys thank you for watching this video hopefully you enjoyed it and you like videos like this if you want to see more if you want to see more gaming on this device definitely head over to board gamer I do have some tips and tricks on how to use the ROG phone 5 you can definitely check out there if you have any questions or any comments let me know otherwise don't forget to like share and always enjoy your entertainment and I'll see you there


in the Chicago area because we don't have any customers. We just created the money that's owned by the partners and it's a very different kind of work experience and I'm loving it. And if any of you are in the Chicago area and interested in talking about that with me later, please feel free. I maintain the RSpec project recently released version 2.1. With the 2.0 release, the new thing that we got going is all these cucumber features are being displayed on this website called Relish App. And it's just a beautiful presentation of all the documentation of the code which is actually executed before we push it up there. You can't run it on the site but all of the documentation is actually executed against the code base and it looks like that. Beautiful, isn't it? Yeah, that's what I'm talking about. And the other little bit of good news, housekeeping stuff is the RSpec book is actually going to the printer tomorrow. I mean, after about four years ago I stood up, not at this podium, but at a podium at RubyConf and said, hey, it's gonna be Q1 of the coming year. Yeah, this time it's actually going to the printer. There's a discount code for any of you who wanna buy the combination of the print book and the e-book and this is the discount code. It's 20 underscore ACHBD underscore RubyConf in snake case. All right, 20% discount expires Monday, get it while on time, it's not even on the presses yet so. All right, but this talk is not about RSpec. This talk is about duplication. Now, we all know that duplication is a bad thing and the reason we know that is because we've been hearing about this for a long, long time. In Martin Fowler's book, Refactoring, he talks about code smells, which are things that you notice in code that kinda smell fun and one of the code smells he described is duplicated code and then Uncle Bob Martin in his book, Clean Code, said, duplicated code is the root of all evil in software design. This is actually, I think this is traceable back to Kent Beck like a few years before but I know I've heard that, that's a statement a long time, for a long time. And then of course there's the drive principle which everybody here has shown. So on the RSpec mailing list, a lot of people write in questions about the drive principle and it comes up, there's something like every week someone's asking about, how do I make this more dry? Isn't this, can this be more dry, whatnot? So I was curious and I did a little bit of research. I went to the Google and I typed in Ruby RSpec. I had to preface it, prefix it with Ruby because it turns out that there's a couple of other RSpecs in the world. There's a car, there's a Hyundai car called the RSpec. There's a spectrographic monitoring thingy that I don't know what it is but it shows cool pictures and it has to do with stars. So anyway that's RSpec and you can Google that. And then the other thing is something about swimming pools, like the S stands for swimming, S and P stands for swimming pools. Anyway so, and then I Googled Ruby RSpec dry and it turned out that 6% of the hits for RSpec also had the word dry in it. And then I thought okay well I wonder what that looks like for Ruby on Rails, right? So it did the same thing with Rails and it came back 3% though. So that was a little less but the real surprise for me came when I checked out just Ruby. Ruby language, now I had a Ruby language dry and 11%, more than 10% of all of the pages on the web that Google could find also say dry if they say Ruby and language. So people in this community really care about this. So one of these emails that I got had this subject, custom matchers, shouldn't they follow the dry principle? And basically there was a guy on the mailing list and he was trying to write a matcher library for like RESTful services, HTTP requests. And he wanted to write these two matchers. Is there anybody here who doesn't know what RSpec is and what matchers are? Good. Sure about that? Okay, one, okay. Seriously? The one who raised your hand? Okay, it doesn't really matter, it's just some code that we're not talking about. So here in this example, these are like texts, right? So they're executable code examples. And in the top one, we make a post and it says the response should be created and he wanted to create this be created matcher. And what that really meant was that we got back a 201. And then he also wanted to have an alternative which is this should have creative resource which would do both. It would check that it was a 201 and it would also verify that the object actually got created and stored in the database. And he wanted to make the underlying code for these drives, he felt that he couldn't do that. And so this is not the code that he presented to me or to the list, but I imagine that it looked something like this. So we've got the two matchers and so in both of these we say RSpec matcher is defined and then the be created and have created resource are method names, this thing defines methods. And it's important for what I'm talking about if you were to realize this actually creates two different objects, this code. All right. So, and you can see there's some duplication, right? We've got three appearances of comparing response code with the strain 201. And so he wanted to get rid of that duplication. And there's also these strings, the failure messages are very similar. In fact, they're identical because the second one could fail for two reasons, so it fails for the same reason as the first one, it would be the same message, otherwise it would be the same message. Now this is what he actually said he wanted to do. So you could see the top matcher is the same, but the code in the bottom one changed a bit. And so let's look at what happened here. So he said, I wanna be able to depend on the other matcher because the other matcher already does this comparison between response code and the string 201. But what he's doing here is he's creating this instance of another matcher and then calling the matches question mark method, that's a Ruby predicate, which is part of the underlying matcher framework. It's not part of the matcher DSL. So there's two problems that are introduced just by that one line of code. One is we're creating this dependency between the two matchers. And the other is we're letting the abstraction leak the internals up, right? So both of those are bad things to do. Similarly here in the be created and calling the failure message for should, it's calling it on the be created matcher. And again, we're depending on what's happening in the other matcher in order to do this. And now this one's a little bit more subtle, but what's going on here is there's this instance variable at message. And in this case, the part of the code that's manipulating that bit of data is not the same part of the code that we're gonna use to access it, right? So there's a weird dependency here. First of all, just looking at the code at the failure message for should block, you don't really know what's going on right away with that data. And second of all, they have to be called in order for this to work. Now it happens that in this framework, that's gonna happen. Framework calls them in order, but that's a weird sort of dependency to have in the code. And so by reducing the duplication in this way, the end result is that we've increased the coupling between the two matchers. And this is really true. Every time you reduce duplication, you're gonna add new dependencies and you're increasing coupling. Both of those things are bad things. Well, they're not both bad. Dependencies we have to have, right? The important thing is to be able to manage them. And so it's important to depend on the right things. So how do you know what to depend on? Well, there are a number of principles other than the drive principle that help us figure that out. So one such principle is called the dependency inversion principle. Now, it's a little bit more complicated than this, but the gist of it is depend on abstractions. Now, that comes out of that it was originally described in the context of statically typed languages. And in Ruby, kind of everything's an abstraction at some level, right? So in terms of trying to apply this to Ruby, we can rephrase it like this, which is depend on the things which are less likely to change. Because that's the reason we want to depend on abstractions in statically typed languages because the high level, the method names are not the things that change, it's the underlying implementation. All right, so with those things in mind, let's take a different look at how we can refactor this. So we still have this duplication where we're calling response code and comparing it to 201. The real problem here, the duplication is this magic number 201 represented in a string that keeps coming up. We all know that 201 has this meaning for us, which is that it's the status code to get back that says something got created. But, and this is sort of an unlikely example, but imagine that that code changed. We have to change it in all three places, right? So obviously it's unlikely to happen in this case, but a typical thing to do would be to give it a constant so that it's only defined in one spot. And then that way, if it ever does change, you change it to the one place and all the other places that reference it get the benefit of that change without having to change themselves. Another thing we could do is actually just add a method right onto the code object. It's a string, most likely. And we could just ask it, are you the created status code? So let's leave that there now. And then we've got these two strings that are identical. So rather than trying to have one matcher depend on the other matcher, we can have them both depend on something else. We can have this failure messages. I'm sort of making this up as I go, but this would be a perfectly reasonable solution. Have this object that creates failure messages for us. Give it a little bit of an API that makes sense in the context of the matcher. So failure messages, expected response code for created and gotresponse.code. And that would create the same message in both time, in both matchers. And if we ever wanted to change that, we would change it in one place. But now that we've done that, even though this bit here, this other failure message isn't duplicated anywhere, at least in what we're looking at here, it still looks different from all the other failure messages. We've got this sort of imbalance in the level of abstraction where we've got a concrete little here with that string. And so compared to calling out to the failure message generator. So there's sort of, I don't know that there's a principle for this. If someone knows of it and can tell me now. A slap. Huh? The what? Single level of abstraction principle. And is that, did you just make that up, or does that actually? I made it last year, so. Okay. So the slap principle. There it is. And so what we can do to apply the slap principle in this case is just do the same thing. We just put a method on the failure messages object that will create this message for us too. And when you move code around like this, nice things happen. Like all of the messages start to get created in the same place. And when we make decisions that oh, we don't like the way they're phrased, that they're all in one place. It's just like the stuff we do for I-18N where we put everything in a Yaddle file and all the doxters are in one place and you can scan them and see them all next to each other. So this is a little bit more balanced. It's, we've got, there's a little bit of duplication in terms of the characters that are written, but we've removed the parts of the duplication that are gonna buy us, which are the things that are gonna change. So the motivation for that, of course, is the drive principle. So I'm gonna tell you a little story. I was visiting my girlfriend's family in Brazil and this is her niece, Bruna. Bruna is four years old and Bruna came up to me while I was preparing these slides to do a presentation down there. And she said this to me. I'll translate it for you, but she said, I have a computer with a computer. I have a computer with a computer. And I asked her to slow down and she actually did a great job and she said it very slowly. And what it meant was, I have a computer and then this part of the end, Jim and Chiara, I didn't really understand what she said or what that meant. And so I'm learning to speak Portuguese and so I did the thing that I do when something sounds similar to an English word. It kind of sounded like, demented to me. So I imagined that she had said to me, she has a demented computer and I was perfectly happy to live with this perception of what she had said. So a little while later, I was talking to her cousin who's an adult and the cousin said, no, no, no, it's actually two separate words. It's de menchia. And I didn't know what menchia meant. So it still didn't help me that much. So I imagined, okay, what's another word that I know? There's this other word menchi, which means mine. So I thought, okay, it's a computer of the mind. So it's an imaginary computer. She has an imaginary computer. And I was perfectly happy with that too. And I went on for another half hour, hour of my life, believing this misunderstanding of what she had said. In the end, it literally means of lie, like untruth. And so she had the toy computer and I had the computer David Dodger, which is the computer of truth. So this made me happy as well. So here's the thing. The reason I told that story is because there was this period of time where I'd heard something and I was satisfied with my understanding of what that meant. And there is probably a fair number of these people in this room I'm gonna guess. Like how many of you think the dry principle is don't repeat yourself? Oh, that's good. Okay, actually, that's not what the principle is. That is a device for you to remember what the principle is. The principle is actually this. And this is what's printed in the book, The Pragmatic Program. Every piece of knowledge must have a single, unambiguous, authoritative representation of that system. So we're talking about pieces of knowledge. Bits of information, things like 201 has a meaning which is created. That should have one representation somewhere in the system. And there should be one representation. It should be unambiguous and authoritative. And what that's about is, and I think, I don't know, Dave and Andy were at this part together, I imagine, but they were talking about, so if you have a situation, consider active record, where we have representations of the attributes of a model that live in a couple of different places. They're in migrations. They're ultimately in the database and then they're in the schema file. But really, there's only one authoritative source for that. We write migrations and we generate the schema file from that and that generates the right time information about what those things are. So even though it appears in a couple of different places, it's still dry in that case. So with that in mind, let's look at another example. I'm working on an app at the company where I work and this is an application for allocating things to other things and there's a part of it that's a little Java web service and we're using this framework that asks us to represent the different paths in this manner. So some people might look at these three strings. I know they're kind of small, but I'll show them a little bit bigger in a minute and think, oh my God, they're all exactly the same. There's a lot of duplication here. Let's see what we can do to dry this up. So the first thing you notice is that each one starts with the word allocations. So we'll put that in its own constant and then we could use that constant in the generation of the other three, which are the actual paths that we're interested in. Then the next thing you notice is that source type shows up at the beginning of each so we can pull that one out also. And then you've got the same thing with target type and target ID and the year and month keeps showing up as a pair so we can put those all in their own constants. And so, okay, that's kind of nice. Maybe it's a little bit bleeder. There's no duplication, but still like source type and source ID, they both start with source, right? And then source type and target type end with type. And there's all these slashes and curly braces everywhere. So why don't we take those and we'll stick those in a red. And so now they only show up once. And then, so the problem now is you've got these lines in the middle that all start with delimiters, you're in a one and end with delimiters two. So we put those into a method and so you can clean it up a little bit. Here's the thing that's awesome about this. Imagine that we decide we're gonna go from snake case to camel case. I mean, the other way around from camel case to snake case. So all you need to do is go to the ID, make the I lower case and put a underscored front of it, do the same thing with type and you're done. Amazing. All right. So, what's that? I'm making a joke. Here's actually the point. Imagine there's a test failure or something goes wrong in production and I see that, hey, someone was trying to get to this path and I need to look at this mess and figure out which of these paths this thing lines up with. Compared to this, with all that duplication, you can just look right at that, scan those three paths and go, oh, it maps up to the middle one. So we started off with some strings with some duplicate letters and words. We said, oh, that's not dry enough and so we tried to make it drier and drier and drier and eventually ended up with something that's absolutely useless and silly, right? So the point of that is that dry doesn't mean don't type the same characters twice. That's not what it's about. And the reason I'm carving on this is because I see this all the time. People go way out of their way to reduce every single possible thing and it can make code really unreadable. And the underlying issue that Dry is trying to resolve is about duplicated concepts. It's about isolating change so that when changes come in, you only have to make the change in one place. All right, so you see some duplication and so how do you know whether it's really a problem or not? So think about its purpose. So in the case of the matchers, there's some kind of calculation there. There's some, it's doing some comparison. Whereas the strings are just there to represent patterns that you should be able to scan. So they're functionally very different things. Think about the risk of changing more and not changing that particular code. What happens if we leave the duplication from the strings in place? Well, maybe we'll get four, five, six, seven more of those and it'll be a longer set of strings but we still want to be able to scan them. So in that case, it probably makes sense not to change them whereas with the matchers, as it gets more complicated, we really do want to pull out the things that are duplicated and the risk is that you're going to have to change it in more than one place. And here's the thing about that. It's not about typing. It's not about the tedium of having to change it here and then having to change it here. The problem is that you go and you change it here and you don't realize that you've got to change it here also and you've got two different parts of the system that are behaving differently that should be behaving identically. That's the real risk that Dry is trying to help sell off. You might forget to change it in the other place. So, a little more about duplication. It's not always obvious. So for example, you can have a name that's used to represent two different things. This is one kind of duplication that's a little more subtle. And so, as an example, in that this allocation app I was telling you about before, let's say that we're allocating me as an employee to three different projects at these percentages. So, there are people who work with this application through a browser and they have to type in the percentages. And for whatever reasons, they want to type the percentages in as 50.0 meaning 50%. But the accountants who read the reports want to see 0.5 to mean 50%. And they both, both groups of users have really good reasons that that's how it should be. So, that's what we have. The problem here is that we've got this one word percentage and if we're looking at a browser, it gets represented as this whole number. Well, it's not a whole number, but greater than one, 50.0 for 50%. And in the reports, it's this other thing. And we have to store it in a database somewhere. So, we store it as the 0.5. And the way we do that is whenever we create one of these objects, we divide it by a hundred as we're creating it. And so, this was actually duplication that came out of this, right? You see this everywhere that we're creating one of these things, we have to divide it by a hundred. And we actually move, we tried to move that into the method itself so that inside the object, it would just do the conversion for us. And that ended up having some weird bug with active record where if you have a collection and you create, you add something to the collection and then, so you find the object, you haven't loaded the association yet. You create a new member of that association collection and then you iterate through all of the members of that collection. It goes and gets the full list from the database and starts instantiating objects. And I think what happens, I haven't been able to prove this yet, is that it says, hey, I've already got this object with this ID so I'm just gonna throw these attributes at it and it ended up dividing by a hundred twice. So we got, we ended up with the wrong number, which was crazy. Luckily that happened while we were in the middle of doing this refactoring and it revealed itself. Anyway. And then anytime we wanted to display the percentage in a browser, we would multiply the number. So the solution that we're in the middle of working towards right now is this.  Now you could argue that that's a dry violation itself because these are kind of the same thing. And now we have two names for them. But really in the context of the group that we're working with, this clarifies it. Everybody knows we mean 50.0 for percentage and 0.5 for the ratio. And then in terms of how the data gets stored, it gets stored as the ratio and whenever we're talking about it with the object as a percentage, we do the math in there but we store it as the ratio. Now all works out just fine. And then now all the code that uses it can just use it, no problem. And then in the report it says ratio to end of report. So that was same name to your meeting. Here we've got the same meeting with two different APIs, which is sort of the opposite of that. So in the pragmatic programmer, when they're talking about duplication, they give this example. It's a class called line. And you initialize it with three arguments. A start point and end point and the length. So the problem with this, and we're focused on it right now but if you were just scanning this code, you might not notice. Can anybody tell me what the duplication is? Wait, I don't know. Huh? I was pointing to you but I'm really sorry, I can't hear you. You don't need the length, right? So the problem, the length is actually duplicating something we already have. The problem is there's two ways now to represent what the length is. One is whatever the client of this that creates it passes in and the other is figuring out the distance between the start point and the end point. And so you end up with a bunch of client code that has to calculate this and you potentially have a bunch of different versions of that calculation where what we should really have is this. You create it with the start point and end point and you let it do the calculation. And that sort of duplication is really hard to see because the names aren't the same, the structures aren't the same. So just be aware of that. It appears naturally and you'll see it one day and you should get rid of it. All right, another kind of duplication is structural. So here we have this first object that's got a collection of addresses and there's one that's a primary address. So we have this primary zip code method and so we go into the addresses and we say, hey, which one of you is primary? And if we get one back to use that, if not, we say, well, it's gonna be the first one and if we still don't get anything back then we don't return anything at all. But if we've got something back at that point, we return the zip code from that address. So we have a new requirement that comes in to have a primary phone number. And what do we do? We copy from one to the other and we change the name and now we have this perfect duplication that we can get rid of easily. We'll talk about that in a minute. But the thing is that this is all very easy to see when you're looking at no other context. There's no other code floating around. But this sort of duplication can appear in ways that you don't know. For example, imagine that originally this primary address is called a main address and when the name got changed, whoever the developer was didn't change the name of the local variable inside the method and so they don't look exactly the same even though they're really close in structure and that's pretty obvious right now. But maybe it was formatted a little bit differently. This is functionally the same but it doesn't look exactly the same. So be aware that duplication isn't always that obvious. That's sort of the point of that. So when you have duplication like this, the thing we do is we extract a method. And so here's what that might look like. So we've got the primary zip code and primary phone number methods are both calling to this primary address method. The thing is, there's another thing going on here. There's another code smell that should be making your nose twitch at this point. So the primary address method is going into the collection. It's iterating through everything in the collection and it's saying, hey, are you the primary one? And then if it doesn't get back one, it goes into the collection again and says, hey, give me the first one. And if it doesn't get anything back then, then it creates a new one. So this is a code smell called feature envy. And for those of you unfamiliar, the idea behind feature envy is you've got two objects. This one wants to do some operation and this one has all the data. And so this one says, hey, give me all your data and I'll do the operation. And it might even send it back updated data. And really we want to have the operation live where the data is. So solution to that might be something like this. We can have an address collection and it has the primary method on it. This is functionally the same as what we looked at before. But if you look at our primary address method now inside the person, it doesn't have to go into the collection and do all this manipulation. And the reason that that's valuable is because this isn't the only code in the system. There's probably a lot of other code in the system that wants to care about the primary address. So now we've got that piece of knowledge, how to get the primary address expressed in one place in the system that everybody else can use. So let's talk about specs. So let's imagine that on this person object we're gonna have this is like some system where you could create events that are happening in different locations. And the person has a distance to event method. And this is what we say about it before we write any code. We say, okay, so if a person has one address and it doesn't have a zip code, we should get back nil instead of throwing an error. It should handle that gracefully. So, and this is how you might implement this code example. Now the thing is, there's probably a bunch of other examples in here. This is just the one. So maybe within the with one address, with no zip code context we would pull out a before line. And assign a value to this person instance variable. And that's all fun right now. But what I've seen happen quite a bit is now you recognize, you know, the with one address context, the one right up above, we're gonna need to create a person with one address up there too. And we don't wanna have to duplicate that. So let's have two different before blocks, right? So the one in the outer context creates the person with one address, the one in the inner context, makes sure that that zip code is nil. And then we can take it a step further and say that everything in this file is gonna need a person. So we'll move that up to a before block at the top. And this is all very dry. Everything's represented once, but the problem is it's very difficult to figure out where you are if there's a problem. You have to go scan through all of these different before blocks rolling up the context, right? So we're reducing duplication, but we're introducing more interaction. And that's not an inherently bad thing, but it can make it harder to reason about the code. And when we're dealing with test failures, the last thing we wanna do is go chasing around our entire app to figure out what the hell's going on. You want to be able to look right at the example that's failing and understand the failure right away. All right, so, and then along those lines, this is a little bit different example, but. So when you first make a person, the rule is that person should have no friends. Someone has a good joke about that. So now there's another way we can express that, which is we can do this one line. So for those of you who aren't familiar with the way this works, the fact that it says describe person, we know we're dealing with a person class. And so, in the middle where it says it, and then the first method is should inside that block. When that block gets evaluated, our spec knows that we don't have a receiver for that method. So it goes and creates an instance of person and then passes that over. So these two are functionally equivalent. And you can see that the one on the bottom is a little bit less code. And we don't have the duplication between the name, right? It has no friends and then person, you should have no friends. There's like duplication in the top one that we don't have in the bottom one. This is okay for me. One of the things I really care about with our spec is what does it look like when you run these and you look at the results of it, right? So the top one's gonna create this. So person when first created has no friends. The bottom one is gonna automatically generate its own doc string and it'll say person when first created should have zero friends. So that's good enough. It gets the same point across. The problem is that this tool becomes like the golden hammer for a lot of fun. And so let's say you've got something like this. We've got a calculator and the add method should return the sum of the operands provided, right? So here's how you can drive this up using a couple of things in tools in our spec. And sure, there's less code, but it's also a little bit convoluted in this context. Like you can't really figure out, I can't look at that without studying it and make sense out of what it is we're trying to test. What are we specifying here, right? And the other thing is that the output of the top one reads like the spec, right? Calculator add should return to the sum of the operands provided. The bottom one says this. Calculator should equal five, whoo, right? So it's really important to understand context when you're making decisions about these things. What are the implications gonna be if I remove this through the patient already? So here's another issue is metaprogramming. We all love Ruby. We all love the fact that we can do metaprogramming, but sometimes we do it in places that aren't necessarily that helpful and create additional problems. And so here's a good example of that. So the person again, it's got these three methods. And if you look at the three methods, they look really similar, right? First name, last name, full name, and they're just returning the instance variable. So a really common thing to do is to make that into an array and then use the define method method to define these methods. And that's cool. We saved a few lines of code, but the problem with this is that if something fails and you start running your debugger, well, your debugger might put you in here, but you're not gonna be able to just scan and find this method. And that's the problem with this sort of approach. And now it has a really important place in the code we write, which is that when you don't know what the runtime conditions are gonna be, that's the time that you would create methods using this. So like again, bringing up active record, we have these dynamic finders that say find by username for a user, right? Active record can't know that there's gonna be a username property attribute, but it's able to create this method at runtime. So you can call it, what actually happens is method missing captures it and then it defines the method at that point. So that's a really good use of metaprogramming because you can't know, right? So it's great for that kind of situation. There's a lot of other situations that metaprogramming is great for, but again, it can make code hard to reason with. Okay, I think there's the last thing I wanna talk about, which is Rails controllers. So here's some code.  This is without all of the comments and it's also without all the respond to blocks. So we'll assume we're just dealing with HTML here. And this isn't the whole file where I'll show you the rest of it. So we've got this duplication here in the show and edit method. In both of those, we use params id to find a widget, assign it to the widget instance variable that gets exposed up to the view. And then it's the same thing happens in the update and the destroy methods. So based on what I was talking about before, pretty much in every other language that I've worked in and teams that I've worked with, the sort of instant reaction to this is to extract a method. So we would extract the assign widget method and then we call it from these more different locations. But this is not what we do in Rails because we have before filters. So typically what people do in Rails is something like this. We still create this assign widget method at the bottom, but you can see at the top we're declaring a before filter named assign widget and we're gonna do it on these four actions. And now there's no code in the show or the edit and there's a little less code in update and destroy. And then if we look at the other actions, yeah, those four are the ones that are all taking advantage of the, not index, sorry. Forget that I circled index, but show and edit and update and destroy at the bottom and we're all doing it. But there's also view and create. Both of those are assigning something to the widget. So the next step you might take is to take those bits of code, even though they're slightly different, and move those down into this assign widget filter. And by the way, I'm not making this up. I saw a blog post that actually recommended doing exactly this. And I believe it's the wrong direction, so feel free to disagree. But so anyway, so now we have this before filter up here, assign widget only for the six actions, so maybe we can make that a little bit smaller by saying accept for index. And then here's what the whole code looks like now. Now this is just stop out of the box, generated scaffold functionality, refactored to remove some of the duplication. Now here's the problem with this approach. Let's say something goes wrong with the create method. I go in and I look at the create method, and I look at it and I say, okay, the first line says, okay, widget saved. So there's this instance variable widget. Where is that coming from? I'm in a Rails controller, so it must be before filter. So I go up here and I look and I see, okay, there's this assign widget method, and it's used on everything except the index, so that must be being invoked before this method comes in front. So let me go see what the assign widget method does. So the assign widget method says if there's an ID in the parameters. So that happens in the, there's an ID, so in the edit and the show and the destroy the update, I think. Right, so if it's any of those, then we're gonna get it, find the widget from the ID. Otherwise we're gonna use the parameters actually we've got the widget from the parameters actually create one. And by now I have no idea where I started, right? I don't remember what method I even came in to look at, right? It was the create method. But the point is the amount of code that we're saving here to use this as a before filter is very small. And if we were to just call directly out of each method, we'd be able to look at each of these methods and know exactly what's going on. Now before filters are great for certain kinds of things. They're great for filtering. That's why they're called filters, right? So what do we mean by filtering? We mean things that should happen before we ever get to this method. Things like logging, things like authorization, right? That's what filters are intended for. And so at some level this making use of it as a tool to get rid of duplication is kind of using it in a way that it's not really intended. And it ends up creating problems. And I speak from experience here because I've been working on Rails apps for a while now and I've been in this situation where I'm trying to figure out what's going on and it's buried in some filter somewhere. And it's part of the method. It's part of the function of that method. It's not part of something that should happen before we ever get to the method. So filters can make it harder to reason about code. All right, I've got a minute and 22 seconds left. So wrapping up, many problems in software can be traced back to duplication but not all duplication is inherently evil. Duplication comes in many forms. Duplication appears for many different kinds of reasons. The dry principle is actually this. Every piece of knowledge must have a single unabiguous authoritative representation within a system. This is not about duplicating strings of characters, it's about duplicating concepts. And remember that every time you reduce duplication, you also increase coupling with new dependencies. So you want to manage this so it depends on things that aren't going to change that often. Learn about code smells. We talked about duplicating code. We talked about feature envy. Here's a few others. Get the refactoring book and learn about all the different code smells. Learn more principles. Dry is a great, great, powerful principle but it's not the only principle. We talked about the dependency inversion principle. That's one of the solid principles that Uncle Bob Martin described in the book, Agile Software Development. And there's three P's, principles, practices and patterns and I can never remember which order they go in but Agile Software Development. And then also the Prags, they have this article called OO in one sentence and the sentence is keep it shy, dry and tell the other guy. So we've talked about dry. So shy is about keeping, not revealing too much of yourself. Like if you're an object, you should keep all your data to yourself. It's kind of about data hiding but it's also about reaching across and getting stuff. And tell the other guy is a device to remember the tell-don't-ask principle which basically says it's better to tell another object to do something than to ask it for stuff that you can do things with. And that's it. So are there any questions? I'm a little bit over time so you're on your break time right now. But if there's, I can do a couple. Yeah, go ahead. Can you give controllers a little bit or I'll turn it into controllers just leaving it as is? I think it would depend on what the whole controller, the question was what would I do in the case of the controller that I showed. So I would either leave it as is or I would extract out separate methods for the different kinds of ways we want to instantiate the widget in that case. Part of the problem with that is that this filter actually had some logic so it was gonna behave differently depending on which action it was called before. And it's really hard to like map all that up. Even in the simple example when you just have the seven base actions but as soon as you get into a real controller and a real app and you have more actions, you have more stuff going on, it becomes really, really hard to figure it out. So hope that helps. Anybody else? Oh wait, there's one more. You raised your hand halfway so you get half a question. What do you have to say about dry and then performance? In that line example, if you wanted to sort by distance and distance was a pretty big calculation, you want to store those in the database, then maybe it would be a good idea to store the distance. Yeah, but you could do that. So the question is what about dry against performance? And the example he's bringing up is the one about the line class. So in that case though, you could do the calculation when you instantiate the object or you could do the calculation the first time someone asks for it and then store that in the object and keep returning the same one. The point is the calculation gets done in one place and not in multiple places. So these things don't have to work at odds. Yeah, so. All right, thanks very much.