melreams.com

Nerrrrd

Back to basics: Classes

a macbook sits on a desk surrounded by black and white plans for a house
Loosely related image from pexels.com to make this post look nicer in social media shares.

Let’s talk about classes! Classes in Java are super weird (okay they’re weird in any language), and I really struggled with them when I was learning Java, so don’t feel bad if classes/objects are hard for you.

When you write simple code where everything is in main and runs immediately, it’s way easier. With classes you can’t just write it and call it, you have to create an instance first. What’s even going on there?

A class in Java is just a blueprint, it doesn’t do anything until you create an object using the blueprint (there are exceptions but let’s go with that for now). That’s a big part of the weirdness, you write all this code and it just kinda sits there until you write even more code, and here’s the kicker: that code has to be somewhere else.

In a small project your probably have a Main class somewhere that has a main() method, that’s where you need to call your other class from. Why? Because Java says so, that’s why :) Or more precisely, when you run a Java project you have to tell the JVM where to start. Something, somewhere, has to have a main method no matter how you run your project. Even if you create an archive that you drop into a servlet container like Tomcat or Jetty, that servlet container has a main method somewhere that gets called when you start it up. It may be very stealthily called by a script that calls a script that starts a service, but there’s definitely a main method in there somewhere. No matter how complicated an application seems, it’s really just a much larger version of the tiny little projects you do in school. Programs get larger and larger but the basic principles always stay the same.

Back at basic principles, you create actual objects you can interact with using the class/blueprint. In Java you do that with the new keyword. new YourClassName() creates an object using the blueprint, you can assign that to a variable like any other value and then do what you like with it. Once you create an object it’s separate from any other object you create even if you use the same blueprint (class) again. Again, there are exceptions, but I’m trying to keep this simple.

It’s like building two houses from the same set of plans, they’re separate houses even if they start out the same. You can put completely different furniture in each of them, paint them different colours, make a bedroom into a home office, but whatever you do to one house doesn’t affect the other one. And you can put objects inside other objects, like a house object could contain a fridge object or a couch object or a CNC router object if you have an especially interesting garage.

You could also have an array of house objects – pretend you’re keeping track of one of those subdivisions where all the houses are the same :) Those houses could have a method like closeWindows (pretend it’s an automated house), so you could loop through your array of suspiciously similar houses and close all the windows if the weather report said it was likely to rain. But you would need to call the closeWindows method on every single house, if you close the windows of one house it doesn’t affect the others.

This gets much more complicated when you start thinking about multithreading, static methods, and static fields, but those are another blog post. For now all I want to get at is that Java needs you to spell out exactly where to start and that programs all work pretty much the same way no matter how complicated they are. Frameworks like Spring or Struts and containers like Tomcat and Jetty will hide details from you, but no matter how many other programs or libraries you use, the computer always needs to know where to start.

Be a better programmer while still having a life: part 11

an alarm clock with a weathered, rusty face sits on a rustic wooden table
Loosely related image from pexels.com to make this post look nicer in social media shares.

Don’t be a time thief. More precisely, if a decision has been made let it stay made.

This tip won’t necessarily change your personal output a whole lot, although you will have more time for your own work if you don’t waste it rehashing old decisions, but it will be fantastic for your team’s productivity. Being a better programmer isn’t just about how much you personally get done, it’s also about how much your whole team gets done. If you make your team better then congrats, you’re a better developer!

You will have to deal with decisions you don’t like as a developer. I’m not saying that’s a good time, but that’s not just life as a developer, it’s life in general. You can either accept those decisions like a grownup, or you can waste everyone’s time by fighting the same battles over and over.

Now, if something has substantially changed, like a new tool has been released or there has been an announcement that an open source library is no longer being actively developed, then it may make sense to reopen a closed discussion. But if you just don’t like the decision, you’re wasting everyone’s time. Even if you are technically right it’s generally faster to rework your codebase to recover from a decision that didn’t pan out than to have the same meeting over and over. It’s not just about the single decision, it’s about how you use your time.

It’s also about morale. It’s incredibly frustrating when you have meeting after meeting and finally decide something, only to have someone drag it all back up again a few weeks later. What was the point of all the earlier meetings if a decision that’s been made doesn’t stay made? If you want people to stop bothering to share their opinions, that’s the way to do it. Like I said last time, you have to be open to the idea that you could be wrong. You need your team’s ideas to make the best decision you can, and you can’t possibly get anyone’s real ideas when you convince them that it doesn’t matter what they say.

Arguing about things that are purely a matter of opinion is time-theft too. Curly brace on the same line as the method declaration vs the next line? tabs vs spaces? line width? No professionals bother to argue about that at work (the bar is a different story, however :) ), we pick a coding standard, set our IDEs to autoformat our code correctly and move on with our lives. Some arguments simply are not worth the time it takes to have them.

Speaking of arguments that have been had over and over and are a profound waste of everyone’s time, biology simply does not and never has explained the lack of women in computer science. We seem to drag this argument back up every few years in tech and every time it’s as foolish as it was last time. Google bro is simply the latest to waste thousands of hours of everyone’s time with ideas that have been debunked over and over. A grownup, not to mention a competent developer, would never have wasted everyone’s time with an argument that’s been hashed out dozens if not hundreds of times already. You simply can’t have someone like that on your team if you ever want to get anything done – even a competent developer, which Google bro certainly is not, couldn’t offset the collective productivity lost to rehashing well understood decisions over and over.

It’s perfectly normal to want to undo a decision you don’t like, just like it’s perfectly normal to want to stay in bed on a cold, wet morning and it’s perfectly normal to want to buy lunch and skip packing one. Wanting, however, is different from doing if you’re a grownup and you just can’t be a good developer without being a grownup. Even a lone hobbyist faces frustration and disappointment, you can either let those stop you in your tracks or you can set them down and make yourself useful.

Be a better programmer while still having a life: part 10

a metal framework tower holding up power lines is silhouetted against a dark sky that appears to be photoshopped because it is purple
Unrelated image from pexels.com to make this post look nicer in social media shares.

A little bit of self-doubt is good for you! That might sound weird but hear me out. Doubting yourself just enough to accept the fact that you don’t know everything and will be wrong sometimes is incredibly useful in software development. So many projects have died when the thing that everyone assumed would be easy (or at least doable) turned out not to be. If you can accept that you could be wrong and do a little double checking, you can save yourself so much pain.

While we’re on the subject, if you ever hear the words “it’s done, we just need to integrate it” you should be very very afraid. Not only is the thing not done, but it’s not going to be done any time soon. I admit I’m generalizing from a small sample here, but I’ve never seen the assumption that integrating a new feature will be easy turn out to be accurate.

In general, if you’ve never used that API before, don’t assume it will be easy. Read the docs really thoroughly too – just because it sounds like that API does what you need doesn’t mean it actually does. I’ve been burned by that before and you probably will be too. Same thing for libraries you haven’t used before. Just because you think a library should work a certain way doesn’t mean it actually does. In case you weren’t already worried enough, don’t forget that sometimes the docs are outdated, missing, or just plain bad, too. There’s more than one reason building a very simple proof of concept first is such a good idea.

Like I said earlier, don’t assume you understand the problem either. Talk to people until you’re sure you understand why that feature should exist, not just what it should do. Talk to your team lead, talk to other departments, ideally talk to someone who is actually going to use the thing (I know this isn’t feasible for everyone but it’s really great if you can manage it). The assumption that you’re right about what people need kills projects too. You would think that would be an obvious thing to check, but judging by the horror stories in the news about massive government projects that turn out not to do what the front line staff actually need, it’s not obvious at all.

Seriously, I can’t stress enough how dangerous assumptions are to projects. That’s how projects end up months if not years late and massively over budget if they get delivered at all. Refusing to admit you could ever be wrong kills projects too. The real problem, underneath the assumption that integrating that API will be easy to integrate, is the assumption that you’re right and don’t need to check.

In addition to killing projects, failing to question your assumptions can also lead you to make a complete fool of yourself, a la google bro. If he had questioned any of his assumptions, if he could have faced the possibility he could ever be wrong about anything at any time ever, he would be a far better engineer. As it is he clearly can’t be trusted not to make wild assumptions that will doom his projects, and if you can’t trust someone to check their own assumptions you simply can’t trust them to work as a senior engineer. One simple definition of engineering levels is that junior developers need adult supervision, intermediate developers can work on their own, and senior developers are adult supervision. If you can’t bring yourself to accept that you could ever be wrong about anything, then you can’t competently supervise anyone.

Too much self doubt is obviously completely unproductive, and you can never know everything there is to know about your project before you build it, but a little self doubt is enormously useful and tremendously underrated. In tech we seem to place so much emphasis on always being perfectly sure of yourself but not only is that an unreasonable goal, it’s not even useful. What’s useful is understanding that the most brilliant writers still need editors, and the most brilliant programmers still need input from their teams. Nobody is right absolutely all of the time, the word for people who think they are is “delusional.”

Admit you could be wrong and you’ll end up with the right answer a lot more often.

Tip of the day

Remember how great Authenticator Plus is? Recently a coworker told me about another great thing it can do – categories!

If you have 2FA set up for many accounts like I do, it gets to be a pain scrolling through that list to find the one you want. Categories to the rescue! From the settings menu go to manage categories, from there you can create new categories and put authenticators in them. Categories in Authenticator Plus work more like tags than folders, you can put one authenticator in as many categories as you want. Sorry readers, that was a lie. The interface is kind of confusing, so I thought categories worked like tags, but they are actually folders. Either way they’re still really useful. Once you have your categories set up, you can switch between them from the hamburger menu. The categories list is at the top where it’s easy to find.

Now that I have my authenticators sorted into work and personal categories, it’s so much easier to find the one I want.

Be a better programmer while still having a life: part 9

brown wooden wheel on an old cart with fallen leaves around it on the ground.
Vaguely related image from pexels.com to make this post look nicer in social media shares.

Don’t reinvent the wheel! I’ve touched on this before, but it definitely merits its own post.

A huge part of becoming a better developer is understanding when you don’t need to write new code to solve a problem. The more code you write, the more code you have to maintain, the more chances you have to screw it up, and the more time it takes to write it. So before you write new code, see if there’s a library, a plugin, a product, a design pattern, or a best practice that solves your problem. At least see if anyone wrote an article or blog post about a similar problem and learn from what they did.

To be fair, sometimes what you need really isn’t well served by an existing trustworthy product or library and you do need to write your own custom code, but that needs to be an informed choice, not a reflex.

What I think makes a product trustworthy is active development and a large userbase. The main advantages of using a library instead of writing your own code is that you don’t have to update it and that most of the bugs have been worked out already because so many people use it. By all means use a small library that isn’t maintained if it’s convenient and not a core part of your project, but for the love of god don’t depend on a framework/database/core part of your project that isn’t actively maintained and/or doesn’t have any users. That will just end in tears.

You also don’t want to import a library for every little thing, the more libraries you import the more bloated your project becomes and the more chances you have to run into a bug in one of them (and let’s not forget the left-pad debacle), but for stuff that would take more than a few hours to write, see if somebody else already wrote it.

For example, writing your own regex to validate email addresses is almost certainly a waste of time. Are you really going to write a better validator than the Apache Commons EmailValidator? No, you’re not. And do you want to have to maintain it forever even if you do write a great validator? No, you don’t. So use the library and move on with your day.

Yes, writing code is way more fun than integrating a library, but when you’re at work your job is to get results. If writing your own code gets the best result, do that, but if integrating a library gets the best result, do that instead. Of course, to understand what gets the best results, be it a library, a whole product, an API, a design pattern or whatever else, that means you have to understand what’s out there.

As a bit of an aside, that’s why the Google bro is an incompetent engineer – his ridiculous screed shows he either didn’t read or didn’t understand any of the existing research about personality differences between men and women (spoiler: there aren’t any statistically significant ones). While junior engineers get a pass on not searching for or not understanding existing libraries, senior engineers do not. If you can’t Google (see what I did there :D) existing research or existing libraries, you simply are not operating at a senior engineer level.

Sometimes it is useful to reinvent the wheel – modern wheels with inner tubes and shock absorbers make riding in a modern car a lot more comfortable than riding in the first cars with their solid wheels (Google bro’s wheel, on the other hand, is square and the axel is off center, which is just embarrassing). If you can’t do better than existing wheels, just use what’s already out there and save yourself some time.

Ironically, admitting that you aren’t the greatest developer who ever lived makes you a better developer. Accepting that actively maintained, well-used libraries are often better than what you would write on your own not only saves you a lot of time, but also makes your final product better.

Code smell: long parameter list

a set of train tracks in an overgrown field curves off into the distance
Unrelated image from pexels.com to make this post look nicer in social media shares.

Today’s code smell is long parameter lists. If you have lots and lots of parameters, something is likely going wrong.

Odds are good your method is just doing too much, which leads to confusing code that’s hard to understand and change. Another reason lots of parameters causes problems is that when you call that method, it’s very easy to accidentally get two parameters of the same type in the wrong order (not that that’s ever happened to me or anything).

How do you fix it?

Well, if you can break your method into separate methods that each do just one thing, do that. Not only does that solve the problem of a long, confusing, easy to mess up list of parameters, it also fixes the related problem of your method being confusing because it does too many things.

Another option if you can’t break up your method is to make a new object that holds all the parameters. Having named fields in the new object makes it a lot easier to keep track of which value goes where. If you already have an object that most or all of the parameters come from, it’s often simpler just to pass that along instead of pulling values out and passing those into the method you’re calling.

However, the more objects your caller and callee have in common, the more closely coupled they are. If your classes aren’t already closely coupled you’re probably fine to add another object they both use, but if they already have a lot in common then you should think about whether you really need that object. Of course, if your classes are extremely closely related they should maybe just be one class, but that’s a separate code smell.

And if breaking the big method into smaller ones means that the smaller ones absolutely always have to be called together, it’s probably better to leave it as one big method with lots of parameters. If you have to just remember what order to call the smaller methods in you’re asking for trouble, you will definitely mess that up sooner or later. A huge part of being a good programmer is accepting that it’s very very easy to mess it up and trying to avoid the most obvious pitfalls.

Like the other code smells, long parameter lists aren’t an absolute certainty you need to change your code, but I personally think they’re an especially strong sign that your design could be better. It’s just so easy to accidentally switch parameters, and even if you manage to keep them all straight it’s still a serious hassle to call a method with a huge list of parameters.

You know your codebase better than I do, though. Do what makes sense for your particular situation and don’t worry too much about my personal pet peeves :)

Code smell: feature envy

A large rock or very small island with a few green shrubs growing on it surrounded by greeny blue water and white surf.
Unrelated image from pexels.com to make this post look nicer in social media shares.

Today’s code smell is feature envy. Feature envy is when one class uses the methods of another class to excess. It’s called feature envy because classes that use methods from another class excessively look envious of that class’s features.

The problem with that, as usual, is the way your logic gets spread around between multiple classes. If you have one method that’s using another class so much that it’s hardly even separate from it, you’ll probably have to change things in both places when you need to fix a bug or add a new feature, but the compiler can’t tell you that you need to do that so you risk creating a shiny new bug by missing a spot.

Feature envy probably makes more sense with an example. Let’s say you have an address class and a customer class, and when you call customer.getMailingLabel() your customer class calls address.getStreetNumber(), address.getStreetName(), address.getCity() and so on to build a complete address string for printing a mailing label. Let’s imagine that policy changed and you’re now able to ship to rural mailboxes, so you need to add route and box numbers to your address and to use those instead of street number and street name if they’re present. If your code has feature envy, you have to change both the address object and the getMailingLabel method to support rural mailboxes. If you moved the getMailingLabel method into the address class, then you would only have to change one class when you wanted to change how you build mailing labels.

As with just about all code smells, feature envy isn’t always a sign there’s a problem. Sometimes you want to separate your data from operations on it, especially if you’re using a strategy or visitor design pattern. If, for example, you want addresses formatted differently for different reports, the formatting is probably more the job of the reporting code than the address object. In that case it would make more sense for a visitor to contain the formatting code so the address object doesn’t have to care about all the different reports.

Link of the day

Jessica Kerr has a really interesting blog post about how code reuse is often overrated. Back in college I learned all about how important code reuse was and how duplicated code was the worst, but we never (probably because we had a lot of material to cover in a limited time) talked about how code reuse can cause problems. Jessica gives a great explanation of how bad code reuse can paint you into a corner, you should check it out.

 

 

Code smell: switch statements

a frying pan full of brightly coloured vegetables cut into small pieces
Unrelated image from pexels.com to make this post look nicer in social media shares.

Today’s code smell is switch statements. Long switch statements or complicated if statements often (but not always!) mean that something has gone wrong with your design. Objected oriented languages give you a lot of tools to avoid big complicated switches, if you aren’t using one of those there needs to be a good reason for it. If you’re not using an object oriented language, on the other hand, I’m honestly not sure if switch statements are a sign of a potential issue. If any of my readers could weigh in on that, that would be really helpful.

But why are switch statements a problem? Because you’re spreading around logic that should probably be in one place, and if you add a value to one switch statement you’re likely to need to hunt down all the other ones and change them too.

If, for example, you have a switch statement that does different calculations based on the type of the object passed in, that logic for how to do the calculation probably belongs inside the object passed in to the switch. If you change that object, you’ll have to hunt down every place it’s used and make sure nothing else needs to be changed, which is obviously asking for trouble :) If you give each object a doCalculation method and replace the switch statement with a simple call to doCalculation, then all of the logic for that object stays inside the object. With all your logic in one place, you don’t have to search for every thing you need to change and risk missing a spot, and your design just makes more sense when logic for one thing isn’t smeared across multiple objects.

Polymorphism isn’t the only way to fix a switchy smell, if your method switches on a parameter that’s passed in, you may want to change it to separate named methods to more directly do the thing. If you have a setProperty(String name, String value) method, you could replace it with named methods like setType, setModel, setYear, etc. You might end up with a lot of little methods, but it’s still clearer than one setProperty method with a giant switch. If you end up with a truly excessive number of methods, that’s another code smell that points to your object doing too much.

Just because switch statements are sometimes a problem doesn’t mean they always are. Sometimes what you’re doing is so simple that an interface and a set of objects that implement it (or changes to your existing interface and objects) makes your code more complicated rather than less. And sometimes there just isn’t a better way to do it: factory methods and abstract factories rely on switches or a series of ifs to figure out which implementation to return.

What’s a code smell, anyway?

a rugged metal tower, possibly a lighthouse, seen at low tide on a rocky beach with puddles all around
Unrelated image from pexels.com to make this post look nicer in social media shares.

Design is one of my favourite parts of programming, but I constantly run into the problem of how to tell whether my design is any good.

Before we go any further, I think we should define what makes a good design is. My definition is that if you can change it in the future without cursing your past self, it must have been good design. You may have noticed that using that definition makes it difficult to figure out whether a design is any good until potentially months after the fact when you need to change it. It would be nice to know ahead of time whether your design is going to lead to a lot of swearing in the future, and that’s where I have trouble.

To be fair, if I could definitively answer the question of whether a design was good without having to try to change it, I’d be a millionaire and I’d be writing this post from my own private island :) Whether a design that seems good now is going to continue to be helpful in the future is just a hard problem and there’s no getting around that.

That said, I think code smells can help a lot there. A code smell is, in the words of Martin Fowler, a surface indication that usually corresponds to a deeper problem in the system. The term was coined by Kent Beck while he helped Martin Fowler with his book Refactoring.

This whole concept would probably make more sense with an example. An especially designy code smell is a class that does too much. Ideally a class should have one responsibility – if it’s concerned with more than one thing that’s a strong sign it should be broken up into separate classes. The specific problem with a class that does too much is that it’s likely to lead to long, messy methods that do too many things and don’t make sense because of it, and it generally makes it hard to reason about your system. The more one class does, the more state it’s likely to need to keep track of, and the more state one class keeps track of, the more chances you have to completely mess it up. You may have gotten a hint here that software design is about accepting that humans are bad at it and trying to work around that basic fact :p

The thing with a code smell is that it’s not a hard and fast rule, it’s just a hint that something could be wrong. Sometimes it can be reasonable for a class to do “too much,” it depends on the exact thing you’re trying to accomplish and the context (i.e. the rest of your application) that your class is part of. Having a good design is more about the thing you’re trying to accomplish than it is about following all the rules whether or not they make sense in your particular situation.

The great thing about code smells and design patterns and all that is that they let you take advantage of other people’s experience. Can you imagine how long it would take to get good at software design if you had to make all the mistakes yourself? I love hearing what other people have messed up so I can maybe avoid that particular problem. And from the other side, I’d love it if anything I’ve told another dev helped them avoid a problem. It’s all well and good if I solve a problem for myself, but if I can help a couple of people avoid the problem in the first place and if those people help a couple other people avoid that problem, then I’ve done much more good than if I quietly fixed my own code and moved on.

Stay tuned for more posts about code smells, there are plenty of them to get through :)