1 00:00:16,800 --> 00:00:18,400 ANDY MALEH: Sorry everybody. I lost the slides. 2 00:00:18,400 --> 00:00:20,560 I had to reconstruct them right now. 3 00:00:20,560 --> 00:00:24,280 Right, like in ten minutes. 4 00:00:24,280 --> 00:00:26,560 Ultra light and maintainable Rails wizards. 5 00:00:26,560 --> 00:00:29,880 Who has written a wizard in their lifetime? 6 00:00:29,880 --> 00:00:34,490 OK. It's, it's almost like the most common web 7 00:00:34,490 --> 00:00:40,400 use case, yet it's the least under, under-valued with 8 00:00:40,440 --> 00:00:44,670 regards to providing patterns for doing, like, writing good 9 00:00:44,670 --> 00:00:47,350 code in order to provide for maintainable wizards. 10 00:00:47,360 --> 00:00:52,620 A lot of the time, people write, like, multi-step 11 00:00:52,620 --> 00:00:54,010 wizards, where they end up doing a lot of 12 00:00:54,010 --> 00:00:57,680 copy-paste between the steps or between a bunch of 13 00:00:57,680 --> 00:01:00,350 controllers. And that makes it a hell of a 14 00:01:00,360 --> 00:01:02,650 problem to maintain that code a year or two 15 00:01:02,650 --> 00:01:04,280 later. And every code base is, you know, meant 16 00:01:04,280 --> 00:01:06,570 to be created for a year at least. Maintenance 17 00:01:06,580 --> 00:01:09,360 cost is what's really expensive. It's not, you know, 18 00:01:09,360 --> 00:01:11,580 I can write a wizard in two weeks but 19 00:01:11,580 --> 00:01:13,360 will I be able to maintain it cheaply over 20 00:01:13,360 --> 00:01:16,890 a year. And that, that's really why I'm giving 21 00:01:16,890 --> 00:01:18,970 a talk about this subject. 22 00:01:18,970 --> 00:01:22,120 So just to give you an overview, I'll be 23 00:01:22,120 --> 00:01:25,800 talking about, why do we even use a wizard? 24 00:01:25,800 --> 00:01:32,280 Provide an example. Some implementation goals. The 1001 wizard 25 00:01:32,280 --> 00:01:36,370 implementations out there. And, finally, I'll talk about what 26 00:01:36,370 --> 00:01:37,950 I think is a good ultra light and maintainable 27 00:01:37,960 --> 00:01:40,250 wizard approach. 28 00:01:40,250 --> 00:01:45,110 So first of all, we don't want to overwhelm 29 00:01:45,110 --> 00:01:47,530 the user with a huge form of information, kind 30 00:01:47,530 --> 00:01:49,910 of like those government forms that we have in 31 00:01:49,940 --> 00:01:55,810 Canada. So I come from Montreal, by the way. 32 00:01:55,820 --> 00:01:58,790 This is painful on a computer screen. Computers should 33 00:01:58,800 --> 00:02:03,370 enable people to do better than actual physical paper. 34 00:02:03,370 --> 00:02:05,320 So one way of tackling this problem is to 35 00:02:05,320 --> 00:02:10,979 divide it into multiple steps in a wizard. 36 00:02:10,979 --> 00:02:15,641 So also it's about simplifying the workflow into multiple 37 00:02:15,660 --> 00:02:18,020 steps that make them digestible, just like this protein 38 00:02:18,020 --> 00:02:23,520 shake. And finally it, it gives you the opportunity 39 00:02:23,520 --> 00:02:26,740 to provide more explanation for what each form does, 40 00:02:26,740 --> 00:02:29,570 by being able to fit more information when you 41 00:02:29,570 --> 00:02:31,950 break it up across multiple pages, like what they 42 00:02:31,960 --> 00:02:33,970 do with TurboTax. 43 00:02:33,970 --> 00:02:39,060 Who here has filed their taxes? 44 00:02:39,060 --> 00:02:42,510 Yeah. I did not. I just did this so 45 00:02:42,510 --> 00:02:47,090 I see who raised his hand. 46 00:02:47,090 --> 00:02:53,700 OK. So I had a, a software architecture gig 47 00:02:53,740 --> 00:02:56,900 at EarlyShare about a couple of years ago where 48 00:02:56,900 --> 00:03:00,880 I helped them launch their site. EarlyShare is kind 49 00:03:00,880 --> 00:03:04,520 of like KickStarter or Indiegogo, except it's focused on 50 00:03:04,520 --> 00:03:09,290 allowing people to do crowd investment in businesses. 51 00:03:09,300 --> 00:03:11,650 And it was a website that was being built 52 00:03:11,650 --> 00:03:13,960 fast in order to catch up with some legal 53 00:03:13,960 --> 00:03:19,770 laws in the U.S. that would allow crowd investment. 54 00:03:19,780 --> 00:03:24,020 So I helped them launch the site and they 55 00:03:24,020 --> 00:03:29,000 had, they, as part of their website, they needed 56 00:03:29,000 --> 00:03:32,800 a couple of onboarding wizards. One for investors and 57 00:03:32,800 --> 00:03:36,290 one for business people. 58 00:03:36,290 --> 00:03:38,579 But there were other requirements. Like, the business was 59 00:03:38,580 --> 00:03:43,541 bootstrapped. We were only two developers. Me as the 60 00:03:43,541 --> 00:03:45,820 senior and then there was a junior with a 61 00:03:45,820 --> 00:03:49,240 CTO and a designer and that's it. He wanted 62 00:03:49,240 --> 00:03:51,329 us to move super fast, and I was brought 63 00:03:51,329 --> 00:03:54,591 in as the Rails expert. 64 00:03:54,600 --> 00:03:56,560 So I had not written a wizard in like 65 00:03:56,580 --> 00:03:59,140 four years before that. Or maybe five years. Like, 66 00:03:59,140 --> 00:04:02,170 maybe since the days I did Java development. And 67 00:04:02,170 --> 00:04:04,580 when I started tackling this problem in Ruby, you 68 00:04:04,580 --> 00:04:05,960 know, I like, I went online, checked some Google 69 00:04:05,960 --> 00:04:11,030 guides and all that or StackOverflow, whatever. 70 00:04:11,030 --> 00:04:15,689 And none of their approaches satisfied me. So let's 71 00:04:15,689 --> 00:04:17,959 talk about what I found. 72 00:04:17,980 --> 00:04:20,551 So the wizard example, though, is basically, you have 73 00:04:20,560 --> 00:04:23,629 four steps. Step one is collect basic info. Step 74 00:04:23,629 --> 00:04:26,641 two is details, more details. Step three is upload 75 00:04:26,641 --> 00:04:29,640 some document content. Step four is just preview before 76 00:04:29,640 --> 00:04:32,409 you finish the wizard. And then once it's done, 77 00:04:32,409 --> 00:04:34,870 it shows you a summary, like a landing page 78 00:04:34,870 --> 00:04:38,401 for the project that, that the business is proposing 79 00:04:38,420 --> 00:04:40,420 for investment. 80 00:04:40,420 --> 00:04:46,700 OK. So, I mean, the goals I had was 81 00:04:46,700 --> 00:04:49,029 the Rails server had to persist every progress on 82 00:04:49,029 --> 00:04:53,251 every step. So no, like, js client-side tricks. That 83 00:04:53,260 --> 00:04:56,851 was out of scope. I wanted it to still, 84 00:04:56,860 --> 00:05:00,869 like, be RESTful, like, which is a common issue 85 00:05:00,869 --> 00:05:03,200 with wizard, like, building wizards. How to make them 86 00:05:03,200 --> 00:05:05,080 properly RESTful. 87 00:05:05,080 --> 00:05:09,460 I wanted to also stick with MVC, object-oriented principles 88 00:05:09,460 --> 00:05:11,841 because we're using an object-oriented language. So I wanted 89 00:05:11,860 --> 00:05:13,599 to make sure that the code is maintainable by 90 00:05:13,600 --> 00:05:18,200 other developers going to the feature. 91 00:05:18,200 --> 00:05:22,151 And then some non-functional requirements, like productivity. So that 92 00:05:22,151 --> 00:05:26,749 was part of the concern that the CTO had, 93 00:05:26,749 --> 00:05:27,890 which is he wanted us to move fast, like, 94 00:05:27,900 --> 00:05:30,500 really, really fast. That was part of the reason 95 00:05:30,500 --> 00:05:32,291 why he brought me in. Well, big mistake. I, 96 00:05:32,300 --> 00:05:36,330 I pay attention to details and nice design concerns. 97 00:05:36,330 --> 00:05:38,409 So I will slow him down but for good 98 00:05:38,409 --> 00:05:38,740 reasons. 99 00:05:38,740 --> 00:05:41,050 I'll slow him down and then he'll go much 100 00:05:41,050 --> 00:05:44,060 faster later on. 101 00:05:44,060 --> 00:05:48,840 Still, the story does have a happy ending. So 102 00:05:48,840 --> 00:05:53,521 maintainability, by both junior and senior developers. They had 103 00:05:53,521 --> 00:05:57,069 one senior developer in Brazil as well. Which I 104 00:05:57,080 --> 00:05:59,760 just remembered. He was brought in a little later 105 00:05:59,760 --> 00:06:01,520 on. 106 00:06:01,540 --> 00:06:04,310 Performance concerns. Security concerns. 107 00:06:04,310 --> 00:06:06,990 So it's pretty, it's pretty basic stuff. Like, I 108 00:06:06,990 --> 00:06:08,920 mean, these are the concerns that we should care 109 00:06:08,920 --> 00:06:13,320 about whenever we build any feature, really. 110 00:06:13,320 --> 00:06:16,540 So one approach that I've seen on actual code 111 00:06:16,540 --> 00:06:18,380 bases, I actually saw it on a code base 112 00:06:18,380 --> 00:06:21,270 that I maintained on a following project after that 113 00:06:21,270 --> 00:06:26,920 one, was one controller per wizard step. 114 00:06:26,920 --> 00:06:31,190 So you create a REST resource per wizard step. 115 00:06:31,200 --> 00:06:36,990 And you had multiple controllers, multiple sets of views 116 00:06:37,000 --> 00:06:39,130 and helpers. And then each controller redirects to the 117 00:06:39,140 --> 00:06:41,630 next one. So something like this. And you could 118 00:06:41,630 --> 00:06:44,680 do it either with one ActiveRecord that has conditional 119 00:06:44,680 --> 00:06:46,281 validations for each step, where it says OK, if 120 00:06:46,281 --> 00:06:49,679 step one, validate presence of name, if step two, 121 00:06:49,680 --> 00:06:52,501 validate presence of blah, blah, blah. Or you could 122 00:06:52,501 --> 00:06:53,750 have multiple ActiveRecords. 123 00:06:53,750 --> 00:07:01,850 But either way, who here could find concerns with 124 00:07:01,850 --> 00:07:03,831 this approach, or at least something that could be 125 00:07:03,840 --> 00:07:07,468 improved on? Somebody volunteer? Go ahead. 126 00:07:07,468 --> 00:07:09,590 AUDIENCE: [indecipherable - 00:07:10] 127 00:07:09,590 --> 00:07:13,660 A.M.: And what's the concern with that? So what 128 00:07:13,660 --> 00:07:18,420 if you have a whole bunch of controllers? 129 00:07:18,420 --> 00:07:21,360 AUDIENCE: [indecipherable - 00:07:16] 130 00:07:21,780 --> 00:07:26,030 A.M.: OK. I mean, I've built applications that managed 131 00:07:27,340 --> 00:07:34,340 user profiles, user accounts, blog posts, for example, whatever. 132 00:07:35,300 --> 00:07:36,651 You need a controller for each one of those. 133 00:07:36,651 --> 00:07:38,439 I don't think you could escape that. 134 00:07:38,440 --> 00:07:40,890 So I'm gonna give other people a chance to 135 00:07:40,890 --> 00:07:42,601 talk, but I do get your point. I want 136 00:07:42,601 --> 00:07:43,649 to clarify it. 137 00:07:43,649 --> 00:07:44,441 Go ahead. 138 00:07:44,441 --> 00:07:46,849 AUDIENCE: I was gonna say repetition- 139 00:07:46,849 --> 00:07:47,640 A.M.: Exactly. 140 00:07:47,640 --> 00:07:49,241 AUDIENCE: Re-usability and dependencies. 141 00:07:49,241 --> 00:07:51,830 A.M.: Yeah. So quite a bit of that code 142 00:07:51,830 --> 00:07:53,790 is repetitive. It was just, it was always loading 143 00:07:53,800 --> 00:07:58,059 the resource. It's almost the same resource. Actually, if 144 00:07:58,060 --> 00:07:59,900 you use one ActiveRecord, it is the same resource. 145 00:07:59,900 --> 00:08:03,070 And then we'd run some validations and then it 146 00:08:03,070 --> 00:08:05,110 would pass to the next controller. So, I mean, 147 00:08:05,140 --> 00:08:07,000 there was quite a bit of repetition. 148 00:08:07,000 --> 00:08:11,170 We try to add features a couple of months 149 00:08:11,170 --> 00:08:14,170 after the, after a developer had built that wizard 150 00:08:14,170 --> 00:08:18,040 on that project, and they wanted us to deliver 151 00:08:18,040 --> 00:08:24,090 something in a week, and apparently another developer, before 152 00:08:24,120 --> 00:08:26,400 I joined that team, had tried to implement that 153 00:08:26,400 --> 00:08:27,790 feature and it took him a month. And he 154 00:08:27,790 --> 00:08:30,440 still couldn't do it with the, with the design 155 00:08:30,440 --> 00:08:30,940 they had. 156 00:08:30,940 --> 00:08:32,640 It was still, it was just taking a long 157 00:08:32,640 --> 00:08:34,510 time. Like, he was still not done. And then 158 00:08:34,520 --> 00:08:39,309 that guy left. So I ended up solving the 159 00:08:39,309 --> 00:08:41,760 problem with another senior guy. And it was, so, 160 00:08:41,760 --> 00:08:44,208 I ended up applying this ultra light maintainable wizard 161 00:08:44,208 --> 00:08:47,601 approach that I discovered on the EarlyShares dot com 162 00:08:47,601 --> 00:08:51,240 project, and it worked out really well. So, which, 163 00:08:51,240 --> 00:08:53,920 I'll talk about a little later. But that helped 164 00:08:53,920 --> 00:08:57,510 us actually develop it in, if I remember right, 165 00:08:57,510 --> 00:09:01,540 it was about seven days. 166 00:09:01,540 --> 00:09:07,050 Test first, and rewriting the entire thing, also. 167 00:09:07,060 --> 00:09:08,610 But it was specifically because we didn't have that 168 00:09:08,620 --> 00:09:11,450 many controllers anymore. So, we wrote a lot less 169 00:09:11,460 --> 00:09:12,660 tests so we had a lot less code to 170 00:09:12,660 --> 00:09:15,080 maintain. So that was part of it. 171 00:09:15,080 --> 00:09:17,400 So, another approach I've seen is one controller. Sorry. 172 00:09:17,400 --> 00:09:20,930 Oh, OK, that's just the critique. We already went 173 00:09:20,930 --> 00:09:22,080 over that. I don't think I want to go 174 00:09:22,080 --> 00:09:24,840 too much into details for that cause we're limited 175 00:09:24,840 --> 00:09:25,480 on time. 176 00:09:25,480 --> 00:09:28,240 But yeah, let's go next to one action and 177 00:09:28,240 --> 00:09:30,510 presenter per wizard step. So, I mean, another approach 178 00:09:30,510 --> 00:09:33,340 is, OK, keep one ActiveRecord, but I've also seen 179 00:09:33,340 --> 00:09:38,390 this approach in a code base, where there were 180 00:09:38,390 --> 00:09:43,900 different, say, new_step1, create_step1, new_step2, create_step2. So there were 181 00:09:43,920 --> 00:09:46,860 just, like, eight actions on that controller, each mimicking 182 00:09:46,860 --> 00:09:50,690 the new and, and, and create, say, on the 183 00:09:50,700 --> 00:09:51,880 RESTful resource. 184 00:09:51,880 --> 00:09:55,860 So, although it feels RESTful, it was not REST 185 00:09:55,860 --> 00:10:00,690 anymore. It already broke out of the REST paradigm. 186 00:10:00,690 --> 00:10:03,350 So we can improve over that. 187 00:10:03,350 --> 00:10:07,240 Also, it still had some repetitive code across the 188 00:10:07,240 --> 00:10:09,830 actions. So, I mean, it was, it was just 189 00:10:09,840 --> 00:10:14,060 a slight improvement to the problem. Not much. 190 00:10:14,060 --> 00:10:17,820 Using presenters, which is an abstraction layer between the 191 00:10:17,820 --> 00:10:20,930 ActiveRecord and the controller is an improvement in the 192 00:10:20,930 --> 00:10:22,800 sense that you can put the validations for each 193 00:10:22,800 --> 00:10:28,060 presenter per step separately and not have conditional validations. 194 00:10:28,060 --> 00:10:32,240 I'll talk more about that going forward. 195 00:10:32,240 --> 00:10:35,090 So it was more something like this, where the 196 00:10:35,100 --> 00:10:38,670 controller had a whole bunch of actions that are 197 00:10:38,670 --> 00:10:43,690 connecting to presenters that are talking to an ActiveRecord. 198 00:10:44,480 --> 00:10:45,520 OK. 199 00:10:47,500 --> 00:10:52,450 So I already went over the caveats of that. 200 00:10:52,450 --> 00:10:56,210 OK. Who here has written a wizard with session 201 00:10:56,280 --> 00:11:00,840 accumulation approach? How, how did that work out for 202 00:11:00,840 --> 00:11:02,240 you or, do you think- 203 00:11:02,240 --> 00:11:03,920 AUDIENCE: That's why I'm here. 204 00:11:03,960 --> 00:11:06,940 -well, I'm sorry if it sounds. Well, tell me 205 00:11:07,000 --> 00:11:07,750 why you're here. I'm curious. 206 00:11:07,840 --> 00:11:08,420 AUDIENCE: Well, I mean, right now it's just that 207 00:11:08,420 --> 00:11:12,330 it's to the point where we're breaking it down 208 00:11:12,330 --> 00:11:18,320 further, it was a very basic general implementation. And 209 00:11:18,340 --> 00:11:22,480 now dealing with the fact that we have so 210 00:11:22,480 --> 00:11:26,160 much session iteration that I have to pass it 211 00:11:26,160 --> 00:11:26,730 between, you know, controllers. We deal with it from 212 00:11:26,730 --> 00:11:27,300 multiple angles, and it's, I mean, I can't put 213 00:11:27,300 --> 00:11:28,490 that stuff in a model. So my controllers are 214 00:11:28,490 --> 00:11:29,120 getting really out of hand. 215 00:11:29,120 --> 00:11:29,900 A.M.: Exactly. Yeah. Yup. Yup. Yup. 216 00:11:29,920 --> 00:11:31,220 So you end up with the live session management 217 00:11:31,220 --> 00:11:33,600 code in the controller, which breaks MVC. So if 218 00:11:33,600 --> 00:11:35,910 you're not breaking REST, you break MVC. It's really 219 00:11:35,910 --> 00:11:38,400 tough. It's a tough problem. 220 00:11:38,400 --> 00:11:40,930 AUDIENCE: Can you explain what session accumulation is? 221 00:11:40,940 --> 00:11:42,820 A.M.: Yes. So, actually, maybe I should have somebody 222 00:11:42,820 --> 00:11:45,310 explain that. I saw you raise your hand. Would 223 00:11:45,310 --> 00:11:47,820 you mind explaining it to the audience. 224 00:11:47,820 --> 00:11:53,150 AUDIENCE: Sure. It's basically, as you're going through the 225 00:11:53,150 --> 00:11:58,450 specs, that you're storing all of the information that 226 00:11:58,460 --> 00:12:01,500 needs to be in the session. So then, you 227 00:12:01,500 --> 00:12:03,240 go through step 228 00:12:03,240 --> 00:12:06,460 one. You gather the basic info from the form. 229 00:12:06,460 --> 00:12:08,880 When submitting the form, instead of storing that in 230 00:12:08,880 --> 00:12:11,250 an ActiveRecord, you actually store it in, in the 231 00:12:11,250 --> 00:12:15,520 session, using the session helper in the, in the 232 00:12:15,540 --> 00:12:17,970 Rails controller. And then once you move to, and 233 00:12:17,980 --> 00:12:19,730 then you redirect to step two, and then you 234 00:12:19,740 --> 00:12:21,790 submit that form again, and then you add more 235 00:12:21,790 --> 00:12:23,210 stuff to the session. 236 00:12:23,210 --> 00:12:25,470 Once you reach the last step, kind of like 237 00:12:25,470 --> 00:12:27,930 what you see in this diagram, that's when you're 238 00:12:27,940 --> 00:12:30,330 ready to create the ActiveRecord. So you pass all 239 00:12:30,330 --> 00:12:34,320 of this as the params and the ActiveRecord will 240 00:12:34,320 --> 00:12:41,320 validate it and then you're done. 241 00:12:41,440 --> 00:12:48,440 OK. So, so I mean as far as critique. 242 00:12:49,480 --> 00:12:52,900 So reliance of session, storing objects in the session 243 00:12:52,940 --> 00:12:55,980 has implications on scalability. Usually you want to store 244 00:12:56,000 --> 00:13:00,020 ids of primitives because they're easier to move across 245 00:13:00,080 --> 00:13:02,500 servers when it's primitive data and be able to 246 00:13:02,500 --> 00:13:04,290 support multiple servers. 247 00:13:04,300 --> 00:13:07,220 My understanding is if you have actual objects in 248 00:13:07,220 --> 00:13:10,270 the session, it makes it harder for you to 249 00:13:10,280 --> 00:13:11,930 scale. 250 00:13:11,960 --> 00:13:14,870 Controller code is more complex because of managing session 251 00:13:14,870 --> 00:13:18,330 data. Validations could get defined twice, because you might 252 00:13:18,380 --> 00:13:20,190 have to validate on every step as well, in 253 00:13:20,220 --> 00:13:23,000 JavaScript or in a, in a presenter or something. 254 00:13:23,000 --> 00:13:25,630 And, also present at the last step in the 255 00:13:25,630 --> 00:13:26,100 model. 256 00:13:26,100 --> 00:13:28,200 So again, I mean, if you're not breaking REST, 257 00:13:28,200 --> 00:13:29,820 you're breaking MVC. If you're not breaking MVC, you're 258 00:13:29,820 --> 00:13:34,670 breaking duplication whatever, concerns, so, it's a tough problem. 259 00:13:34,670 --> 00:13:38,710 Hidden value accumulation. Somebody share with us what this 260 00:13:38,740 --> 00:13:41,570 is, or, it's very similar to session accumulation. 261 00:13:41,570 --> 00:13:42,720 Yeah, go ahead. 262 00:13:42,720 --> 00:13:46,210 AUDIENCE: Really, when you're submitting the form at each 263 00:13:46,210 --> 00:13:49,680 step you're shoving all the values from the form 264 00:13:49,680 --> 00:13:53,170 into hidden fields on the page, and then eventually, 265 00:13:53,170 --> 00:13:57,460 when you hit submit, the final version will just 266 00:13:57,460 --> 00:14:00,260 set everything to the server. 267 00:14:00,260 --> 00:14:01,390 A.M.: Yup. 268 00:14:01,400 --> 00:14:04,900 So it's not stateful, it's stateless, because it keeps, 269 00:14:04,900 --> 00:14:07,600 like, each request has its state. You don't have 270 00:14:07,600 --> 00:14:11,110 to maintain the state in a session. So the 271 00:14:11,110 --> 00:14:14,970 performance implications are gone. Like, it has no problems 272 00:14:14,980 --> 00:14:18,860 in scalability. 273 00:14:18,860 --> 00:14:21,740 But you might, you, you might not want to 274 00:14:21,740 --> 00:14:23,400 expose the values all the time on the, on 275 00:14:23,400 --> 00:14:25,440 the user page. You can hash them or do 276 00:14:25,440 --> 00:14:29,090 encoding on them, so that could improve that, that 277 00:14:29,090 --> 00:14:32,540 problem with regards to keeping form data in a, 278 00:14:32,540 --> 00:14:34,100 in hidden fields on the page every step of 279 00:14:34,100 --> 00:14:36,690 the way. 280 00:14:36,690 --> 00:14:43,530 But there's, yeah, I mean, but the complexity is 281 00:14:43,540 --> 00:14:45,690 still there, with having to manage the accumulation and 282 00:14:45,700 --> 00:14:48,380 having to construct the model at the end. 283 00:14:48,380 --> 00:14:49,580 So it's a slight improvement. 284 00:14:49,580 --> 00:14:52,050 Who here has used the state matching for a 285 00:14:52,060 --> 00:14:53,140 wizard? 286 00:14:53,140 --> 00:14:58,080 OK. Do you mind sharing with us your experience 287 00:14:58,080 --> 00:14:58,720 with it? 288 00:14:58,720 --> 00:15:02,450 AUDIENCE: I think main problem that you run into 289 00:15:02,450 --> 00:15:06,180 is that you get fat models, cause you have 290 00:15:06,200 --> 00:15:07,390 to put all of the different validations into different 291 00:15:07,390 --> 00:15:09,310 states. But overall, I found that it was a 292 00:15:09,310 --> 00:15:12,500 better compromise than the other options. 293 00:15:12,500 --> 00:15:15,650 A.M.: Generally it is. One, yeah. So, you create 294 00:15:15,650 --> 00:15:20,530 one ActiveRecord. You make the ActiveRecord a state machine. 295 00:15:20,540 --> 00:15:23,350 You have to add a step column on that 296 00:15:23,350 --> 00:15:27,070 model to support which step you're on when it, 297 00:15:27,080 --> 00:15:29,250 in order for the validation to know which validations 298 00:15:29,260 --> 00:15:31,330 to run for what step. So that way you 299 00:15:31,330 --> 00:15:33,750 say, OK, on step one, if you have that 300 00:15:33,750 --> 00:15:35,630 column, you'll say, OK, you'll have validations that say, 301 00:15:35,640 --> 00:15:38,600 OK, if it's step one, then I'm gonna check 302 00:15:38,600 --> 00:15:40,840 for first name and last name presence. If it's 303 00:15:40,840 --> 00:15:41,990 step two I'm gonna, I'm gonna check that the 304 00:15:42,000 --> 00:15:44,370 project details are present. And so on and so 305 00:15:44,370 --> 00:15:48,730 forth, depending on what each form, what field, what 306 00:15:48,730 --> 00:15:51,360 field each form contains on the, in the specific 307 00:15:51,380 --> 00:15:53,840 step. 308 00:15:53,840 --> 00:16:00,840 So yeah, different view per step. I already went 309 00:16:01,820 --> 00:16:03,051 over conditional validations. 310 00:16:03,060 --> 00:16:05,420 To share an example, it looks something like that, 311 00:16:05,440 --> 00:16:12,440 like validate :phone, presence: true, if current_step is shipping. 312 00:16:12,680 --> 00:16:14,000 So that's just one way of doing it. There's 313 00:16:14,000 --> 00:16:15,870 other better ways of doing it. There's also gems 314 00:16:15,870 --> 00:16:17,020 out there that help you with that. But that's 315 00:16:17,020 --> 00:16:18,280 one way of doing it. 316 00:16:18,280 --> 00:16:20,960 AUDIENCE: ActiveRecord has the ability to run conditional validations 317 00:16:20,960 --> 00:16:22,430 like that. You don't have to run a block. 318 00:16:22,430 --> 00:16:26,640 A.M.: Mhmm. Yup. Yup. I'm familiar with that. Yeah, 319 00:16:26,640 --> 00:16:28,090 that's why I mentioned, there's multiple ways of doing 320 00:16:28,090 --> 00:16:29,720 that. That's just one example. 321 00:16:29,720 --> 00:16:32,340 AUDIENCE: How does, how is the state machine different 322 00:16:32,340 --> 00:16:39,340 than the first, better than any of the ones 323 00:16:40,140 --> 00:16:43,580 you mentioned, [indecipherable - 00:16:39] 324 00:16:44,440 --> 00:16:46,780 A.M.: OK. With the other one, you could cheat 325 00:16:46,780 --> 00:16:50,130 a bit and set an in memory variable that 326 00:16:50,130 --> 00:16:52,100 represents the step name that you're on and then 327 00:16:52,100 --> 00:16:55,190 do that conditional validation that way, whereas with this 328 00:16:55,190 --> 00:16:58,030 one, you have, you're only working with one model 329 00:16:58,030 --> 00:17:02,210 and you don't, you haven't managed the stepping. So 330 00:17:02,220 --> 00:17:03,750 yeah, with the other approach, the controller is doing 331 00:17:03,750 --> 00:17:06,009 management of the stepping. In this one the model 332 00:17:06,009 --> 00:17:09,191 is doing the management of the stepping. 333 00:17:09,200 --> 00:17:13,869 So critique. Well, first of all, it puts in 334 00:17:13,880 --> 00:17:15,799 presentation concerns, like adding an extra column to our 335 00:17:15,800 --> 00:17:20,069 presenter's state, sorry, step, is not part of the 336 00:17:20,069 --> 00:17:23,810 domain, the business domain. So when you're doing MVC, 337 00:17:23,819 --> 00:17:25,910 usually the model, you're trying to put in it 338 00:17:25,910 --> 00:17:29,970 as much decoupled logic that's focused on the business 339 00:17:29,980 --> 00:17:32,660 at hand as possible in order to maintain that 340 00:17:32,680 --> 00:17:35,870 separately from any view concerns or controller concerns. 341 00:17:35,870 --> 00:17:39,071 I mean, you can put anything in the model, 342 00:17:39,080 --> 00:17:41,369 really. But the reason why we do that is, 343 00:17:41,369 --> 00:17:43,790 in my experience, when I'm maintaining a code base, 344 00:17:43,790 --> 00:17:47,171 if I'm not having to manage view concerns like 345 00:17:47,180 --> 00:17:49,950 stepping into a state machine and a model concern, 346 00:17:49,950 --> 00:17:53,999 like the business rules of, of what happens when, 347 00:17:54,000 --> 00:17:56,980 you know, like the project description is not present 348 00:17:56,980 --> 00:17:59,610 or whatever, then it's easier for me to maintain 349 00:17:59,620 --> 00:18:01,640 that model, cause I'm not thinking on one thing 350 00:18:01,640 --> 00:18:03,441 at a time. I'm not thinking multiple things at 351 00:18:03,441 --> 00:18:05,299 the same time. 352 00:18:05,300 --> 00:18:10,481 Also, it makes those models smaller files, if you 353 00:18:10,481 --> 00:18:12,940 separate those concerns. You don't want a huge model 354 00:18:12,940 --> 00:18:15,869 as maintaining a state machine and maintaining business rules 355 00:18:15,869 --> 00:18:18,510 and maintaining like ten other things. You could manage 356 00:18:18,510 --> 00:18:23,360 that with splitting that into modules or concerns, but 357 00:18:23,380 --> 00:18:26,821 still, when I'm working with that model, my head 358 00:18:26,821 --> 00:18:28,779 will have the context of everything at once. SO 359 00:18:28,780 --> 00:18:31,581 it wouldn't, like, this is more of an advanced 360 00:18:31,581 --> 00:18:33,869 programming thing. Like, once you've been programming for three 361 00:18:33,869 --> 00:18:36,932 years at least, you'll, you'll start noticing that. 362 00:18:36,940 --> 00:18:42,728 You'll start noticing the subtleties with regards to mixing 363 00:18:42,728 --> 00:18:46,071 concerns. Like, you start understanding why people say follow 364 00:18:46,080 --> 00:18:49,369 the single responsibility principle. I'm not a fan of 365 00:18:49,369 --> 00:18:51,860 following it dogmatically, I, but I think it's a 366 00:18:51,860 --> 00:18:54,061 good guideline, like any other guideline, where if you 367 00:18:54,061 --> 00:18:57,499 could minimize responsibilities in a model and have it 368 00:18:57,500 --> 00:19:01,400 not manage view concerns, then do that. Especially if 369 00:19:01,400 --> 00:19:03,630 MVC prescribes that as well as that's what all 370 00:19:03,660 --> 00:19:06,071 Rails developers on the field would expect. 371 00:19:06,080 --> 00:19:12,148 So I think I pretty much sold that. So 372 00:19:12,148 --> 00:19:15,040 yeah, so I mean, I think that makes it 373 00:19:15,040 --> 00:19:19,280 pretty clear why I don't like this approach that 374 00:19:19,280 --> 00:19:19,821 much. 375 00:19:19,821 --> 00:19:22,559 Also, it's a bit techy. Like, thinking of the 376 00:19:22,560 --> 00:19:24,540 wizard as a state machine is a bit computer 377 00:19:24,540 --> 00:19:27,250 science-y. Like, I mean, I have a background in 378 00:19:27,250 --> 00:19:29,650 computer science, but, the, the point of anything you 379 00:19:29,650 --> 00:19:31,071 learn is to apply it in the right place 380 00:19:31,080 --> 00:19:33,700 for it, and I don't feel like, when I'm 381 00:19:33,700 --> 00:19:35,590 thinking about a wizard I'm thinking about the business 382 00:19:35,600 --> 00:19:36,789 problem. That's what I really want to think about. 383 00:19:36,789 --> 00:19:38,130 I don't want to think about a state machine. 384 00:19:38,130 --> 00:19:40,341 As cool as that is, that's not the time 385 00:19:40,341 --> 00:19:41,289 to think about it. 386 00:19:41,289 --> 00:19:45,691 So I mean, a thousand and one approaches is, 387 00:19:45,700 --> 00:19:48,009 there's a whole bunch of gems out there. Most 388 00:19:48,009 --> 00:19:50,250 of them will simplify the things I mentioned, or 389 00:19:50,280 --> 00:19:53,441 give you better, shorter DSLs for doing the approaches 390 00:19:53,441 --> 00:19:56,590 I mentioned. But none of them achieve all the 391 00:19:56,590 --> 00:19:58,899 goals at once, of having MVC, REST, and all 392 00:19:58,900 --> 00:19:59,640 of that. 393 00:19:59,640 --> 00:20:03,110 I mean, to get back to that, there's REST, 394 00:20:03,110 --> 00:20:06,290 MVC, OO, and then the non-functional requirements. So, let's 395 00:20:06,290 --> 00:20:09,701 go to, jump into this. I think we have 396 00:20:09,701 --> 00:20:14,290 about ten minutes left. 397 00:20:14,300 --> 00:20:17,590 So the first thing that, so I, I'm like, 398 00:20:17,590 --> 00:20:19,859 OK, let's try to solve this wizard problem from 399 00:20:19,860 --> 00:20:22,380 scratch, like, as if I just, I'm just gonna, 400 00:20:22,380 --> 00:20:25,250 like, get my tools out there. Like, the object-oriented 401 00:20:25,260 --> 00:20:30,640 principles, the domain-driven design principles. Who, who here has 402 00:20:30,640 --> 00:20:33,801 read the book Domain Driven Design? Or heard of 403 00:20:33,801 --> 00:20:36,200 it, at least? 404 00:20:36,200 --> 00:20:38,349 It's a book that I, my team did a 405 00:20:38,349 --> 00:20:41,340 book club on, or a previous team, like six 406 00:20:41,340 --> 00:20:43,870 years ago, did a book club on for the 407 00:20:43,880 --> 00:20:47,831 sake of learning how to do object-oriented design on 408 00:20:47,840 --> 00:20:49,879 real business problems. Cause a lot of the time 409 00:20:49,880 --> 00:20:51,900 you learn object orientation, but it's hard to figure 410 00:20:51,900 --> 00:20:54,191 out how to create the right objects for the 411 00:20:54,200 --> 00:20:56,480 real, for the right person's problem. It's, that, that 412 00:20:56,480 --> 00:20:58,119 book is a very good book on how to 413 00:20:58,120 --> 00:20:58,920 tackle that. 414 00:20:58,940 --> 00:21:00,879 So I, I started using those tools. Like, whatever 415 00:21:00,880 --> 00:21:02,400 I learned from that book, whatever I learned from 416 00:21:02,400 --> 00:21:07,770 object-oriented programming. Whatever I learned from, like REST. To 417 00:21:07,780 --> 00:21:11,280 try to figure out what a wizard is. 418 00:21:11,280 --> 00:21:14,130 Before I go ahead and talk more of what 419 00:21:14,130 --> 00:21:16,990 a wizard is, what do you think a wizard, 420 00:21:17,000 --> 00:21:19,100 the wizard's highest goal is? 421 00:21:19,100 --> 00:21:20,630 Go ahead. 422 00:21:20,630 --> 00:21:25,051 AUDIENCE: To serve views for the user. 423 00:21:25,060 --> 00:21:28,349 A.M.: That's correct. So, you stumped me. Cause I 424 00:21:28,349 --> 00:21:30,291 was gonna ask about the highest goal from the 425 00:21:30,300 --> 00:21:31,769 developer's point of view, but you're right, we should 426 00:21:31,769 --> 00:21:33,730 think about the user's perspective first. 427 00:21:33,740 --> 00:21:38,091 Now, let's dig, let's dig a little. No, that's 428 00:21:38,100 --> 00:21:40,830 good. Let's dig a level lower. So, OK, so 429 00:21:40,830 --> 00:21:43,580 we know that. That's our guiding principle, is OK, 430 00:21:43,580 --> 00:21:45,149 to serve to make things easier for the user. 431 00:21:45,149 --> 00:21:50,280 But, next, what, why, why, OK, technically what, what 432 00:21:50,280 --> 00:21:51,120 is a wizard doing? 433 00:21:51,140 --> 00:21:52,790 OK, that's my next question. What is a wizard 434 00:21:52,790 --> 00:21:54,160 really doing? Go ahead. 435 00:21:54,160 --> 00:21:57,470 AUDIENCE: Collect the proper set of validated values. 436 00:21:57,470 --> 00:22:00,770 A.M.: That's part of the work. What else? 437 00:22:00,770 --> 00:22:01,890 AUDIENCE: Break down the form so they're just small 438 00:22:01,890 --> 00:22:02,230 steps. 439 00:22:02,320 --> 00:22:04,440 A.M.: OK. Break down the data. Yup. Like separate 440 00:22:04,520 --> 00:22:05,920 it. What else? 441 00:22:05,920 --> 00:22:06,960 AUDIENCE: I was gonna say something really similar to 442 00:22:07,120 --> 00:22:09,040 that. Organize the data into, like, you know, making 443 00:22:09,040 --> 00:22:13,220 it weighted or in comprehensible sections. 444 00:22:14,020 --> 00:22:16,380 A.M.: OK. And what's the end goal of running 445 00:22:16,420 --> 00:22:18,880 through the entire wizard? 446 00:22:18,920 --> 00:22:21,391 AUDIENCE: Creating an object. 447 00:22:21,391 --> 00:22:24,758 A.M.: Yup. Pretty much. So a wizard is nothing 448 00:22:24,780 --> 00:22:29,220 but the good old builder design pattern. Anybody's heard 449 00:22:29,220 --> 00:22:30,821 of it. I mean, I used to be a 450 00:22:30,821 --> 00:22:33,269 hardcore Java geek and design patterns were big in- 451 00:22:33,269 --> 00:22:35,761 [audio jump] seven days - in Ruby. 452 00:22:35,761 --> 00:22:38,720 But it's still good to know about things like 453 00:22:38,720 --> 00:22:40,980 that, cause that pattern flashed in my head right 454 00:22:40,980 --> 00:22:42,520 away. I'm like, oh wow, a wizard is nothing 455 00:22:42,540 --> 00:22:44,831 but a builder. Like, it, all it does is 456 00:22:44,831 --> 00:22:47,409 like an assembly line of building a car, where 457 00:22:47,409 --> 00:22:50,370 step one, you know, whatever, you put the chassis, 458 00:22:50,380 --> 00:22:53,091 second, like, step two is you add more, I 459 00:22:53,100 --> 00:22:54,649 don't know, you add the doors. Step three, you 460 00:22:54,649 --> 00:22:57,061 add the windows. Four, five, and then all of 461 00:22:57,061 --> 00:23:01,629 the sudden you've built a car. So that's really 462 00:23:01,629 --> 00:23:06,681 what it is. 463 00:23:06,681 --> 00:23:11,039 Second part of the philosophy that I was following 464 00:23:11,040 --> 00:23:14,301 is, each step in a wizard is nothing but 465 00:23:14,301 --> 00:23:16,570 a partial view of that main, full object you're 466 00:23:16,570 --> 00:23:19,459 building. So, one, one step is about, say I'm 467 00:23:19,460 --> 00:23:21,030 ordering a car and I want to customize that 468 00:23:21,060 --> 00:23:22,990 car. Like, one step will show me the exterior 469 00:23:22,990 --> 00:23:25,770 body and another will show me the interior to 470 00:23:25,770 --> 00:23:29,941 customize the interior with, whatever, leather or mahogany front-panel, 471 00:23:29,941 --> 00:23:32,330 whatever. And then, and then a third part lets 472 00:23:32,330 --> 00:23:33,410 me customize the engine. 473 00:23:33,410 --> 00:23:35,719 So it's just, so all what steps are, are 474 00:23:35,740 --> 00:23:38,931 views. Like, instead of thinking about them as states 475 00:23:38,940 --> 00:23:41,330 and in a state machine, this is a more 476 00:23:41,340 --> 00:23:43,470 higher level way of thinking about it. It's less 477 00:23:43,470 --> 00:23:46,919 technical and more, it's just, I'm viewing one part 478 00:23:46,920 --> 00:23:49,730 of a model. 479 00:23:49,740 --> 00:23:54,721 Third part is if you were to, so, with 480 00:23:54,721 --> 00:23:56,480 that in mind, if you ever think about the 481 00:23:56,480 --> 00:23:59,869 REST resources, it's very simple now. It's done. Like, 482 00:23:59,869 --> 00:24:02,091 you have the main model, that's the main resource. 483 00:24:02,100 --> 00:24:04,679 And then you have the model parts, nested model 484 00:24:04,680 --> 00:24:07,050 part, under the main model. That's the second resource. 485 00:24:07,050 --> 00:24:10,390 That's it. You have two RESTful resources. Very clean. 486 00:24:10,390 --> 00:24:12,640 So every time you're walking through the steps of 487 00:24:12,640 --> 00:24:17,040 a wizard, you're actually editing a model part. So, 488 00:24:17,040 --> 00:24:19,811 and, so that makes it very, very clear what 489 00:24:19,820 --> 00:24:22,499 the REST resource is. 490 00:24:22,500 --> 00:24:25,571 Another thing in my philosophy about it was I 491 00:24:25,580 --> 00:24:28,049 did not want to have conditional validations, cause they 492 00:24:28,049 --> 00:24:30,280 make a model hard to maintain. It's harder to 493 00:24:30,280 --> 00:24:31,910 read if statements. Like, if I can have those 494 00:24:31,910 --> 00:24:35,250 without if statements, it would be better. Especially when 495 00:24:35,250 --> 00:24:37,250 you come back to maintain that wizard six months 496 00:24:37,260 --> 00:24:39,801 later and then a year later and, on, on 497 00:24:39,801 --> 00:24:41,969 both projects I was on, they actually added steps 498 00:24:41,969 --> 00:24:43,630 to the wizard. So they started with four steps 499 00:24:43,640 --> 00:24:46,030 and then they grew to nine steps. 500 00:24:46,030 --> 00:24:51,120 And the more I can separate that stuff, the, 501 00:24:51,120 --> 00:24:55,571 the better. And then finally I just wanted to 502 00:24:55,580 --> 00:24:57,729 maintain the views in separate view files as well. 503 00:24:57,740 --> 00:25:00,100 I didn't want a single view file that would 504 00:25:00,100 --> 00:25:01,341 do it the way I used to write code 505 00:25:01,341 --> 00:25:03,759 in ASB where I'd have a crazy if-else statement 506 00:25:03,760 --> 00:25:06,081 that says if step1 show this part of the 507 00:25:06,081 --> 00:25:09,529 form, if step2, show me the project details, if 508 00:25:09,529 --> 00:25:12,840 step3, show me a document content upload. I don't 509 00:25:12,840 --> 00:25:19,840 want that. That's, yeah. That's ASP programming. 510 00:25:21,060 --> 00:25:28,060 AUDIENCE: If they change the order of the steps, 511 00:25:28,060 --> 00:25:31,440 you want the steps [indecipherable] step three became step 512 00:25:31,540 --> 00:25:32,660 four. 513 00:25:33,700 --> 00:25:35,340 A.M.: Yeah. It'll work. 514 00:25:36,840 --> 00:25:40,960 OK. So, so really I mean, high level is 515 00:25:41,040 --> 00:25:42,829 just, I have the main model. That's the main 516 00:25:42,829 --> 00:25:44,631 resource. And then the, on the, nested under it, 517 00:25:44,640 --> 00:25:49,130 there's the four different, so, what I end up 518 00:25:49,130 --> 00:25:52,400 doing is creating four different presenters. One per step. 519 00:25:52,400 --> 00:25:55,000 Which manages the validations for that step separately, as 520 00:25:55,000 --> 00:25:57,290 well as any stepping logic related to what happens 521 00:25:57,290 --> 00:25:58,681 when you land on that page. What are the 522 00:25:58,681 --> 00:26:01,159 defaults for that form? Should we initialize the phone 523 00:26:01,180 --> 00:26:03,540 number with zero, zero, zero, zeros, or should we, 524 00:26:03,540 --> 00:26:05,810 like, should, should we prefil the name from the 525 00:26:05,810 --> 00:26:08,630 logged in user account? These kinds of concerns now 526 00:26:08,630 --> 00:26:10,331 are uploaded cleanly to the model. 527 00:26:10,340 --> 00:26:12,700 So we're adhering to MVC. You handle all the 528 00:26:12,700 --> 00:26:15,800 wizard intelligence and business logic in the models now. 529 00:26:15,800 --> 00:26:17,769 You're not, or presenters. I mean, a presenter is 530 00:26:17,780 --> 00:26:19,941 just another form of a model that focuses on 531 00:26:19,941 --> 00:26:22,629 presented a vi- a part of a model. So, 532 00:26:22,629 --> 00:26:25,600 really, I'm, I'm using it in a loose sense. 533 00:26:25,600 --> 00:26:27,210 There's many ways to do presenters. I don't care 534 00:26:27,220 --> 00:26:28,280 which way. 535 00:26:28,280 --> 00:26:30,910 I do have a prescribed way here, but, the 536 00:26:30,910 --> 00:26:34,311 point of first to grasp is that you're operating 537 00:26:34,320 --> 00:26:36,029 on a part of the model. You're not operating 538 00:26:36,029 --> 00:26:37,500 on the full model. And you're doing the logic 539 00:26:37,500 --> 00:26:41,330 in the, in a model, not in a controller. 540 00:26:41,340 --> 00:26:43,071 And then the, the controller is the, yeah. So 541 00:26:43,080 --> 00:26:44,700 there's two of them. There's the one that manages 542 00:26:44,700 --> 00:26:46,919 the main model creation. So the first step of 543 00:26:46,920 --> 00:26:49,191 a wizard, when you create it, you create it 544 00:26:49,200 --> 00:26:51,710 with a main model controller. So if I have 545 00:26:51,710 --> 00:26:54,560 projects controller, I have a create action. And then 546 00:26:54,560 --> 00:26:58,119 that triggers the wizard. It'll, it'll create it and 547 00:26:58,120 --> 00:27:00,471 then redirects me to the first step. 548 00:27:00,480 --> 00:27:01,779 So when it redirects me to the first step 549 00:27:01,780 --> 00:27:03,981 it takes me to the edit page of model 550 00:27:03,981 --> 00:27:07,700 part, the nested model part, with id_step1, for example. 551 00:27:07,700 --> 00:27:10,779 Or id basic info. So you use the step 552 00:27:10,780 --> 00:27:13,101 names as the ids of that RESTful resource. Which 553 00:27:13,101 --> 00:27:20,019 is perfect REST. Like, that's, that, that goes with, 554 00:27:20,100 --> 00:27:21,690 that gives you an example of why, when people 555 00:27:21,690 --> 00:27:25,481 talk about REST outside of Rails, they tell you 556 00:27:25,481 --> 00:27:28,840 REST does not relate to having a database table. 557 00:27:28,840 --> 00:27:31,149 You can, so this, this, this is an example 558 00:27:31,149 --> 00:27:35,000 where the RESTful resource is a step that is 559 00:27:35,000 --> 00:27:37,670 a view of the model, but it's not a 560 00:27:37,670 --> 00:27:39,900 resource. It's not a database table. It's not a 561 00:27:39,900 --> 00:27:42,691 separate database table. It's just a virtual resource. 562 00:27:42,700 --> 00:27:44,499 I need to wrap it up and then I'll 563 00:27:44,500 --> 00:27:47,040 take, I'll take questions. So in a nutshell, you 564 00:27:47,040 --> 00:27:49,790 have the model resource, nested model. So you end 565 00:27:49,790 --> 00:27:54,200 up with URLs like that, which is very restful, 566 00:27:54,200 --> 00:27:58,800 again, cause, like, so you have projects, with the 567 00:27:58,800 --> 00:28:00,460 id. We were using friendly id on the projects, 568 00:28:00,460 --> 00:28:03,440 so the project says, yeah, so project1, then project_parts, 569 00:28:03,440 --> 00:28:05,540 and then the name of the step. And there'll 570 00:28:05,540 --> 00:28:07,700 be four steps for, you know, every time you 571 00:28:07,700 --> 00:28:09,279 run through that wizard. So there'll be four ids, 572 00:28:09,280 --> 00:28:11,860 only. It's a finite set. You don't have to 573 00:28:11,860 --> 00:28:13,520 store it in the database. 574 00:28:13,520 --> 00:28:20,140 So yeah, step names. There's id, contains validations, yeah. 575 00:28:20,200 --> 00:28:22,771 I already talked about all of that. So let's 576 00:28:22,771 --> 00:28:23,820 skip. 577 00:28:23,820 --> 00:28:26,469 So the routes is very, are very simple. You 578 00:28:26,469 --> 00:28:30,181 just have a resources projects. It's actually only create 579 00:28:30,181 --> 00:28:32,440 and show. I left the show out. There should 580 00:28:32,440 --> 00:28:34,659 be a show as well. Show is the landing 581 00:28:34,680 --> 00:28:37,300 page of the project when you finish the wizard. 582 00:28:37,300 --> 00:28:39,400 And then the project parts, which is edit and 583 00:28:39,400 --> 00:28:41,571 update. And it's that simple. 584 00:28:41,571 --> 00:28:44,289 So, so here's the project model. It's got the 585 00:28:44,289 --> 00:28:48,640 basic definition of that model. And associations and so 586 00:28:48,640 --> 00:28:51,421 on and so forth. However, what I end up 587 00:28:51,421 --> 00:28:54,070 doing is creating a presenter per wizard step, so, 588 00:28:54,070 --> 00:28:56,550 and I nest them under a directory that matches 589 00:28:56,580 --> 00:28:59,409 the model name, so, project, for example. And that's 590 00:28:59,409 --> 00:29:01,431 one way of doing it. There's many ways of 591 00:29:01,440 --> 00:29:03,299 doing it, but. 592 00:29:03,300 --> 00:29:06,230 In this case, only step one and two had 593 00:29:06,230 --> 00:29:08,841 customizations over that model. Step three did not have 594 00:29:08,841 --> 00:29:10,989 validations of its own, so I didn't even have 595 00:29:10,989 --> 00:29:14,520 to create a file for it. And step four 596 00:29:14,520 --> 00:29:16,340 actually didn't have anything either so I didn't have 597 00:29:16,340 --> 00:29:17,240 to create a file for it. 598 00:29:17,260 --> 00:29:20,480 But yeah. Step one, you can't see the details, 599 00:29:20,480 --> 00:29:22,930 but the point is that this is, these are 600 00:29:22,930 --> 00:29:27,000 validations for step one, only. So that's the first, 601 00:29:27,000 --> 00:29:29,220 and then the first step, as well as some 602 00:29:29,220 --> 00:29:33,170 business logic related to it, like initializing default, like 603 00:29:33,170 --> 00:29:37,620 initialize from user, which initializes from the signed in 604 00:29:37,620 --> 00:29:38,191 user. 605 00:29:38,200 --> 00:29:42,529 And then there's the project detail model, which has 606 00:29:42,540 --> 00:29:45,650 a few validations, only. Only three, cause it only 607 00:29:45,650 --> 00:29:49,280 has three fields on it. So that one is 608 00:29:49,280 --> 00:29:53,900 also, like, cleanly separated. Nice, easy to maintain. So 609 00:29:53,900 --> 00:29:57,331 you go back to maintain the code and it's 610 00:29:57,340 --> 00:29:58,679 like, it's like, it's squeaky clean. You know it's 611 00:29:58,680 --> 00:30:01,581 like so easy. It's like the way programming should 612 00:30:01,581 --> 00:30:06,039 be. 613 00:30:06,040 --> 00:30:08,140 So the project's controller, the create action, all it 614 00:30:08,140 --> 00:30:10,540 does is it creates the project and then redirects 615 00:30:10,540 --> 00:30:13,890 to the edit page of the first step, which 616 00:30:13,890 --> 00:30:18,780 is basic info. And then the project parts controller 617 00:30:18,780 --> 00:30:20,850 has the edit and the update and all it 618 00:30:20,850 --> 00:30:23,691 does is it steps through the wizard. Now, what 619 00:30:23,700 --> 00:30:25,430 I ended up doing here is the way I 620 00:30:25,430 --> 00:30:28,940 reasoned about it is that the project in MVC, 621 00:30:28,940 --> 00:30:32,039 or, sorry project controller in MVC is, or project 622 00:30:32,040 --> 00:30:36,071 parts controller, is actually, although it's a controller, it's 623 00:30:36,080 --> 00:30:38,239 a model of sorts. It's a model focused on 624 00:30:38,240 --> 00:30:39,470 control flow. 625 00:30:39,470 --> 00:30:41,571 And stepping through a wizard is control flow. So 626 00:30:41,580 --> 00:30:44,060 then I made the controller responsible for it. So 627 00:30:44,060 --> 00:30:47,599 the, so here, at the top, it, it defines 628 00:30:47,600 --> 00:30:49,120 the order of the steps, and then based on 629 00:30:49,120 --> 00:30:50,720 that it walks through them. So in a way 630 00:30:50,720 --> 00:30:53,480 the controller is the state machine, except I didn't 631 00:30:53,480 --> 00:30:56,681 need a state machine cause I'm not maintaining state. 632 00:30:56,681 --> 00:30:58,830 I do it with, I don't need to maintain 633 00:30:58,830 --> 00:31:00,450 state. Every time we finish a step we can 634 00:31:00,460 --> 00:31:02,479 redirect to the next step. And I can pass 635 00:31:02,480 --> 00:31:05,431 the id of the next step RESTfully and redirect 636 00:31:05,440 --> 00:31:06,609 to the next resource. 637 00:31:06,609 --> 00:31:08,500 So I, I don't need to maintain what step 638 00:31:08,500 --> 00:31:11,061 I'm at, on. It's always on each page. Like, 639 00:31:11,061 --> 00:31:12,659 on each page, I can know, if I'm on 640 00:31:12,660 --> 00:31:15,110 step two, I know that if I hit submit 641 00:31:15,110 --> 00:31:17,270 it'll take me to step three next. I don't 642 00:31:17,270 --> 00:31:19,330 have to, like I just know that from this 643 00:31:19,340 --> 00:31:23,931 array that we define over here, which orders the 644 00:31:23,940 --> 00:31:25,759 steps in the wizard. 645 00:31:25,760 --> 00:31:29,050 So, yeah, we're almost done. But yeah. I mean, 646 00:31:29,050 --> 00:31:32,681 it's got stepping logic. There is, there's a gem 647 00:31:32,681 --> 00:31:34,769 out there called wicked that helps to implement this 648 00:31:34,769 --> 00:31:39,241 sort of logic in a controller. I, I'm starting 649 00:31:39,270 --> 00:31:42,720 a gem called ultralightwizard that will do similar stuff, 650 00:31:42,720 --> 00:31:48,490 except it'll add the, the concept of presenters to 651 00:31:48,500 --> 00:31:51,280 it as well. But until then you could use 652 00:31:51,280 --> 00:31:53,400 wicked for the controller part. 653 00:31:53,400 --> 00:31:57,130 The views, you'll just have a different wizard part 654 00:31:57,130 --> 00:32:00,100 view, or sorry, step view. And one thing I 655 00:32:00,100 --> 00:32:02,850 didn't know is that this edit action, it actually, 656 00:32:02,850 --> 00:32:04,431 when it renders the view, you don't render and 657 00:32:04,440 --> 00:32:07,379 edit dot html dot erb, you polymorphically just render 658 00:32:07,380 --> 00:32:09,580 the step name. And then it ends up picking 659 00:32:09,580 --> 00:32:10,890 a view matching that step name. 660 00:32:10,890 --> 00:32:13,280 So if I render basic_info, it renders basic_info dot 661 00:32:13,280 --> 00:32:16,051 html dot erb, which contains the edit form for 662 00:32:16,060 --> 00:32:20,039 that step. If I render the, the detail step, 663 00:32:20,040 --> 00:32:23,671 then it renders detail dot html dot erb. So 664 00:32:23,680 --> 00:32:25,289 that's why I have these. So that way we 665 00:32:25,289 --> 00:32:27,260 have the views separated as well. So we achieve 666 00:32:27,260 --> 00:32:30,540 that goal. 667 00:32:30,540 --> 00:32:32,801 The form that you put can be the same 668 00:32:32,801 --> 00:32:35,089 on all views actually. Because you have, you're editing 669 00:32:35,089 --> 00:32:37,480 the same model. You're just editing different parts of 670 00:32:37,480 --> 00:32:40,270 that model, but it's, it's the same model on 671 00:32:40,280 --> 00:32:44,080 all pages. So the root model is project, but 672 00:32:44,080 --> 00:32:47,951 on one page I'm editing nested document content, upload 673 00:32:47,960 --> 00:32:50,639 the documents. On another page I'm, I'm, I'm editing 674 00:32:50,640 --> 00:32:52,331 just the first name and last name, and so 675 00:32:52,340 --> 00:32:52,800 on and so forth. 676 00:32:52,800 --> 00:32:54,300 So you could actually wrap this whole thing up 677 00:32:54,300 --> 00:32:58,979 in the helper, call it project_form_for. That's super short. 678 00:32:58,980 --> 00:33:00,921 Just use that. I know on one of my 679 00:33:00,921 --> 00:33:03,709 projects, another senior developer on the team did that, 680 00:33:03,709 --> 00:33:07,980 like he did that as a refactoring step. 681 00:33:07,980 --> 00:33:11,100 So, I mean, this is an example, but a 682 00:33:11,100 --> 00:33:15,311 view, a very straightforward view form, like, straight Rails. 683 00:33:15,320 --> 00:33:19,570 Nothing special about it. 684 00:33:19,570 --> 00:33:22,009 So that concludes the talk. So, I mean, I 685 00:33:22,040 --> 00:33:23,341 talked about why use a wizard, provide a wizard 686 00:33:23,341 --> 00:33:28,638 example, implementation goals, other implementations out there, and finally 687 00:33:28,640 --> 00:33:31,410 talked about what's my recommended approach for sticking with 688 00:33:31,410 --> 00:33:34,990 REST, MVC, OO, and, you know, all the things 689 00:33:34,990 --> 00:33:37,410 that would help ensure that your code is not 690 00:33:37,410 --> 00:33:40,000 maintainable only today but also a year from now, 691 00:33:40,000 --> 00:33:42,260 and also by other developers that will join the 692 00:33:42,260 --> 00:33:45,820 team with minimal training efforts, hopefully. 693 00:33:45,820 --> 00:33:47,911 This is the project that I launched and is 694 00:33:47,920 --> 00:33:49,599 empty right now, but I would like to, but 695 00:33:49,600 --> 00:33:51,600 I mean, you can star it and monitor it 696 00:33:51,600 --> 00:33:53,340 and hopefully I have something out soon. Maybe I'll 697 00:33:53,340 --> 00:33:55,910 do it at RailsConf. Somebody want to pair with 698 00:33:55,910 --> 00:33:58,390 me on this, you're welcome to. So yeah, my 699 00:33:58,400 --> 00:34:00,811 name is Andy Maleh. I'm the VP of Engineering 700 00:34:00,820 --> 00:34:06,190 at a remote only, or 100% remote option consulting 701 00:34:06,190 --> 00:34:09,690 company called BigAstronaut. These are my folks over here. 702 00:34:09,699 --> 00:34:11,250 That's Lance, CTO. 703 00:34:11,250 --> 00:34:15,909 Oh, oh yeah, Chief Fun Officer as well. 704 00:34:15,920 --> 00:34:17,840 AUDIENCE: We've got t-shirts and stickers and we're hiring. 705 00:34:18,179 --> 00:34:20,580 A.M.: Sweet. Yeah. Thank you everybody.