# 6: Defensive Programming ###### tags: `Tag(sp22)` ## Context If you write code someone else uses, there is an implicit agreement between you. They _provide your code with something_. You _give them something back_. In both directions, there is an obligation. You might tell them: >"The constructor of my `TAHours` class should take an instance of something implementing the `Iterable` interface, and iterating ought to return `Student` objects." At a high level, that's an obligation on _their_ part. But you might also say: >"At any point at which at least one TA is free, the next student in the given iterator will be dispatched to one of those TAs before any other student is dispatched." That's an obligation on _your_ part. These sorts of *contracts* are everywhere in engineering, and software engineering is no exception. If you can't rely on your caller to conform to your preconditions, unspecified behavior might be, _in principle_ at least, on them. But if they can't rely on your code to provide what it promises, it's your fault. And if they don't know what to provide, or what to expect, that's also your fault---who trusts code that isn't clear about its job? Often, these guarantees can be enforced by the type system. The stronger the type system, the more these contracts can be checked _before_ runtime. This is why Java generics were such a big win: mismatches in promises or misconceptions could be found out early. Similarly, this is why _interfaces_ are so important. Every time you implement an interface, you are working to conform to the preconditions of some library. They say: "Give me a `Comparator` and I'll sort that list," so you'd better implement `Comparator`. But not every precondition or postcondition can be checked by the type system---at least, not in most languages, and certainly not in Java, Python, Typescript, and other languages you'll use here and elsewhere. And, worse, _good_ code should still try to detect violations of its expectations early, and notify the caller about that violation in some useful way. Just saying "Oops, LOL, I guess you gave me invalid input shrug emoji" may be _fair_, but it's not going to make you feel better when your boss calls you to ask why Google Maps is down, or an airplane crashed, or some other consequence happened. Writing code that is _safe from bugs_ requires being more professional, and thinking adversarially about: * potential ways that a caller might violate your preconditions; * potential ways that a caller might modify data unexpectedly; * potential exceptions that code _you_ call might throw, or other error conditions from that code; * and much more. Indeed, I write "thinking adversarially" because it's useful to imagine a truly malicious caller or callee _trying to break your code_ for fun or profit. Sure, most issues won't be malicious---probably they will just be honest mistakes. But I find thinking adversarially to be deeply beneficial for _defensive programming_. ## Defensive Programming Let's write a class whose job is to coordinate TA hours for a big class. There's a central signup queue (which will be provided to our class) from which we'll dispatch students to available TAs. We've already got `Student` and `TA` classes defined elsewhere, and they do what you'd expect. ```java package edu.brown.cs32.livecode.feb15; import java.util.Iterator; import java.util.Map; public class HoursDispatcher { Iterator<Student> queue; Map<TA, Integer> minutesLeft; String statusMessage; HoursDispatcher(Iterator<Student> signups, String statusMessage) { this.queue = signups; this.statusMessage = statusMessage; } void addTA(TA ta, int minutes) { minutesLeft.put(ta, minutes); } } ``` Remember: we're pretending that there's someone using our code, or someone whose code we're using, who is actively trying to break the queue or do some other kind of mischief. Even though, usually, the mischief is unintentional. Got any concerns? * The fields should be `private`? * Some of the fields should be `final`? Ok, let's make those changes, and continue iterating. ### Private and Final There are a few problems we might notice as we go. First, neither `private` nor `final` always protect you. Let's look very closely at one example: our `minutesLeft` field. We can make it `final` to prevent it from being modified---but that prevents value of the _field itself_ from changing, and doesn't stop someone from calling (e.g.) `minutesLeft.put` themselves. That is: **The reference is protected, but the object remains mutable!** We can make the field private, but then nobody can see the current state of the TA pool. It's reasonable to imagine that's bad; in real applications we often want to expose a view of some piece of state while disallowing modifications of that view. A common technique is called a _defensive copy_: we'll just make a getter method that returns a copy of the `Map`: ```java= public Map<TA, Integer> getMinutesLeft() { // Defensive copy return new HashMap<>(minutesLeft); } ``` I want to point out that, in general, this technique is very useful and often the two problems we're about to discover _aren't_ much of an issue. However, here, there are two concerns: * The `minutesLeft` field is mutable by design: we need to update the TA pool! The view provided by a defensive copy won't update, and so it really just provides the state of the pool at the time the getter was called. * Someone in class raised another concern: every defensive copy is going to consume extra memory on the heap. We can make progress on fixing both of these. Maybe we keep a canonical copy around: ```java= private Map<TA, Integer> public_view_minutesLeft; public Map<TA, Integer> getMinutesLeft() { // Canonical defensive copy if(public_view_minutesLeft == null) public_view_minutesLeft = new HashMap<>(minutesLeft); return public_view_minutesLeft; } ``` But this doesn't solve the unchanging-view problem. In fact, it makes the issue worse: the view is set once by the first call, and never changes. This is fixable by checking whether `public_view_minutesLeft` has fallen behind `minutesLeft`, but even then those who called the method before won't have their references updated. This solution is still moving in the right direction. We could certainly update the canonical copy _object_, rather than creating a new one. But then we've got another problem---any caller could mutate their canonical copy, which is the same one every other caller has! So we need to enforce immutability on the canonical copy. Next time, we'll talk about how to build this ourselves, and about the convenient way Java's standard library has built in to easily enforce immutability. ### Documenting Assumptions and Guarantees How do we tell our caller what to expect? The types say _part_ of that, but they aren't enough on their own. For everything else, we need to write documentation. Note that this is very different from "code comments". Code comments help a developer understand your code. In contrast, documentation is a kind of _specification_: you're communicating to someone what your code does, and what it needs, without them needing to understand the code itself. Documentation is thus much more important than code comments, and code comments are pretty important. I'll usually skip this in lecture, unless it's the topic of discussion---good documentation takes time. ### Validing Input and Exceptions Defensive programming isn't just about protecting your own code from someone else's bugs, it's also about protecting others from themselves, you, their other dependencies, and your own dependencies. It's always good to ask yourself, for every place your class is obtaining data, **what does a consistent state look like?** That is, what _properties_ define a good state for the class... For example, we should probably do something coherent in case our caller registers a TA with a negative amount of time available. This sounds like a job for exceptions. ### Checked vs. Unchecked Exceptions You might have noticed that some exceptions get declared for methods that use them, and other don't. Take a look at the Javadoc for [NullPointerException](https://docs.oracle.com/javase/7/docs/api/java/lang/NullPointerException.html). Since these can happen unexpectedly, it wouldn't be very ergonomic to ask programmers to write a `throws` declaration for them. Hence, these exceptions are _unchecked_: the type system won't (usually) consider them. Unchecked exceptions are those that descend from `RuntimeException` (like null pointer exceptions) or from `Error` (which is a category usually reserved for errors that are so bad that most applications _shouldn't_ try to catch and handle them, like internal JVM inconsistencies under which all bets are off). Usually you'll be communicating with your caller (and callee) via checked exceptions. A common situation is when a caller provides an argument that is invalid: the type is correct, but some other important criterion has failed. Often, the first choice is to throw the _unchecked_ [IllegalArgumentException](https://docs.oracle.com/javase/7/docs/api/java/lang/IllegalArgumentException.html). This isn't a "stop everything, the world is broken" `Error`, and your caller can try to recover from it or not. Indeed, because this is an unchecked exception, they might not even think to catch it. Thus, _it is absolutely vital_ that you declare this error in your documentation, and preferably give it a `throws` clause even if Java doesn't require it. Another option is to define our own, custom, _checked_ `Exception` class. We'd then _have_ to declare it in a `throws` clause. Custom exceptions are great if you want to pass back more context that's related to your method. Imagine what information you could give that would be helpful to your caller in: * debugging; or * sending high-quality error messages to end users. Remember: a string isn't a great way to send back structured information. A person may be able to read it, but if they want to do something more programmatic, they need to parse it. Don't make them do this! If the exception happened for complicated reasons (or maybe even if it didn't) make a custom exception that includes fields related to the problem, and document them. ### What _Else_ Should We Worry About? You tell me! ## Code Review ![](https://i.imgur.com/UeKi7QS.png) [Code Review Form](https://forms.gle/3cmRT9rTdkCy1diA7) ## Looking Ahead We'll continue this theme next time, with a more complex example introducing the _proxy pattern_ (which will be needed in Sprint 2). I'll do more livecoding, and there will be more code review. We'll also talk about documentation, and how to approach dealing with it.