Thank you for coming to the talk. So I'm Yeni, and today I'm going to talk to you about washing away cold smells. So this is a nicer picture of me than real life, and I'm originally from Hong Kong. I'm a software engineer at Yelp on the business national team in Hamburg, Germany, where we're scaling advertising tools and also doing reporting solutions for our biggest customers. I was previously a speaker at PyConDE, PyDays Vienna, and also the talk PyCon podcast. The reason why I want to mention this is because I learned a lot from these kind of experiences. So I just want to give credits for the people I talk to, the organizers, and also a lot of things that I learned through the experience of presenting at these occasions. So yeah, a little bit more about my company. Our mission is really simple. We want to connect people with great local businesses. So you're in this beautiful city of Edinburgh, and one of the really important questions you ask yourself is, where do we get dinner, right? So Yelp help you find exactly that through people's reviews, photos, videos, and also their opinions on which one you should go to. And that's one of the things that I'm thinking about as well. And this is probably what our homepage looks like here. So there is a search, and you can just put down the category that you want to search for. So pretty easy. And some fun facts about our company. So Yelpers have written over 155 million reviews. There are a lot of users, as you can see, a lot of monthly unique visitors. And our engineering team is growing very fast. We have over 500 developers now over the offices of San Francisco, of London, and also of Hamburg where I'm working. And we have over 300 services, and our model list, Yelp main, has over 3 million lines of code. And why am I bringing this up to all of you? It's because when you have so many people working on the same code space, it actually really important that we keep a standard of what kind of code we're checking into production. And that's why I want to share with you this little message that I learned basically from my time at Yelp here, and hopefully you'll like it. So that leads us to our agenda. We're going to talk about what code smells are. Why is that something that we should spend time in? Why should we care about this? Why should we spend our engineering effort into clearing out these code smells? And how we can use the technique of refactoring to wash away these code smells.  So let's get started. What are code smells? A code smell is a service indication that usually corresponds to a deeper problem in the system. So one thing to know is the service indication here. So sometimes you can have a code smell, but maybe there's nothing wrong with it. If you look deeper into the code, if you do some investigation, maybe that's what it takes to complete the problem. But so this is the service indication. So I want to bring forward a metaphor here. It's like eating cheese, right? Sometimes you smell really, really pungent cheese and you think there is a problem with this. But then when you eat it, oh, it's actually fine, it's good cheese. So that's something like code smells. So why do we care about this? So the tech lead for Twitter's engineering effective groups once said that 1,000 flowers bloom and then rip 999 of them out by the roots. So what do we mean by that? I think that's a metaphor for your developers have a lot of ways to do things. And yeah, of course everybody can try out their creativity. We can try out things and see if it works. But then gradually through experiments, we realize that some of them don't. So that's the time when we want to rip them out from your code base. And this is why we should do that. First of all, when we just leave it unchecked, it builds up tech debt. So what that means, it's not like if we procrastinate and not solve this problem in this project, it's gonna go away. It's actually gonna gradually build up and comes back to you in the next project, which is actually exactly what is happening to me right now, but so there's a problem. And also, it's not like if you design the code, like say I'm very good at designing code, I do it right the first time.  So code actually gradually rods as time goes by. So one example that I can give you is say you have a code base in Python 2.7. You can create everything that's of the standard of the time. But then over time you'll code rods and now we have to migrate to Python 3 because there are new standards. There are news experiments that people do that make things better. So here, we don't wanna let your code rod. And there is also a class of saying that talks about why do we need to uphold that kind of quality in code when one day we will throw the code away because technology moves so fast and we're building so many new products. We might have to get rid of the old products. So why do we have to maintain this standard? Actually, this is a very strong argument on why we have to spend time doing this. It's because only with good code can you identify what to throw away immediately. So I can give you an example. I'm sure in your company, there is this one file, there's the admin code that is 4,000 lines long, nobody know what it does. And that's not great because when you have to throw away functionalities that you don't want, this is the problem here. You don't want your code to be like CSS.  This is not what you want your code to be like. And at the same time, I also wanna bring forward that it decreases productivity. So I definitely have that experience before. I'm working on legacy code. Well, in my dry run, I keep on saying legendary codes, so I have to be very careful here. Legacy code and yeah, I thought I figured it out this one day. Okay, I know what's happening. I'll even try to write down how it inherits 10 hierarchy in the Python code. And then the next day, I sleep and I come back to work and then what is this? So imagine that times five because your whole team is struggling and doing the same thing. So that really weighs our productivity here. And there's one story that I wanna share with you briefly. So in New York City, there is an area with a lot of primes. And the city is very dirty and there are a lot of drug problems, homeless people. And then they actually send in some psychologists to check what is the origin of the problem of why is it so dirty, why are there so many problems? And actually, it all originated from a few broken windows, can you imagine?  You can check in code that is not of enough quality. You're checking in code that is not up to the standard. So you don't want your code to be like this. And at the same time, I also think it's very important for developer happiness and why is that? So a show of hands, who here just really likes working on legacy code? I will, can I say it's not the majority here? Yeah, so you get the idea. Maybe that's also important for us to retain people if your day-to-day work is just cranking out what your Python code of ten levels of inheritance means. Yeah, so probably we don't want that. So we have the technique of refactoring that can actually come to our rescue. So one thing to bear in mind throughout the talk, it's about changing the design of your code, but not the functionality. So the end result of what is being produced shouldn't be altered during the process of refactoring. So here, let's go through a small example to develop our code notes to see if we can identify some of these code smells here. So I'll give you one second to look through this. I'm not brave enough to do life coding, but this is the best I can give here. So this is a fairly simple program that gets us the cheese we want based on our mood, hunger, and money. So there are a few problems here. This is supposed to be a fairly simple function, but it's quite long. No, let's see what kind of problems we have here. Can anyone in the audience already see if there is any problem? It's missing one more than three times. Yeah, that's one of it. It's missing tests. Oh, missing tests. Oh, that's an interesting one. We'll talk about that in a second. Multiple return points. Yeah, that's a good point. So let's organize that a little bit. I think you basically hit all the points here already, right here. So first of all, the naming is a little problematic here. So mood is bigger than three. What does that even mean? Does that mean you're ecstatic? Does that mean you're sad, angry? There is no way to tell. So if it's not for the comment, we actually don't know what we're meaning here. And we're using comments here as a deodorant to cover up our code smell, right? So the problem itself is we didn't name things correctly. And that's why you need to write a comment to kind of explain what your code is supposed to do. But we don't actually need that, do we? And as you pointed out here, we have some dead code that never got executed. So for a simple program like this, it's pretty easy to spot out that this never gets executed. But for, say, the program that I was dealing with, maybe it's much harder to see what is being run and what is not, especially when you're not familiar with what the code is supposed to do. And duplicated code, which we can also extract out of the if-else conditions. And also conditional complexity, right? For a simple program like this, we're nested it for three levels, which is probably the maximum we should have. If you have more than three levels, you really should think about if there is another way to do things. But yeah, let's do a simple refactoring here. So magic and, oh, we have something better. In real life, it rarely happens this way. You actually have to take some effort to do that. But yeah, let's point out the things that we have improved here. First of all, just want to mention there is a nice doc string that tells you what the function does. That's usually helpful in most of the cases. Also, we changed the mood bigger than three to is happy. So now you know it's actually happy. And we have introduced something called the guard clause that's here to get rid of the complexity. So one thing to know is the top four are the cases where it's not supposed to happen. And the last one is the default case that you want to return. So if I have money and I'm hungry and I'm happy, I'll return blue cheese. And also, Bruno, this one is also pep eight compliant for people who like pep eight. Yeah, personally, I don't recommend you to go buck your colleagues and just be like, oh, you're missing a space there or missing an indentation. They're actually automatic tools that you can use that. But I think it does bring value to your company because since we're working with more than 500 developers, it's good to have a style guide of how you write code. It just makes things easier to read for everyone. And also it avoids get merge conflicts. So that's the practical point. So yeah, we have taken a look at a simple exercise. So now we're gonna dive into some of the points that I wanna mention for refactoring. So just a quick recap of what we've done here for the refactoring. First of all, we named things right. Same for the comments point. We have removed that code and we have dried out the duplicated code. And also we have reduced the conditional into guard classes. So I can briefly categorize these into categories. And these are probably the lower hanging fruits that you can get basically once you start refactoring. There are definitely much more ways for you to do that, but we can also investigate into that later. These are the things that I think it's easier to do and has the most immediate effects. So name it right. Naming is actually one of the hardest problems in programming. Do you know which three it is? Yeah, naming is one of them. Cash and validation. Cash and validation, then one more. Threading, okay, there we go. Three of them. So I'm happy to talk to you about one of it, which is naming things right. So it's a cure for uncommunicative naming. Python itself, it's dynamically typed. So since you don't have the typing information, we want to name things very clear so that other people know exactly what's going on here. Of course, I would also recommend pushing for type annotation. That is one thing that will help, but naming is also very important for Python. And apart from the variable naming that we have mentioned, there is also function and module naming. And module naming is probably more specific to Python. So you probably don't want to do something like from yelp.business.bizimport.bizinfo or something like this that doesn't give people a clear sense of what you're trying to do. And that's just asking for bugs. And at the same time, keyword arguments, that's part of the PEP aid as well, that increases clarity. So if you have it in the code that you're using, then you don't have to go back to the original function to check, actually this one corresponds to mood, or is it hunger? So it just saves you some time and increases clarity. At the same time, I would want to introduce replacing magic strings and numbers with enumes. I think that's a very good practice. So here there is a short how-to that we can go through together. So one thing that is good about it, so even though it's happy, it's not as explicit as this one. Now you can specify your mood to be exuberant. You can be content, you can be apathetic or melancholic as specific as you want. And you can specify it right in the enum class of mood. And if you're a fan of being explicit over implicit, so I think this is something that you'll like. And at the same time, it also have pretty good properties, like it supports iterable and also it's hashable. That means you can use it in a dictionary, you can use it as a key. So it can be a substitute for just a pure string or an integer. And that's really great because consider the situation where this string is just used in like 15 places in your code and suddenly your product manager wants you to change it into something else, which happens very often actually. And then you just have to change one place in the code and you don't have to worry about typo because there is just one place. So that's something that is considered a good practice. At the same time, I want to push for also getting organized. So it sounds pretty simple, it's actually probably one of the hardest thing to do. It's a cure for long functions, classes, and param lists. So one thing that this wants to uphold is the single responsibility principle. So your function or your class is only supposed to do one thing. And how do you know that? Actually, when you're after you write the function and when you try to name the function, if you find yourself having a very hard time naming that function, it's probably because you're not following the single responsibility principle because it should be fairly easy to name if it's only doing one thing. So in this case, you might have to extract some of that into other functions or break it down. There is also decomposed conditionals, which is one of the getting organized method, and also dry, which is don't repeat yourself. I also didn't know that I had to look it up. I think in the beginning of when I learned about this, dry actually means don't repeat yourself. So yeah. One of the example that I want to give here is fixing long parameter lists. I think this I've encountered when I'm doing programming as well. And so here there is a simple example of identified cheese. And you know identified cheese is a hard task. So like we need to pass in the country, smell, touch, city, year, taste, you know, a lot of information for the program to decide what cheese it is. But you know, gradually this list grows, right? And it gets out of hand. You know, you have what 20 parameters that you want to pass in. That's kind of like an eyesore. So what we can do is we create name tuples that can organize these things together. And you can even add type annotation that kind of groups them into a more orderly fashion. And hence you can only pass in, you end up passing in only two things. Of cheese production info and cheese attributes. So, and there is also like a, it's a way to document what exactly do you want to pass in. Name tuples to the rescue. And actually going from this point, why do I put name tuples instead of other data structures? So that's also one thing that we need to think about when we're designing. So I will want to go through some examples to talk through why dictionaries versus name tuples and also lists versus sets. But you know, like you use these data structure based on your need, but in this case maybe one thing is better than the other. And we'll see why. So here's how it's like using dictionaries, but this is a wrong case or a bad case of using a dictionary. So just one second for you to digest this. So we're just doing some cheese math manipulation, I guess. And we're passing in a dictionary as a default value. So I'm passing in cheese counts that consists of green and blue. And we're just doing something simple like cheese counts blue incrementing by one. But what is happening here that is scary is, so what Python's actually doing is just saving that into like a default variable. And in the beginning you have what you expected, right? Green and blue, both are equal to zero. But after you call it once, what happens? This actually gets mutated and your default got changed. So depending on how many times you're calling your function, your default is different. And that's pretty scary. And imagine having to debug this in our monolith code base, I cannot imagine. So this is one thing that we actively try to avoid, putting mutable data structure as a default that's not recommended. And here is where name tuples can come as a rescue because they're immutables. So the same thing, we can actually pass in cheese counts as a name tuple. And here is how you can specify a default for name tuples. So here if you're just specifying blue equals two, the default knows that blue is equals zero and blue is equals two. If you don't put anything at all, then you get blue equals zero and blue equals zero.  So that's better because you realize the mistake before it goes to production and I don't know how far it can take before someone finds out. So there's that. And also between using lists and sets. Here is a function that select my favorite cheese from the catalog. So we're passing in two things, the cheese catalog and also my favorite cheese. And you're just basically doing a loop to see if this thing is in the my favorite cheese list and we'll return picking the favorite cheese from the cheese catalog. And yeah, everything looks good. We're passing in blue and cheddar into the cheese catalog. And my favorite cheese is truffle brie because of course, and also blue cheese, right? And in the end you return blue cheese because that's the only thing in the catalog. It's supposed to do what it does. And that's good, except it's a very long function for this because we can do something actually simpler than that. And that's where sets come in, right? So right now, how many lines do we use? One, two, three, four, five lines for a one liner like this. And you can basically just use intersection to come up with the common set between your cheese catalog and my favorite cheese. So it also returns the same result, except now it's a one liner, which is more of a pythonic way of doing things. But of course, there are some drawbacks between sets and lists. Maybe sometimes sets has performance or memory implications. So that's also something that we need to consider when we're refactoring. But for like a general use case, the set comparisons are pretty awesome, no? It is. And yeah, another suggestion is to check out the standard library. There are actually a lot of gems in there that I feel like I personally also don't spend enough time on it, especially iter tools and collections. If you make something an iter tool, there are a lot of iterable, you can actually make use of a lot of toolings that are on it and also with different collections like sets and other data structures. So I think those are pretty handy. And yeah, testing, so we're missing some tests. So let's talk about testing. A pretty short one, but it's pretty necessary in the refactoring process because if you don't write them, maybe it's too late already. So the first part, I would recommend writing integration or end-to-end tests for the code to be refactored. And that ties back to the one of the slides we talked about, right? Refactoring is changing the design of your code and not really the end result or the functionality of your program. So supposedly, if you write an integration test, they should pass throughout the whole process of your refactoring. And that's also your compass to make sure that you're doing the right thing during refactoring and not deviate too far away from what the program is supposed to do. So it's kind of like a check for myself. And of course, you're having fun doing all the refactoring. And after that, we can write some unit tests for the refactored code to make sure that the code is actually correct. So this kind of helps you gear you towards the right direction in the refactoring process. And I think we shouldn't be lazy with the tests. It's a very important part of the refactoring process. So cool. And so if you think that you're so sold about the refactoring idea, like tackling cold smells, how do we sell this to the company? How do we talk to your product manager about this? How do we convince other people to also jump on the same boat? The secret weapon is code reviews. So I remember when I first joined Yelp, I don't know who told me, but one of the people who told me, I don't know, like a Boy Scout rule is you should leave the code cleaner than you found it. And I think that was very valuable advice. Every time I'm trying to push some code, even if I'm not trying to reinvent the wheel or try to refactor to a very deep extent, I try to make it a little bit better. Say I see a variable that is not named correctly, maybe I can do a little change. I see a test that is not well covering the code, then I add another test to make sure all cases are covered. So things like that. It's a culture that we need to cultivate in the company to make this happen. So one thing that we can do is also to encourage refactoring when people are adding code and especially fixing bugs, right? Because something happened to the code and refactoring can probably help with that. There are also other things like you can write code review guidelines to tell the code reviewers what to look for, especially when doing code reviews. So these are also pretty good advice that I've heard. And I think the harder part is coming with the product manager, because they definitely have, usually they have a different agenda than engineers because they really want the product to ship fast and they care a little bit less on the engineering integrity or the engineering quality. One way I would go about that is to break down the tasks and really take maintenance into account. So from my personal experience, as I told you, right, I'm working on the legacy code base and yeah, I have the hardest time trying to understand what is happening there and afterwards I have to spend a lot of time to maintain this code base and it actually takes a lot of time that in retrospect maybe if we have rewritten some of it, if we have refactored more of it, we can actually save a lot of time in squashing the bugs afterwards and in the maintenance part of it. So a rule of thumb that I tell myself is four weeks, four with refactoring with the maintenance effort and otherwise six weeks because we have to account for the times that we need to get ourselves into the not-so-well-done coder again. But yeah, if all things fail, maybe one thing we can do is to abstract out the implementation detail and as a good engineer, you can adjust your estimates to include refactoring and also the test and just say this feature takes X but that's the last result. Yeah, so far we've gone through mostly the manual work of doing refactoring but there are some things that can be automated, not all of them. So I think we have some open source tools or things that we use. One of it is called Undead. So that's based on high parsing. It can do massive find and replace. So that's something that's helpful because if you want to deprecate a function or deprecate a class, deprecate a package, you can do a massive find and replace. And on the same note, we also use a debt tracker called branch debt and for some of the code reviews, we actually include that into the code review itself so that gives people more pressure. But both the reviewer and also person who writes the code, how much tech that they're introducing and the new code that they're deploying. Some of the example metrics that this tool looks at, including how much no QA text you put in in the code, how many deprecated functions are you using or also how many lines are you adding to the monolith, y'all main, because we want to move out of it eventually. Yeah, so these are some things that can give yourself more pressure to really deal with it now instead of procrastinating it to later or another project that you're working on. Yeah, some of the takeaways just to wrap it up. We talk about code smells, why is it important? How do we use the technique of refactoring to get rid of them? And also some of the tips to bring that to your company if you're sold about the idea of refactoring and code smell. Most important of all, if you want to work for a company that cares about code quality, that lets you spend time to do refactoring work, we're hiring, we have offices in Hamburg, that's where I work, London and also San Francisco. So we also have a booth down there if you're interested and want to talk to us, we're there. Yeah, thank you. Before the questions, let me remind you, actual questions. So who has one? Thank you for your talk. So one of the things that wonders me from some time is, because many of these tips looks like, when you know them, they look like, yeah, great idea. But are people likely to just make up them by themselves, or do they rather need to learn them? Do you have an experience, like, did you see junior developers, for example, looking at such bad code? And do they know what to do with it, or rather... So you mean how to acquire the skill of practicing your code notes to spot out what is good in a code and what is bad? Yeah, so I'm just wondering, what are your thoughts about it? Is it like people need to learn it, or rather, they just see what's bad? Well, I think... So there is the first gatekeeper, which is the code review, right, where, I guess, more experienced engineers tend to tell newer or less experienced engineers what they have learned throughout their times, but I'm a proponent of, you know, you crash and you burn and you learn. So, you know, next time you'll know, because you see what didn't work. Any more questions? Why didn't you see it closer? Okay, so my question is related to you say that you should leave your code in a better scene than you found it. Some could argue that goes against having small reviews, because now the reviewer has to see 10 pages of the factor instead of just the actual value added, so to say. So one of the practice I usually use is, I see the problem, and I usually tackle it in another code review, just so, because it's a different context, but I should, I would recommend following it up immediately, otherwise it will lost in the Jira, Jira forest jungle. Or, yeah, or sometimes if you identify these to be good new hire tickets, that can also be the case. Anything else? Thank you, Yany. What's it? What's the top level? Come on. Go ahead.


Yeah, it's good to be back. It's good to be here with you guys. Good afternoon. Good morning. Good evening wherever you find yourself Welcome to another video here on the channel me plus you is us and my name is Kwame and today I'm here alone because the thing I'm about to discuss with you as you've already seen in the title I believe is something that I have done the most learning on and I believe that it's something that I I would want to share with you in the last seven years I've had to learn and relearn the hard way and rediscovered that over and over that These things I'm about to share with you don't ever stop you keep learning and you keep relearning and it never stops so you have an argument with your partner and you know tempers are high you're Not thinking straight.  How did we get here and the arguments just gets keep getting heated and Yeah, it's a struggle and it happens all the time and I have to say that you know a healthy relationship is one that is thoughts In my opinion devoid of any arguments So long as you're two individuals with differences, they'll be miscommunications. They'll be conflicts that would need resolution And I believe it makes you stronger, but if you're having or enjoying some kind of peace and you feel that Yeah, you should just find something to argue about that's just No, that's just witchcraft. That's that's mentally Mentally deranged in my opinion move to pull in a relationship or in an argument So yeah, that's not what we're talking about here So let's get to what you should not do in an argument with your partner or your spouse or your girlfriend in a relationship that you're in What you should not do things that I've learned to not do when there's an argument And I hope you can get something from it as well. So the first one is What I I call The vague apology, I mean, it's not what I call the big apology It's the first one you should not do is the vague apology the vague apology It's when you want to avoid a conflict all together You don't want to argue and you think that you know what to de-escalate this whole thing Let me just apologize for what's happening and let's call it quits So let's call it a day. It's fine. I'm sorry. Whatever is happening. If it's your fault or mine. I'm sorry Let's just stop it. Okay, because it's uncomfortable and I don't want to do it anymore well, let me just say that the vague apology doesn't work because your partner will most likely ask you what are you sorry for and Half the time if you're aware what you're sorry for It's better that they hear it's reassuring that they hear and Know that you acknowledge and you are aware of the depth of what you've done and you're sorry for it And how it affected them that is rather a way to go about it than just vaguely apologizing and I'm sorry and We should just end this here or cut it short So the vague apology is one move you should avoid pulling if you want peace And you want to have mature Conflict resolutions in your relationship the second thing I wrote them down. So let me just find my lists quickly and Yeah, and to also let you know that this list has been approved by Elaine She read through it. That's what I mean. Yeah, and the next one on the list number two is generalizing behaviors the you people Yeah, don't don't do that if you're having an argument with somebody you are in a relationship with the person the argument is happening Between the two of you if there are some character traits or some behaviors that you know tend to trigger certain things in you don't generalize those behaviors and tend to blame them on something else like the culture or even The agenda that you people like to do this or you're from here and that's why this is happening that will just bring a whole different discussion or whole different aspects or different, you know Matter into the whole argument and you do not want that when you're having an argument by generalizing behaviors that is a thing you people do and it's it's it's something that it's Judgmental, yes, the word I'm looking for was judgmental Based on stereotypes and prejudice and you don't want to say it's a woman thing or it's a It's a Dutch thing. I mean an interracial relationship or you know, it's a you people thing. Don't do it It's not fair to the argument and it will not move it forward in any way so don't generalize arguments don't generalize behaviors when you have an argument and Yeah, let's go to the third one Utilizing or using the infinite Where these words always and never come out of your mouth you never do this You're always doing this and that is why we're here or that is why we're having this argument It's so annoying. You're always doing that. You're never doing this Using the infinite for me. I've realized Tends to push the person to the wall to find the reason to Defend themselves and argue that no, I've not been doing this or I've not done this And why should you say I always do this? There's some moments. I've done it to admit But there's not a reason why we should be doing this or doing that it never moves the thing forward and using always It's also a negative affirmation To be even projecting on your partner and in the first place if it's something the person does often does Not always often often is a better way to put it Then yeah, it's better to choose your words wisely in this sense that you always do this You never do this it makes them defensive and Yeah prolongs the whole argument It might even increase the tempers and make things escalate even further so avoid the infinite always and never don't be To the next point number four pointing fingers either so pointing fingers when something has happened just Makes the person feel alone in an argument in a relationship in a conflict resolution situation. You don't want to Isolate one person. It's not fair to the person It's not nice to feel that whatever is happening is one person's fault or the reason the person did this is why this is happening And so to isolate the person or to blame the person is something that you want to avoid pointing fingers has never Ended in a good way for anybody in an argument if you're having an argument with somebody Yeah, it's between the two of you and you're trying to find an amicable solution together You know things happen and people react and things happen and people gets you know triggered by certain emotions And you want to come to that conclusion or find that situation which is making the person behave a certain way So saying you did this or you did that and that's where we're here It's not something you want to do if you want to have peace in Conflict resolution situation the next thing you should avoid probably doing is comparing them to another person or Yeah, somebody else Don't do that in an argument that you wish they'd behave this way or this person didn't do this or doesn't do this When this happens It is also another isolation tactic or just putting them in a situation where they just feel that you don't even value Them for who they are and you're comparing them to another person that you wish you had that I mean you can't have Perfect human or you can't have perfection in people's behaviors and you committed to Doing this with a person and you can't at every least chance Compare them to another person when you're having an argument So avoid doing that if you don't want any trouble another thing you probably should avoid doing is dismissing their feelings when arguments are happening emotions are rising and everything and For me, for example, I tend to border on the rational or logical tangent when there's an argument and feelings often You know don't come in when some of the arguments are happening and somebody might be feeling a certain way for some reason and You think that because you don't feel that way about the whole situation They can't feel that way about the situation and you think that they are making it up or they are being too emotional About a situation which is also something which is really hurtful and disrespectful and it makes people not even want to share in the first place so please avoid this missing feelings because it makes people hold back it makes people crawl back into their shells and Ultimately when people hold back and not talk a lot You realize that it's going to affect you in so many other ways It's going to dig an even deeper stretch for you guys to not be able to cross in the in the long run So please avoid dismissing your partner's feelings when you're having an argument The next thing you should not do is probably ending the conversation abruptly when it's getting too uncomfortable And you think that just you know, I don't feel like you know Continuing this you want to call time out? Please let the person know that where this has gotten to at the moment I'm struggling to continue and I would love that I would need time Or I could get time to think things through calm down a little bit and then we can continue the conversation But you should also follow up on that time out that you've called Don't let the person come back to you to ask if you're okay now and we can continue the conversation Where we left it off So please if you want to call time out, don't just end the conversation abruptly that you know what? I'm not doing this anymore and I've done don't talk to me and you're gone. No, that is also disrespectful to the person you are just intolerant and Yeah, it's it's not a good thing to do And that also leads to walking away from then that that's an action That's often follows. Don't walk away from the person. That's also very disrespectful and You don't want to do that in an argument and Next thing you should have probably avoid doing is or saying is that it's fine Never mind that you never understand it or you don't understand. So it's not even necessary for me to continue Explaining so that's very condescending and it makes them feel that they're not Intelligent enough or emotionally mature enough to understand your stance When is probably you not knowing how to explain it properly? So Avoid using statements or phrases like it's fine. Never mind. You know, let's just stop it That's also an abrupt way of ending it. So avoid using that phrase if you want peace when you're having an argument with your partner and The final thing which I think is is an emotional abuse level type thing to avoid doing is threatening to end the relationship At every chance you get you think that okay, fine, you know, this is just too difficult Let's just call it quits Yeah, you make the person feel that they are the only person committed to a certain degree In a relationship. They are doing more. They're offering more. They have more to lose and because you don't feel the same way You just think that you can easily just say, yeah, let's just stop. I'm done. I don't want to do this anymore It's just Complete bs and you want to avoid that when you're having an argument with your partner or your spouse So these are some of the things that I've learned the last one I mentioned is something that Never happens it at least in my relationship So if you do that often you are an emotionally abusive person. I'll tell you that You should avoid doing it. It's immature if there's conflict to be resolved your Last thing you should ever even want to do is threatening to end the relationship anytime or any chance you get It's not cool. It will not bring you anywhere Near resolving or having a mature conversation. So Yeah, if you found anything useful in this Do hit the like Like button and subscribe to the channel If you have any more that I may have missed that you've learned in your relationship over the course of time Put please put it in the comment section below and let's have more conversation around this I'll catch you in the next video My name is Kwame and this is me plus you is us adios for now


Thanks for staying with us. Overnown to Infrastructure As part of measures to extend development across Lagos and grow the economy of the state through a robust infrastructure portfolio, the state government has commissioned a multi-purpose car park and building at Onicon. Governor Babaji de Songhu Lu stated that the edifice will not only handle all traffic issues but also ensure an ambience needed in the area. The construction began in June 2013 during the tenure of now-Minister of Works and Housing, Babaji de Facula, then Governor of Lagos State. He is now completed and commissioned by Governor Babaji de Songhu Lu, an affirmation and attestation to his Result Ranger, completion of all inherited projects that fits into his film's agenda. Governor Songhu Lu is convinced that with the commissioning of the multi-purpose Onicon car park and facility building, traffic gridlock would become history in that area. This multi-level car park will speak to all of the traffic issues and all of the social integration that needs to happen around here. But you can see that this is well conceived, is well thought out and it will help and reduce all of the gridlocks that usually happen around this place. This edifice that has over 384 parking lots, that has seating capacity for over 1400, will ensure that not only is free flow of traffic but will also ensure that there can be ambience that is needed in this entire neighborhood. Special advisor to Songhu Lu and Works and Infrastructure, engineer Aramidi Adeyui, said the edifice would extend development across Lagos and grow the economy of the state. In a city such as Lagos, scarcity of land is an issue, hence the multi-storey car park which utilizes vertical space provides an ideal solution to overcome horizontal space constraints and regulate better traffic flow. In deciding to do this, we also realized that this facility building is significantly important because of its large size parking capacity, income generation potential and its location strategically within the heart of Onicon. Its judicious use will no doubt help absorb vehicles that would have otherwise parked on the roadside and other illegal parking spaces along the corridor. She also highlighted the scope of works for the project. Five levels of parking floors with a capacity of 384 vehicles with offices for tickets and restrooms on each floor. The sixth floor is designated as multi-purpose mixed use, consisting of a clubhouse of about four and ten square meters capacity. This provides additional recreation facilities for this area that has both Island Club and the River Tennis Club at close proximity. Engineer Adeoye Strongly Beliefs Another Revenue for Job Opportunities has just been created with the commissioning of the facility, providing an aesthetically pleasing environment and more reportedly complementing the state's efforts around tourism infrastructure within the precinct of Onicon. From Lagos, Ladikuku Oyidoku, Paplas TV, Africa. Moving on to the issues of voter apathy. Nigeria youths have been urged to register and get their permanent voter cards, PVCs, in order to participate in political affairs in the country and get the desired leadership. The score was made by some artists in the entertainment industry at an Ignite Conference 2020 to educate and curate awareness against voter apathy. Many young people have been involved in movements for change. They are taken to the streets and using online social networks and communities to connect. But that's not enough without their PVCs and involvement in politics to drive the actual change. To this end, at this conference involving Nigerian creatives, entertainers and influencers, charted ways to keep the conversations going in reshaping the polity. A renowned Nigerian entrepreneur at Tedo Petoside advised the youths clamoring for change that without their PVCs and voting, it is just a mere wish. When young people disconnect, they disconnect from everything, they surrender their birthrights and so people who should be in the departure lounge want to decide everything, including the plans for the future and all that. And so the same young people will tell you, some will ask to come and say, you know, I have no interest in all these plans, no problem. Well, guess what? That old thief will go in and smuggle projects for himself, using your own resources if you're not careful. I don't want to live anywhere else. I've lived there, it's not great. It's good for them, but it's cold and it's just not home. The food, I mean, it's just not home. So I think it's up to us, a few of us, to build this country so that the rest can come and join us. In prison in Nigeria, the space of citizens' voices and their interface with the government is threatened. All of us are politicians without joining a political party and I think it's important that we all understand our role in politics and governance. The belief that voter turnout is declining in Nigeria, especially among the youths, are the challenges we're highlighted. Whether you are for separatism, or you are for uniconstitution, or you are for restructuring, or for anything, the most important thing you have to do is to ensure that your enemy does not going to represent you. When I went out to vote for the recent local government elections, I believe maybe there were three ballot papers. Three. But when is presidential election? Oh, things are happening. Come on, let us not be distracted. The role of creative industry cannot be overemphasized in getting the young ones to focus on setting their priorities right. The thing with intellectuals is we talk a lot and we do not make effort. And then we end up allowing the riffraffs to get into power and make policies that we have to follow. We're talking about changing Nigeria. One is young people go and get your accreditation so you can vote. The thrust here is that there is need for young people to do enough in registering, collecting their PVCs, and coming out en masse during elections. Well, the take home there is that politics is everyone's business as regards to who becomes the leader in a country. And so, first thing first, register, get your PVCs ready and participate in order to get the desired change. In capacity building, the National Youth Service Corps NYSC has organized a workshop for employers to exchange ideas on oppressions and enable an efficient working environment for core members. Plus TV Africa's Ngozi Kawaijisi monitored the employer's workshop in Ligas. The 2021 edition is themed optimizing the NYSC core employer's partnership for national development in the context of new normal. The Lagos State NYSC coordinator, Edwin Megwa, who was represented by Esther Otoyo drew the attention of the participants to some shortcomings on the path of core employers which need to be tackled. Number one, delay in applying or not applying at all for the services of core members and expecting them to be posted. Two, increasing rejection of core members. Three, aiding core members to stage manage their own rejection. Four, on the utilization of core members. Five, delay in issuance of monthly clearance to deserving core members. Some employers share the challenges they encounter with core members and spoke on their expectations. The challenges we have is that usually they send someone from managing someone that studied business admin or sending someone that studied economies. And our system is actually digital too. We just do most of the digital market and not like the physical sales revenue too. So we really usually don't have where to fix the core members too. So we actually have challenges of, oh, we don't want to reject, but if you accept it, we don't want it to be redundant. They expect them, when they get there, to meet up with their KPIs. Core members at the workshop explained why their colleagues warned some employers to reject their deployment to place of primary assignments. Why some core members necessitates their rejection? Maybe the company does not have an accommodation due to distance, like from where they stay to the company. Some of them, they feel like the company won't pay enough. Maybe the company is paying them enough money. I don't think anybody will look at distance. I mean their transportation will be covered and all of that stuff. It is hoped that critical actions will be taken concerning all the issues raised at this forum. One of the highlights of the event was an award of recognition to the best employer of the year. For Plus TV Africa, Ngozika, Ohio, Chesapeake. Still on capacity building, the Nigerian Navy has retreated from its commitment to combat piracy and order maritime crimes as they collaborate with Kofi Anam International Peacekeeping Training Centre in conjunction with Denmark Government to organize a five-day training to key law enforcement agencies. The Navy says such partnership has been yielding good results, seeing in the significant drop in piracy and incidents of maritime crime in Nigeria and the Gulf of Guinea. Destiny more more has more. This training, which centres around developing maritime security culture in the Gulf of Guinea, brings a holistic approach in the management of Nigeria's maritime environment and requires a coordinated effort among the security agencies operating within the domain. Flag Officer Commander in Western Naval Command represented by Ria Admiral Habila Zakaria said most maritime crimes call for cooperatively framed responses. He therefore commanded the Denmark Government and the Training Centre. It is in the light of this that I'm excited about the potentials of this capacity building effort to draw attention to the seemingly innocuous but crucial role of cultural considerations to maritime security governance. The Commander of the Training Centre, Major General Francis of where he also spoke of the Gulf of Guinea being at a critical juncture in its socio-economic and political development of Africa, hence the training. Over the last decade, the region has faced a number of maritime security threats which include maritime piracy, armed robbery and transnational organised crime. You've heard a number of them. The ECOWAS and ECAS in a bid to stem the title of these threats join up under their only architecture and efforts to coordinate their response to the insecurity of the Gulf of Guinea. Danish Ambassador to Ghana, Tom Noring, spoke on the importance of the Gulf of Guinea to his country and the need for criminal elements to be read off of the region. The previous cost is held in other African countries which train the 164 maritime security actors at both regional and national levels. Recently, the federal government launched the Deep Blue Project as the first integrated maritime security strategy in West and Central Africa with the aim of tackling the incidences of piracy, sea robbery and other crime. For Plus TV Africa.


Welcome back everyone. Today we'll talk about optical character recognition from images using gImageReader on Windows. Please subscribe to get updates on new videos and help this channel grow. So the first thing we want to do is actually go get gImageReader for Windows. You can find gImageReader on the GitHub website, so github.com and Manizandro, gImageReader. So this is where the source code for gImageReader is located. But you don't have to know anything about compiling source or coding or anything like that. All we need to do is go to the website, go to this page here, which I'll have in the link below. Scroll down and then you can see the screenshot of it and installation. So we have a couple different options here. We have the source installation. If you want to build this package yourself, if you know about programming, you can download the source. What we're going to be using today is the Windows downloads, the download from the releases page. And then they also have different versions for different versions of Linux. There's also apparently supports and of course you can contribute if you can code. You can do a pull request to them. So let's go for Windows because we're on Windows here and go to the releases page. Then we have gImageReader and the current version is 3.3.1, which is actually relatively new from this year, July. So what we need to do is go down and if you're on Windows, there are a couple different options. But basically what you're going to want is anything with a .exe on the end. And most likely, if you're watching this, if you don't know what to download, most likely if you're on a newer computer, gImageReader 3.3.1qt5x8664 is the one that you're going to want. So if you don't know which one to choose, choose this one. x8664. Everything else basically is source code or for the Linux version. So once we download that, and I already have it downloaded here. So I'm going to double click on it to install pretty much like normal. Do you want to allow this app to make changes to your device? Yes. And then welcome to the installer, click next. And then this is the GNU license. So you might want to take a look at that. GNU licenses are interesting, but that's a different topic. The version that you want standard will install the English interface and then international will have translations. And as far as I understand, there's quite a few different languages. This app has been translated in. So if you want something other than English, install the international package. This isn't for the translations of the documents. This is not document languages. This is for the interface for the program. So I'm going to keep English. Click next. Install for everyone on this computer. Next, the location that you want to install on. Install. So now we're installing and this will install the app plus basically Tesseract as the back end. Then click finish. So now we have the app running or we have the app installed so we can go to start menu. And G image reader. So now we have G image reader app running. I'm going to minimize this so you can see it a little bit better. We have G image reader app running. Now G image reader is interesting for a few reasons. But what I'll talk about first is how we can actually get a file into here. So there's files and if you click the down arrow, you have the paste option and you have the take screenshot option. So imagine that you had two screens and you have a document on one screen and you need to OCR that document. It was a scan from a scanner, an old book or something like that. As you're going through, you need to take a screenshot or copy and paste a screenshot of that image into G image reader. And then they also have the acquire tab. And this is where you can set up for scanning documents. I don't have a scanner installed but you can scan directly to G image reader. So if you are taking some documents, physical document, trying to scan it, I would recommend this way or you can copy and paste which is also relatively easy. Now I have a Korean PDF. I'll just open that up. It's a Korean PDF of paper. Now this PDF itself doesn't need OCR because as you can see I can select the text. This is not an image and it's a correctly made PDF. This PDF however does have Korean and English. It's formatted in a little bit of a complicated way. Two column, like one column with multiple languages and then two columns. But not really too bad because the text is fairly clear. A little bit fuzzy at least to me but fairly clear. The only complicated thing are maybe these headers, the footer and then possibly the columns. So this is the document that I have and I've already created a screenshot of that document. Also you can see the screenshot is a little bit fuzzy but I think if you scale it up it would probably be a little bit better. So I have a screenshot of this document and this I cannot select the text. So this would be a good candidate for OCR because I can't select it so I want to know what this is. So I have my image or my file that I want to analyze already. Notice I don't have the entire PDF. We didn't have a way to just import the entire PDF into GImageReader. We're doing scans like one at a time. Now because my source document is English and Korean. So my source document is English and Korean. You can see it says recognize all English. We also have the OCR mode but basically right now it's set to only English. So what I need to do first is go to the settings menu. And I can click on manage languages and this is where you'll set the languages that you want to try to detect. So there's many different languages. All of these should be the same as default Tesseract OCR. I don't know if this program has actually changed the models any but I don't think so. So here I'm trying to do Korean and I don't need Korean vertical so Korean can also be written vertically. I don't need that because I know this is a modern document that's not going to have that. So if I click apply I'm going to get into a problem. So the following files could not be downloaded or removed. Fail to create directory for test data files. So it's trying to download the test data files which basically is the model of that language that you're trying to detect. So the reason for this is because I have installed this inside a kind of protected system directory and we don't have right permissions to that directory. We don't necessarily want to open up this application as an administrator that does have right to that folder. So instead of doing that I'm going to change the path for the test data. So they even have a hint here. You don't have right permissions to system folders. You can switch to user paths in the settings. Yeah, user paths in the settings. Okay, let's do that. I'm going to close the test data manager and go to preferences. And then our problem here is C program files G image reader share test data. So we don't have right access to this folder and I don't want to start G image reader as administrator just to be able to get access to this. So what I'm going to do instead instead of system wide paths we're going to click down and click user paths. So now what this will do is see users Joshua app data local test data. This is for this user we will store the language definition definitions inside this folder. So it will be let's say user specific. So if you're sharing this with let's say everyone in a group and everyone has their own login that the files that you download will only be available to this particular user. You probably want to work on system wide paths. But if everyone uses either the same account or it's just you user paths is no problem. Okay, so now we can click OK. No test racks languages are available for use recognition will not work because we've now moved the path where the test rack language files are available to click OK. Now we need to go back to manage languages. And then now we don't even have English because English was installed by default so we need to select English because I have an English document with also Korean. Okay. Okay. So then we apply. And now it's going out and you can say downloading E and G trained data KOR trained data. So it's downloaded the files. So then we click close. And then I'm just going to redetect languages just to make sure then. So now we should have the languages that we need installed. You can go back to manage languages anytime and work with any of the languages that you want. Remember, these are being downloaded from Tesseract OCR directly so that the default trainings on the language. So if you have a very specific book or font, it might not work very well. You probably have to make your own trained model, which we'll talk about how to do the training in a different video. Okay. So for now, I need to go back and I have my my document. I'm going to take another screenshot just so you guys can see. Plus it's a little bit easier. So I'm going to open the SNP tool in Windows. Okay. I want to get all of this page. So I'm going to make it a little bit smaller. That looks about right. So from the SNP tool, my mode is just a rectangular SNP. And then I'm going to do new and then select what I want. I'm going to leave that number off. And then I have the file copied. Okay. So now if I need, I can just click copy. I can minimize this now back in G image reader. It will recognize that I have something in the clipboard so I can just paste. And now I have my document inside G image reader. Okay. So now I have my pasted one document. So I need to say recognize all English in US or Korean or multilingual. So in this case, we want multilingual because we have both English and Korean going on. So I'm going to select that. And then now it's, I just clicked recognize all English plus Korean. Now it's processing. And then we have non moon. Not exactly correct. So again, I would probably retrain this model if I cared about this line. The second line, let's say mobile eight. Okay. That's okay. But it added a space. Notice I can, I can edit this test text directly as I'm working on it. And then hook. It's not mom. I think that's a bit. So I think that's a little bit off, but close still close. A saw shouldn't have a space. So these little things, it's mostly actually getting spaces and it's really, really close. There's like one, one character off. But then notice what happens here. We have Korean text and then we have an English word inside Korean text. Well, what is this doing? It's understanding the English text inside the Korean sentence as a number. Right. So that's not very good. That's not what we want. But, you know, better than nothing. So now I can just go in, I can see the, the English text so I can just type, for example, Bluetooth. So I can edit it on the fly and make sure it's okay. And then give on correct. And then MMORPG also detected as a number. And then we have, I think this was also part of the, the G kind of detected. So it wanted to try to make it Korean. It just, it just couldn't figure out anything. And then we have way. And then I'm missing the second line. So, so I would need to add that in. Okay. Now let's see what it's doing whenever it's just English by itself. So design of Bluetooth based MMORPG game in minutes. Well, that, that worked pretty well. Okay. So the Korean side, there were some things a little bit wrong with it. You kind of see, oh, it's not in correct. Okay. And it detected that little star there. And then it thought that this was also Korean. So it came up with numbers. I think that's the issue here. Yeah. Okay. And then we start getting into it. And the text, this was fairly big text, fairly clear. You notice that this image, the PDF itself is relatively fuzzy. The image is, I think even a little bit more fuzzy. Once we started getting into the, the smaller text, that's when things really got, got to be a problem. So here we have Doa and it's what it looks like. Yo, yo, yeah. I can't even barely see it. Okay. It's a bit of a problem whenever you're trying to recognize all because it's trying to figure out or it's trying to guess which language it's currently looking at, English or Korean. So that's not really what we want. And I can tell you that it looks like this detection just didn't work at all. Whenever we go to English, it also didn't really work very well. Okay. So I'd say the, the very clear big stuff worked pretty well. You know, not, not perfectly, especially whenever English was mixed with Korean, but it worked pretty well. So I'm going to go back and instead of detecting all, let's go ahead and just try to detect Korean. Okay. And it's asking me for a Korean dictionary. So let's go ahead and install that. Okay. No, no, no Korean spelling dictionary. All right. Well, whatever. So I just want to detect only Korean. Now if I recognize all as Korean, then all of this English is also going to be messed up just like it was before, but we'll probably have better luck with our main text. Instead of recognizing all, I want to select just the text that I'm looking for. So here all I've done is click and drag the text that I'm interested in. And then now it's changed to instead of recognized all, it's recognized selection. And I've already told it that this is Korean. So let me make sure that I'm getting all of that enough space around. Okay. So now I have recognized selection as Korean. And that is way better. I can already tell that's way better. I think the second character is still wrong. But so much better than it was before. Now the thing about especially PDFs that you'll process sometimes, you'll get these new line characters and one nice feature that I like about this tool is that you can remove spaces, strip line breaks on the selected text. So I just select the text and then strip line breaks. And then now we have it basically how we want it again, probably need a period in there. Notice we still have numbers detected instead of the English text. So Bluetooth MMORPG, anytime a different font was used, it inserted the numbers. So that could be a problem, but it's not used very often. So it's probably okay in this case. So now we have a pretty decent looking OCR of the Korean text. Even though the quality really isn't very good. But you know, it's not it's not old style Korean or handwritten or anything like that. It is still a computer font. So fairly clear, which is why we get a pretty good OCR. So now let's just go back here and see we have our next base. Let's select the next line, next paragraph. And then we need to switch to English. I don't think I don't think English will make too much of a difference, but yeah, English and then not perfect, right? So abstract kind of. And then with the rapid growth of recent wireless technologies with the rapid growth of recent wireless mobile computing application technology and handheld mobile devices kind of struggles, struggles a bit. Actually Korean turned out way better than the English did. I'm not sure if it's because of the font or or what it is exactly, but Korean turned out way better. And this is where the spelling, sorry dictionary comes in because now we can just right click and fix anything that was probably not handball handheld. Yeah. So abstract, right?  So I think if the font was a little bit clearer, maybe we would probably get a better OCR off of this. But that's basically how you do it. So GM and reader has a lot of really nice features. What I like about it is that you can actually see the text you're working on as you're you're working on it. Whenever we were doing something from the command line, we just trans OCR at all the documents and then whatever result we got, we have to open up both documents and then compare them. This kind of does that for us. We can select very easily the things that we're actually interested in working with and then really get that text perfect if that's what we're trying to do. Again, it might make a difference in your document. What you're trying to test or what you're trying to detect versus the model that has been trained up for that document. So I'll show you in another video how to actually make Tesseract OCR models because if you're doing something, especially something like handwriting, this probably won't work very well for you. It might work okay depending on how clear the handwriting is, but especially for older documents, it may not work as well just because Tesseract has been trained with basically older books, which are also typed. So we'll talk about training in a later video. This is how to get started with GM and reader, which I think is a really nice tool. Very basic, very simple to use. You can get up and up and running fairly quickly. There's different acquisition methods, but I think the biggest problem that I see with it right now is that I don't see a way to just import, let's say an entire document or an entire PDF. You will have to make screenshots or single page acquisitions on it. But that's kind of the point. This is really made for getting the text perfectly converted into OCR. That's why they give this editor here. One thing I didn't talk about is saving the output. So with this output file while you're working on it, you can either clear the output, don't click that unless you really want to, and then you probably want to save the output and you can save it as a text file. So this is how you work with the document. This is how you import your screenshots or the images that you're trying to detect the characters on, and then you can basically just have a bunch of pastes, OCR them, make sure the OCR is perfect, and then move to the next paste. So that's it for today. Thank you very much. Thanks for watching. If this was helpful, please like and subscribe. Also, please consider supporting us on Patreon. Your support lets us focus on making better tutorials for everyone.


Hi, my name is Safad Marzouk and I teach Hebrew Bible here at AMBS, and I'm really excited to be co-leading a trip to Egypt in January and February 2020. And think about this way. Have you ever been to Egypt before? Have you ever thought about Egypt in the Bible with an Egyptian Hebrew scholar with you on the same trip? So we would love to have you join us. My name is Drew Strait. I'm Assistant Professor of New Testament and Christian Origins here at AMBS. And I'm really excited about this trip because we are going to have the opportunity to walk in the footsteps of one of the largest diaspora Jewish communities during the Second Temple period, a community that produced more literature during the Second Temple period than any other Jewish community during that era. It is my sincere hope that you can join us on this trip.