Umbraco anti-patterns
Previously on Codegarden Marc Goodsoon talked about my adventures with liverpool.gov.uk and Umbraco; which in turn led him to leaving liverpool.gov.uk and working for the popular Umbraco Gold Partner Moriyama; where he expected to be building one shiny new Umbraco site after another; but in reality Mark found himself inheriting site after site of crazily broken Umbraco implementations.
This talk will give you ways to identify when you going down a wrong path in Umbraco, and better solutions to common challenges Umbraco developers face.
View transcript
Hello! Hello. Hello. Hello. Hello. Hello. Sound in check. I can see. Yes. Good. Welcome to my talk on Umbraco anti-patterns. Let everyone get settled. Hang on a sec while I work out how to use PowerPoint. Hello again. I work for Moriyama, the popular Umbraco gold partner in the UK. My name is Marky Mark on Twitter, Mark Goodson. You might know me because I'm one of the official Umbraco trainers in the UK. But let's face it, you're probably here to see me because of my excellent package, UCSS class name drop down. Hooray. It's really hard to think about building a site these days. Without using that in some way. That's probably why you're here today. I'm told that you would do a talk at a conference twice in your career. Once on the way up. And then once again on the way down. So, ladies and gentlemen, it's really nice to be back. Previously on Code Garden, I talked about liverpool.gov.uk and building a site in Umbraco. And then I left liverpool.gov.uk. And now, working at Moriyama, I'm going to have to stand here to press the slides. Working at Moriyama, we build lots of lovely, nice, shiny Umbraco sites. But we also have a reputation of taking on other people's sites which we didn't build, warts and all, and stabilising them. We do health checks and have SLA support contracts. But we don't reject these sites. We try and bring them back into a stable state and fix them. So what this talk is about is when I've been looking at these sites and going through, probably about 80 or 100 sites in the last three years that I've gone through Umbraco sites and talked about and fixed and looked at code and gone through code, I've spotted things that are wrong or, let's face it, not optimal. Because Umbraco is so flexible, there's so many different ways to do it. And the interesting thing is sometimes different people do different things, or they do the same things wrong. And that's what we call an anti-pattern. So even though it seems a little bit crazy, different people who've never spoke to each other are doing it how I wouldn't do it in the same way. It's a bit odd. So this talk, really, is not one of those talks about learn by doing. It's more of a learn by don'ting. And I've trademarked that. So if anyone uses that, that's mine. Learn by don'ting. The idea is that we learn from our mistakes far much more than we learn when things go well. If something goes well, you don't think about it again. But if you've had to hack through and try and work out why something doesn't work, you actually learn. So it's really good when sites fail. Honestly, that's what I've been telling my boss anyway. But I can't show examples of real sites when there might be someone in this room who is responsible for the code. Because that would be a little bit unprofessional. And I might get punched later on. So what I've done is I've changed the names of the sites and bits of code so you shouldn't be able to guess which site it is. Don't try. Don't shout it out if you know it. It's not a game. But these are all real sites and real situations that I've encountered in the real world. And I've had to deal with and fix. Without further ado, this will probably give a better idea of what it's about. I'm going to talk about the first case. And this is the first anti-pattern that I've come across. And I've given it a generic name which is sort of misusing Umbraco properties. But I'm going to illustrate it with a very specific example. So imagine a travel site. It's a normal travel site. Lots of pages. About 100 pages on there talking about locations. SEO to the max. And at some point somebody says, Wouldn't it be good to have an advert in the right-hand column? But we don't want it on every single page. We want the editors to be able to control which page it appears on. You're already thinking with your developer minds how you would do that. This developer chose to create a checkbox. Show skeever mont ad. So it's quite good. The editors can tick that box if they want it on that page. Or tick it if they don't. It's not too bad, is it? It's probably not how you'd do it. But it does work. You can see. The code up there. You can just do a little check to see if that's true. And write out the code for the advert. Job done. Not worrying, is it? Until somebody adds a second advert. We need a second advert in the right-hand column. So how would you deal with that? Two adverts. Editors need to be able to pick which one to show. Or choose to show both of them. Well, you add another checkbox, don't you? That makes sense, doesn't it? The first one works. The second one doesn't. It's not too bad for an editor. It's not a great crime. You could tick the boxes. You've got full control, haven't you? So a third advert comes along. But this advert's different because it's got three color variations. And I am only guessing because I wasn't in the room when this happened. I've only inherited this site and had to fix it. So they've got a visit Flannau advert. This is a reconstruction. It's not exactly what it was. But they have the blue, red, and white versions. So we've now got five checkboxes. And we're starting to feel a little bit uneasy about this because you can't reorder them. I mean, you can still see the options in the screen. But it's also you're hard coding the name of the advert into the doc type property, isn't it? So, again, it's just not quite right. But you can see sort of why somebody might think that that would be the way to go. But this is the time when it's time to refactor and take a more generic approach. And I'm pleased to tell you that the developer did take a much more generic approach. They added another ten checkboxes. But the genericness is they just put show advert one, show advert two, show advert three. How is the editor going to know which advert is going to show when that shows? They must have had a bit of paper with it written down. Genius. What I like to think is that there was a bit of an argument over what to call these things. And the person who added show advert nine said that it should be a zero. And they did it from there so it lined up neatly. And they lost the argument for the first eight. But then someone was out of the office and they just called it 09 anyway. That's what I like to think happened. So it's odd to see what scenario that's been created in. But I know some of you keen developers and you're thinking about scalability. Is ten enough? Is it? No, it isn't. No. 11, 12, 13, 14, 15, 16, 17, 18, 19, 20. All the way down to 20. 21, 22, 23, 24, 25, 26, 27, 28, 29, 30. All the way down to 30. You can cope with a lot of adverts, can't it? The tension in the room. It does stop on the next slide, I can assure you. They only go as far as number 38. But 36 goes to 38. There's no 37. So did they do 38 and then go, oh, we don't need that 37 faffer anymore. Well, let's neisten up the UI for the editors. Let's remove that one so no one gets confused. It doesn't make sense, does it? I've known. Unless 37 is an unlucky number. I don't know. I don't know. So now you're thinking, what does the code look like? I can't really show you a slide of the code. Mainly because it doesn't fit. But I can describe it as ifs forever. Just all the way down. Dynamic node raiser. When's that coming back in fashion? All the way down there. It's horrible. How does it happen? How on earth does it happen? I mean, we were contacted because this was Umbraco 4. And we were contacted because the back office was slow. Particularly when publishing. If you think about it, in Umbraco 4, each property, when you save and publish, it would have a separate SQL statement was issued for it. So when they were saving and publishing their entire site, it was taking about eight to nine hours to do a publish. Effectively, they were mounting a denial of service attack against their own SQL database. It was horrific. But you can sort of see, maybe, possibly, the first checkbox worked, didn't it? And if somebody comes at 10 to 5 and says, we'll get another 5,000 pounds and get this advert live tomorrow, maybe the developer's on holiday. Maybe they just don't really like their job. I don't know. But very quickly, you can see how you cut and paste to make that happen. I mean, I'm only speculating. But this is what I would describe as an anti-pattern. If something works, and we know it works, and we've got a short space of time, we will repeat it. If you think about things you've done yourselves, when you've been asked to do something, you've done it before, you've just cut and pasted it, haven't you? And just got it live to work to meet that deadline. So this is what I'm talking about. This is an anti-pattern. And now anyone who's really, really technical is thinking, I wish I'd gone to the unit testing talk. Just feel free to leave me. It's okay. I was thinking about it myself. I have to stay. So, apparently, when I spoke to Per and Nils about this, it's not enough for me to point at really horrible things that I have seen and say, God, it's awful, isn't it? None of you have done anything like that, have you? But I guess that we have, at other times, misused property editors in order to get a result. You may not have done something as horrific as that, but you may have put Vorto inside Archetype, inside Nested Content, or something like that, because you thought it was the right way to go. And there isn't a library of patterns anywhere, perhaps there should be in the community, saying these are different ways of achieving these things. And Umbraco allows you to do so much that it allows you to get caught and do these wrong things. But I meant to say how I would do this, and I don't know if anyone else has got any better ideas, but I would probably create a document type for an advert. So you've got a repository of adverts in Umbraco, and I'm also no tree picker, you could pick which ones on which page and reorder them. I think that would work. You could get really niche about it, create a custom property editor, as you do these days. So it's a really nice, after you see the adverts on the page, kind of thing, for the editors. You could use the grid. You could use the grid. And Nested Content, which will be in the course, who not here, or it's an advert, so you could use Google Ad Code. But basically anything but that approach. So hopefully that's covered my how to do it part. So I'm only speculating. It would have been really good to have seen some comments in the code explaining what had happened. It would have been fascinating to read. And one of the things that does fascinate me as I'm going through these sites and health checking them, and looking at code and reading other people's code, is the comments that you do find. So I'm always quite happy when I find an apology. This one here, sorry Mark, that's my boss. That's my boss's code. Telling me to code properly. And then going, oh sorry Mark, I've just done it in the view. Darren Ferguson. It's not just developers though. This designer was forced towards Foundation and Bootstrap in the same site. And, you know, help, they're making me do this. I've actually been locked up in the cupboard. No, I won't do it. And then just like, observations about it. Yeah, this makes no sense to me either. I'm not going to fix it, but hey, this was crazy. And this is really good. This is importing code. So it imports one thing after another. And somebody's going, oh, I'm not sure why this method errors, but try-catch fixes it. Isn't try-catch wonderful for fixing things? Or does that record just not get imported? If you've, um, if you've inherited a lot of sort of Umbraco 4 sites or the older sites, and they've got XSLT involved, then it's only a matter of time before in the comments, you find a reference to Greystate. Christian Steinmeier. And somebody will have said thank you to him and referenced some post that he's answered on. So that's like three or four sites, different sites, different agencies. Thanks to Greystate. I don't know why. But the next comment is my favorite comment that we've found of all time. Um, it was the only comment in the project. So the only single comment. This is the only line of code they thought was worth commenting for future developers. Who knew what that meant? So this has become a bit of a cult in the Moriama offices. And now whenever, whenever we are incrementing by one, we always comment for future developers. It's just polite to, isn't it? You know. Pass that information on. Okay. So, case study number two. Of my anti-patterns. The things I've gone really horribly wrong with. And this concerns Umbraco versions. What do we mean by Umbraco versions? Well, whenever you create or publish something in the CMS, it is a CMS, it manages content, it will create, oh, hang on a minute, I need a new avatar. My old one doesn't have the beard, you see, so. What was I saying? Right. So it's a content management system. You can roll back to previous versions of content. That's what it does. That's not an anti-pattern. That's functionality. But Umbraco has this thing where, by default, it just rolls back forever. There are no checks on it. Okay? It's okay, as long as you're aware of that. So what is the anti-pattern here? Well, it's about programmatically updating content. So you expect if you update content in the CMS, it will create a version. That's what you expect. But if you create something programmatically, no version? Use the services to update something? Would that create a version? Version. And people aren't really aware of this. They think somehow it's magic because they're doing it in code, that they don't need to roll back. And so these versions can build up. And here's the database table. So you've got, your Umbraco objects, your pages, they're Umbraco nodes. And you've got a CMS content table. You've got content types. You've got property types. And for every property type, you've then got your CMS property data table. And you can see that's got a version in there. So for every property on every page, for every version, there is a row in the CMS property data table. All right? So imagine a travel site. I'm not saying that every travel site is built on an anti-pattern. It's just so far it's 100%. But it's only the evidence I can go by. This travel site's a bit different. It's booking tours. So it lists lots of different tours that you can book online, coach tours mainly. And it has about eight or nine different provider companies. And they have XML feeds. So the XML feed's probably about 100, 150 different tours in. So overnight, the code runs, and it pulls down these feeds, loops through every one of the tours available, looks in Umbraco for a node that matches that tour. If it's not there, it creates one. If it's there, it saves and updates it, even if there's no changes to it. And so all these tours are imported into Umbraco every single night. So the editors could update the text or whatever. But that happens every single night, and it uses the content service. And if you do that kind of like, write that kind of code, and don't think about the versions, then six months later, you've got 14,006,050 rows in the CMS properties table. And we were told that the site's running a little bit slow in the back office. It's horrific. But if you think about it, it's like every single night, all those versions chucked out. It would never end. People don't realize that versions go on forever. And it's fine for normal content. A page gets updated three or four times a year. But if you're doing something programmatical, that's the anti-pattern. You need to handle the versions. So again, how would you resolve this? Well, immediately, which is what we did, is you install matbrowsers on version package. This allows you to set a number of versions to keep for a certain doc type, or to set a date after which it doesn't matter how many versions you've got. So you've got control over how many versions should be kept. There's a version for Umbraco 4 and Umbraco 7. We've got a console app which will work for, version 6, if you've got this problem on a version 6 site. Let us know. But in the long term, the way to resolve this, it's kind of, don't use Umbraco for this. Umbraco isn't a relational database. You're going to have problems doing this. In the site that I'm talking about, we built an MVC app outside of Umbraco to hoover up all the feeds overnight, bring them into one common format. We built, I think it's probably even a couple of views in MVC, and the editors can update and tweet the text. And then the Umbraco site manages the landing page content. And then we use services to pull in the search results to make it work there. We separate them out. Because, and it's not just creating nodes in Umbraco. The other common problem we have with versions is likes. So I've seen lots of sites where you've got a blog post or something like that, and you have a property, a label property called likes. And when somebody likes it, you just increment that by one. That completely destroys the functionality of CMS. You're not going to roll it back to yesterday's version where it had less likes. So you've got to think very carefully if you're programmatically manipulating content service. And I would suggest that you don't use nodes in this way, programmatically. Use a database table. So, you're probably thinking now, Mark seems like a nice person, doesn't he? We don't want to make his life harder in the future, do we? So, if Mark inherits my site in the future, as will inevitably happen when I fall out with the client, how can I make his life easier for him? So, let's do some quick-fire don'ts. Don't use only one document type for every single page of the site. Don't put hundreds and hundreds of properties on to deal with every situation. Just have one doc type. It's really difficult to use for editors. The clue is, if you've got a doc type with properties on that aren't rendered on that page, it probably should have been a different doc type with a different nice icon, perhaps with a different colour. Help your editors a bit. But I see that all the time. Everyone's first on Bracco's site. It's a little bit like that. The opposite of that is, don't create a brand new document type for every single page. So, you'll see an About Us document type or a Terms and Conditions document type and it just writes out text. It's a document type for every type of page. But again, those two are astonishingly common in the sites that I inherit. And it's a real pain to have to refax and move all the content around. Don't mix your naming conventions for the property alias. I might sound a bit pedantic, but Bracco will suggest a lowercase letter for the property alias because of the XSLT history. But Csharp, developers.net, etc. It's a public property, isn't it? It's got to have an uppercase letter there. I've watched people argue about this for hours. And it's just like, I don't care which one it is. But just decide in your company which one you're going to use so that every site has the same uppercase or lowercase for property alias. And if you can't agree in your company, then at least think about it yourself and do it the same way every time for yourself. And if you can't do that, try and do it on the same project in the same way. And if you fail to do that, just maybe in the same day. Just try and... This is really common. They've published something. We want to notify somebody. We want to send an email. We want to create some content. We want to do that. Don't cram all those things that happen on the publish event inside the publish event. Because it stops it publishing very fast. We had one where a notification was being sent. So they'd written code on the publish event to go through everyone in the AD and email them. And Bracco has notifications built in. But it meant that publishing was astonishingly, astonishingly slow. So if you need to do that, take the ID of the node, stick it into a database table, and write something to happen to poll it asynchronously. So your publishers are really quick, but you can still do all the crazy things you want to do on publish. Don't use the content service to pull back content. Content services really makes a lot of sense. The API for a developer, it seems really straightforward. So I'm going to use that to bring back content. A lot of people, when they first come to our home, are unaware of the Bracco helpers. They're looking for a service, so they use a service. But that's really slow, because the Bracco database is not optimized for front-end access. It's barely optimized for back-office access. So that is another great don't. And then, if you can't find the content service, the other thing I've seen developers do is point the entity framework diagram at the Bracco database and use that to pull back content. That's madness. Absolute madness. And you're thinking, I wonder what the diagram looks like. That is the entity framework diagram for the Bracco database. I can't fit it on a slide. Why would you do that? You don't have to learn the services, do you? But it's really slow. Another really common point of falling over is people relying on Bracco.type media or Bracco.type content. They're not magic. So if you write code, Bracco.type media.url, if that's null, that's going to just throw a Y-sod. So just writing that, you've saved a bit of time by having it on one line, but you're just opening yourself up to a null reference. That's particularly where now the media are built on top of the examine index. If the media's not in the examine index, it defaults to the database. If the media's sort of half in the examine index but not quite properly in there, you get a Y-sod. So check for nulls. Actually, these are meant to be don'ts, aren't they? So don't not check for nulls. That's the kind of thing I mean. Pull back the object, check if it's null, then read the properties. Okay, so people who've seen me talk before might be aware of a little hobby that I have. Since I've started working with Umbraco, I wander around, and quite often I just see Umbraco logos everywhere I go. And what I've realized is I can pass on, and talk with them. So I still see Umbraco logos wherever I go. This is a dentist logo on the Holloway Road. It's quite good. It's one of my favorites. It's a Umbraco tennis ball. It's really got a smile in there. This is a vending machine sticker at Wigan Walgate in the north of England. There. A bit curly there. And I was in Dublin recently, and I found this one. Umbraco logo looks a little bit drunk, a little bit sloshed in this one, but it is hanging onto a pint of Guinness, so that probably explains it. So, yeah, I still see them, in case you were wondering. So, the third case we're talking to you about today, again, it's another common anti-pattern. It's one that I see messed up time and time again. So, Examen is built into Umbraco, and it allows you to search text, and it's really fast. It's built on Lucene, and it's excellent. Its job is to find text and return it. So it's brilliant for building a search. But people use it for lots of other things as well. So it's also a fast way of retrieving types of document types if you've got thousands of rows. So you might use it to build some kind of paging, to page through doc types, rather than using the cache. But the anti-pattern is that, because we're so used to using, like, Link, and we think that Link with databases will have iQueryable, we kind of think that we can automatically chain Link statements on, and it'll do something with Examen, so that it won't be really slow. So quite often, when we come across sites with Examen, people have just done it slightly wrong, and made a slight mistake. It's a little bit complicated. So what I mean here is that, Umbraco gives you a helper for doing a typed search, so this is a helper. It's going to search for the word fish, using the external index. And then the developer's put .where document type aliases news article. The .where bit happens in memory, because typed search returns an IEnumerable of published content. So, to a certain extent, that's not great. And then the developer here has done searchResults.count, so it's an IEnumerable, and you're counting an enumerable, so you've got to go through them to count them. And then they're looping through it again, and if you've got resharper installed, like I have in this screenshot, it'll warn you about that. Having to go through it twice. Now, Examen comes with a more complex situation. I'm not saying that's necessarily bad for a search, by the way, because if you've got 12 articles with the word fish in, then filtering out the news articles, it's not very expensive to do that. So it only becomes a problem when there's thousands and thousands of nodes. Examen has a more verbose syntax with a fluent interface, so this bit here, it's kind of doing the same thing, but because we're using this fluent syntax with and no type alias news article here, it means that we're not doing it twice in memory. What results we get back from Examen are already filtered by the news article type. Examen returns an ISearchResult here, this searchResult object, and because they thought about it a little bit, Shannon's thought about it, it gives you a property with a total value of, let's say, a flight and count on it. So you don't have to return them all in order to count them. You've got the number of records there, which is super easy for paging. There's also some skip and take properties that are specially adapted for the ISearchResult, so that it doesn't do that in memory. So it's quite a bit more efficient. So let's have a look at the example site. Imagine a travel, not a travel site this time, imagine a, a print magazine that's been going for a long time in England, say it's gone for 16 years, and they've moved all their news articles, they're still relevant today because they adopt the history of the specialist area. And all of those articles have been imported into an Umbraco site, and they have a news archive, and you can page through the articles in date order. So you can see this is the paging site here, and it goes up to 200 pages, and there's 20 articles on each page. So there's about 4,000 articles in there. We were contacted, and I was speaking to the guy on the phone, and he's saying, and he said name of the site, and I went straight on, clicked around. And you start to get a bit of a sixth sense for this kind of thing. So he's saying that site's really terrible, it keeps falling over, we don't know if the agency knows what they're doing, what should we do next? And at that point I put my sales hat on and said, well let's do a health check. Moriama health check will give you a basic idea, a baseline of your site, we'll check all these common things, we'll go through the code, and we'll give you a report, so at least you kind of know, you know, it's like taking your car to the garage and getting an MOT. So he talked about it, and he said that will do, that will help us talk to our existing agency, and they'll help you to rectify some of the problems. But as I was clicking through the paging, every click got slightly slower. And I thought, oh, that's not being implemented correctly, is it? So, looking at the code, this is the code they had, they're so close, because look, they've used the more complex syntax, they've got a little helper method there, which turns nice search results. So, you know, they've probably been trained, they kind of know a little bit about what they're doing, so that's great, it's good to see. So then, they get the results, and they get the count of them, the total item count, so they know exactly how many results are in the database. They're paging through all of them, so there's nothing on the search thing there. So that results object has got, the 20 times 200 in, so that's got like 4,000 articles in, if my maths is right. And then they loop through every single result there, and they call umbraco.type content for every single result. And then, because they're using their own strongly typed approach to doing views, then as they loop through and they pull back, as long as there is an umbraco-type content result for it, so they've obviously tried to fix a problem where the node's in the examine index, but it's not published. So this code here, they'll check that, and then they'll add it to their own, their own list, list object, if I publish content, and they'll add that in there, on the model. So they'll loop through all 4,000, and then after they've looped through all 4,000, they'll do the paging. So they'll do skip and take. But these 4,000 records are in memory, so they're doing that skip and take in memory, on their own there. So it's really, really slow, and of course, as you, if you take the first page, perhaps when you're testing, it's quite quick, because it's an iron umbral, so you can get the first, first 10. But for a site with 4,000, as you page through, that gets slower and slower and slower. And this is a real anti-pattern, because it's like, people get quite close, but they don't, and then they don't understand why. Now, we were a bit lucky on this, this one, that we had the, the Git repository, which showed all the commits. So we could actually see that they knew they had a problem, and we could see the bits of things they tried to move stuff around to fix it. And the comments they said, saying hopefully this will work, et cetera. But the surprising step they took to try and fix this problem, was to install an IIS module. This isn't the name of the IIS module, I'm calling it speedy speed speed speed, just so that, you know, I'm not casting any aversions, it might have been this environment that this was installed on. So I'm not, you know, basically this is a clever thing, it'll look at all requests, it's from a mobile phone, it'll shove down a smaller image, and it'll, lots of little things like that to improve the speed. But it didn't really, doesn't really have the ability to fix bad code. So the best thing here to do is to look at your code, not just guess and install a module. So this is fixing the code. And again, when you take on a site like this, you don't want to change too much instantly. A lot of agencies will look at something like this and say, you need to rebuild that from scratch. And a lot of people say, well we haven't got the money to. But if you say that 10 times, somebody will say, yes. And you'll get a new build from scratch. You can do it badly, and then go off again. And that's probably quite a good business model. There seems to be a lot of agencies out there following that model of, of just building something, getting paid into that. So when we inherit a site, and you try to save it, you try to change as little as possible. So all we've done here, to try and resolve this paging issue, is we've moved the skip and take, so it's actually happening on the iSearch results. So it's using Shannon's more optimized approach of taking a page of items. So because we've done that, so because we do the paging there, the page results there, that's only got 20 items in. So when you loop through the 20 items, and do the iPublish content thing, you're not pulling back 4,000 iPublish content objects. And then you can add it to the strongly typed model. And this sped up. When you're clicking around the paging, you had a consistent response time. And it really sped up the Umbraco site. It made such a difference. However, we couldn't celebrate yet, because the site still kept falling over, and crashing. And we looked at all of the common things that we would check, with code and so on, and tried to pinpoint what it was. But there seemed to be no rhyme or reason as to what would be causing this to fall over. The agency had told the company that this happens quite a lot with Umbraco, and you just have to do an app pool recycle. So there was a pattern of the company, the site back office being slow, then phoning the old company, the old company going onto the site, doing an app pool recycle, charging them for support, and everything was fine again. And that's the way Umbraco is. And that really annoys me. The thing that annoys me most about these anti-patterns is that people who come across them, they go, Oh, Umbraco's terrible, isn't it? It's really hard to use, it's really slow. But it's not Umbraco. It's just a really bad implementation. So anyway, we looked at things, and instead of just doing an app pool recycle the next time it happened, we got an IAS dump, I say we, Darren, and trawled through all the threads to see what was happening. And what we found was that the speedy speed speed speed module was blocking the garbage collector threads. So it could never clean up after itself. So the memory grew and grew and grew. So it was only a matter of time once it did an app pool recycle that it would happen again. So I think just hitting app pool recycle is an anti-pattern again, because it allows problems to exist much longer. So always be careful. Always try and find out why. Particularly if you're doing app pool recycling, you have to do the same tomorrow. If you do one app pool recycle and it's six months before it happens again, maybe it's not a problem. But in this situation, it was. So we took out speedy speedy speedy, on this date, with the orange line there. So you can see, all these red lines here is when the site was unresponsive and down, effectively, to the client. And all the spikes there. And afterwards, it's fine. Response time's fine. It doesn't go down at all. So that isn't such an anti-pattern, but I just thought you'd appreciate the irony of the fact that the thing that somebody put in to try and fix the bad code was the cause of the site going down, which eventually, lost them the client. So I need to pad a bit more. So, sparring Umbraco logos is okay, but you know, if you're a bit like me, when you've been doing something for a while, it's not quite as much fun as when you originally did it. And what I've noticed that a lot of the cooler kids in the Umbraco community do, is they're playing Umbraco Street Bingo. Umbraco Street Bingo is where you take an Umbraco bingo term, and if you see it in the street, you photograph it. And tweet it. And it also pads talks. So this is Courier. This is a poster for a magazine in London. It was a good spot. The O2 has Concierge there. Can I get all, can I get the main three? Thanks to Jeven, yesterday, on the walk up to this venue, on the wall, contour. It's the main three. It's a bit boring now they're calling it Umbraco Forms and Umbraco Deploy. I'm not going to be able to find stuff. At Festival, I got very excited because I found Poco classes. Can I take a picture of your halloumi stall please? And finally, this one's for Kevin Jump, who's here with us today for the first time at Code Garden. A venter of U-Sync. If you've used it, buy him a beer. We're thanking for it. It's quite hard to find U-Sync in the wild, so I'm pretending, if you squint, that the frame, that grey frame up there is forming a U. U-Sync. So, it is quite hard. Yeah, they're actually the only ones I've found. But if you do find one, take a picture and play hashtag Umbraco Street Bingo. So, I'm coming to the end of the talk and I think I need one more case to explain it. So, I spoke to Darren, my boss. I said, have you got any ideas about anti-patterns that I could talk about that you've seen? You've much more experience with me. You've been doing this for years. Well, can you think of any particular time where, you know, something's gone wrong and we could perhaps talk about that? And he said, yeah, yeah. People always mess up multilingual sites. They're never really quite sure what the current culture is and things like that. And, didn't we have that site once where none of the translations worked? And I went, oh yeah, I remember that site. I built that site. It's no, I'm looking for, it's okay for me to point to other people and say that their code's wrong. I can't, that's mine. I, we can't talk, that's not an anti-pattern. We were really busy that day. If you remember, it was a last minute change. I didn't think, well, let me show you what it is. So, imagine a travel, no, imagine a campaign site where you have multilingual campaigns. So you sign up for the campaign, fill in a form, they'll send you a PDF or something like that. So the form needs to be translated in all the different languages. And the industry drop down that you have to say what industry you're in, God knows what marketers do with it. But that needs to be translated and in alphabetical order. So, I built an API and put it in, which would accept the current culture from the page. And then if that, if it didn't send the current culture, it would just return English, so it didn't YSOD. And it would return them in the right order for the drop down. And I put that in a bit of JavaScript there. You can see I'm passing the current culture in. And I have that at the bottom of three different views. Now, what we quite like to do at Moriyama is we like to have a bit of a peer review. So, basically, we talk through our code with other developers and explain a little bit about what we're doing. And so, It's not like a proper kind of code review where you try and brutally destroy the developer. It's just like a chat about what we did, really, because we're all geeks and we're just doing what we do. So, Darren suggested, quite rightly, he said, don't put this at the bottom of the page. You know, put it in some JavaScript file. So, it's like neat and you can use it across the site. And this was like the morning of we were going to put it live. And that's a really small change, isn't it? And you should always make really small changes before you put something live because nothing can go wrong. But he's my boss, so I thought it was a good idea. So, I did that. I created a campaign form, JS file, and I copied and pasted that in and I tested it. And it worked. I got lots of English drop-down industries. There was no errors. The JavaScript was still fired. But, of course, I forgot that Razor doesn't work inside JavaScript files. So, it always sent English. So, I tested it. It was fine. It seemed English to me. The client was happy. I don't know if they tested it in other languages, but they tested it when it was working. And we put it live. And it was an hour later, and we went, how did that happen? This is all in English. And spotted the mistake and went back and rectified it. So, I suck as well. And so, the anti-pattern here is like those last-minute changes, as easy as you think they are, you know, don't do them. Say no. Say, all right, it's a good point. When it's live, well, we'll go back and change that. But too often, as developers, we don't say no and we just try and make changes forever and just let ourselves open to these mistakes to creep in. I mentioned peer review. And I managed to Google and find some numbers on the internet which said it was a really effective way to do things. So, it's more effective than writing a unit test if you just go through your code with somebody else. But I wouldn't really try and sell it on the fact that I found a figure on the internet. The main thing for me is if you talk about your code, you feel a little bit more relaxed about it. If you're the only person who's looked at that code and you put it live, there's pressure on you and you're like, is it going to work? Is it not? If you talk through somebody else, you share it. You share that issue and you learn and you just feel better about the code that you've written. Oh, it's going to be okay. So, I can recommend peer reviews, definitely, and just chatting to people about code. And that brings me on to a general point. It's like, how do we find ourselves in these crazy situations? How do things like that check box thing, how does it get live? How does it happen? As us as developers, we're the people in control, we're doing things that even we can see are wrong. So, think about questions like, when people ask you, how long will it take? Or, could you just... Or, when will this be done? And none of those are questions we're asking you, the person who knows kind of how to do it, whether you should do it or not. They're all implying you've got to do it by a certain date. And if somebody comes to you as an introverted developer and says, can you do this in three days? And they're like a professional project manager or a professional developer, you're like, I don't know. But you must think that I could do it in three days. So, maybe my job is to do it in three days. So maybe if I say no, that means I can't do my job. So you say, yes, I could do it in three days, I think. And that just means that you work all the evenings and all the time that God sends to make sure you're delivering to this completely artificial deadline. Because you didn't say, no, I don't know. When a developer gets asked how long things take, there's only two or three replies that they can give. The first reply is, it'll take two minutes. Okay? And that means one thing. That means that the developer's written the code before and they know exactly where to cut and paste it from. It's a two-minute job. But it also has a second meaning, which is, I've never done this before, but I really want to have a go at it. It's just a two-minute thing. Let me have a go at it. And they do it to lull your interfaces and security. And that's not too dangerous in a way, because you'll find out after about half a day that it isn't a two-minute job. But it's not a straightforward answer. The other answer you'll get is half a day. That means the developer's done this before, but doesn't know where the file is to cut and paste it from. So half of the day is going to be looking for the code to cut and paste. And then you say, well, maybe about three days. Maybe a week. The point is, anything after that half a day point is a complete guess. Like, code is art. It takes time to layer and build and work on it. And find out about it. And put something together. You can't measure it in that way. And the longer the time scales, the more opportunities there are for something to go horrifically wrong. The two-minute thing, the half-day thing, you find out that it's on tap. But if somebody says it'll take three days, what do they actually mean? Does it mean in 72 hours it will be ready and live? Well, no one would think that would be insane, wouldn't it? You've got to sleep. So how long is a day? Is that eight hours? So is it going to be ready in 24 hours? Or do you mean like three days stretched over six weeks, because they'll be doing other things like making tea and chatting? There's no... There's no... As soon as it gets that long, there's no way of really knowing how long it's going to be. So you have to break those tasks down, the developers. So how long will it be this bit? Because otherwise it's just a guess. And you don't know. And this is when you get into these situations where you rely on patterns because you know you've done it before. And this is where anti-patterns creep in. My theory, anyway. The other question we get is when is that something actually done? So if you say to somebody, have you done that? We quite often get the answer again, yeah, it's done. And I'll go, is it done done? And I think you know what that means, don't you? You've done it. Is it done done? Does done mean done? Is it done done? I have a theory that when developers say it's done, what they mean is they've got past that horrible, embarrassing stage that they don't want anyone to see their thoughts or attempts at doing the code, and they're quite happy for someone to see it. But actually, they're really emotionally tired from having done that and now want to look at something else. And so they want to have more conversations about it. So saying it's done is the most convenient thing to do. Which is fine. That's how they work. That's good. So you should work with that. The danger of that is that then they get on to something else and they forget whether they actually did it, whether it's done, whether it's done done, or whether it's done done done. So I've introduced a new term there. Done done done is when something scary is about to happen in a film. The whole talk was just for that joke. So you're left in this really awkward situation. So we've stopped saying, is it done? We've started saying, is it shippable? Because the two things are different. And actually when a developer says it's done, that's the perfect time for the peer review. So let them have a break first. Don't just sit at their desk and say, let's go through it then. But shortly after, arrange for it and review it. And then that's when you can evolve and change it at the point when it's not got too far. Because once it's done done, a developer never wants to change that again. Because it's done. I don't want anyone to visit that. But when it's done, it's okay. So that's the point at which you can improve the code and try and avoid anti-patterns creeping up. But I also feel like we live in this era of relentless positivity. And I've read a few articles on the web about it. It's quite interesting. And all these things like, yes we can. They sound like fantastic positive slogans of things. Just do it. Everything's awesome. Yeah. Cool. And if you're an introverted, self-lacking confidence developer, you feel like you've got to do things because those other really cool kids can just do stuff, can't they? And so it sort of drives you. And I think it's, you know, there isn't ever a slide or a slogan that says, well that's okay, don't worry, have a cup of tea, have a think about it. Write a bit of code. Work out whether you know what you're doing. And we'll plan a few tasks. You can't put that into a little slogan. So you feel compelled to make these quick judgments to get things out. Who's ever rewarded somebody and said something like they've got a can-do attitude? They're good. No one says, oh well he thinks about it a bit. He's a bit slow. That's not a positive thing. But actually, I think we've lost the whole concept of building prototypes and exploring a solution before we ship something. All these things could have been prototypes and stopped before they went live. And then refactored. When was the last time as a developer you actually said no? When you actually say no? Developers always say, yes, I think I can. And no is a really positive word to say. It feels like I'm being negative saying no. But if you say no, somebody might say why? And suddenly you're discussing, got a dialogue with the person who's asking you to do something. So you can actually say, well, because we need to upgrade the servers, we'll find budget to do that because we need to do this thing. And suddenly you're doing it. But if you say, I think so, I'll go off and have a look, then they think you're going to do it. So no is a really powerful word to say in having your vocabulary. And I often wonder, do I say yes too often? Three weeks ago, a pair said to me, do you want to do a talk at Code Garden? And I said, well, if I did, I'd probably do it about anti-patterns. I've got a few ideas. But the thing is, I'm doing the training in London. And the training in Dublin. And I'm camping for a week. I have no digital access at all. So I don't think there's going to be time to do it well. But I didn't say no. And so the first I found out about it was on the campsite. Got a bit of Wi-Fi. Jay Griessle tweeted to say, oh, looking forward to Mark Goodson's talk at Code Garden. And I hadn't said no. If I'd said no, you'd all be watching a talk that was perfectly polished with pretty slides and stuff. And I got back and I said, well, I've got to do it. I've got a can-do attitude. I don't want to let Umbraco down. Pear thinks I can write a good talk in two weeks. Maybe I can. So I took an agile approach to it. I planned it all out. There was going to be a song. I was going to have a ukulele. I was going to do the anti-pattern song. There wasn't time to do it. It's failed. So it's got to this point where I haven't even been able to think of a really clever, cool, overarching theme to bring it all together to end it in a way that makes you feel like I've done a really good polished job. So in a way, I've completely, I've shipped the talk. But it's not done. It's not even done done, you know? So I can only really apologize for that. But it at least makes you feel like you're expecting a really good polished talk, right? And at no point did you think that delivery was not going to happen, except for the first slide. And then you're left here in this awkward kind of, the man's talking on stage. He clearly doesn't know what he's going to say next. There is no ending. And you feel a bit like, oh, it's a bit odd. It's okay. Well, he's done something. That's okay. That's good. And he means well. But it's not really what we came here for and spent all this money to come on a plane. And this is exactly how your clients feel when you ship something that's done. Ah. Ah. Have I done a, is it? No? No. So that is the official end of the talk. And I'm really sorry that it wasn't a clever, overarching thing that brought everything back together. Or was it? Ah. So all I can say is, fail, fail fast. Fail fast. And celebrate failure because that's when you learn. Celebrate and look at other people's sites. Looking at code. Talking about code is brilliant. Find somebody that you like and who likes you. It doesn't have to be the same company and talk for your code because you'll both learn. It's really good. Don't let anyone make you be as awesome as you want to be. Come to the official Umbraco training, though, of course, because that's how we make our money. But that's how you can learn as well and learn the proper patterns. And then, if the last thing is, just, if you're writing code and I'm going to inherit it in the future, just put me something, just a little comment in there for Mark. Make me smile in the future. Now, that's the end. If you let's You're eat Thank you. Thank you.