On Github lindseydew / coding-for-unhappy-paths
def processContent(): url = "http://content.guardianapis.com/technology" response = urllib2.urlopen(url) data = response.read() results = json.loads(data).get('response', {}).get('results', []) for r in results: body = r.get('fields', {}).get('body', '') if body: cleantext = BeautifulSoup(body).text f = open("technology.txt", 'a') f.write(cleantext.encode('utf-8')) f.write('\n') f.close()
Reading an external resource and storing in memory
Design our functions to return a computation context which can be explicitly type checked when used
sealed trait Option[A] case class Some[A](a: A) extends Option[A] case class None extends Option[A]
public class HelloWorld { public static void main(String[] args) { User user = findUser(1234) if(user != null) { //continue with the program } } public User findUser(Int i) }
object OptionExample { def main(args: Array[String]) { val user: User = findUser(1234) //doesn't compile -> this is an option } def findUser(i: Int): Option[User] }
object OptionExample { def main(args: Array[String]) { val user: Option[User] = findUser(1234) user match { case Some(u) => //continue with your program case None => //handle this } } def findUser(i: Int): Option[User] }
Reading an external resource and storing in memory
sealed trait Either[+E,+A] case class Left[+E](get: E) extends Either[E,Nothing] case class Right[+A](get: A) extends Either[Nothing,A]
def fileFromWeb(key: String, bucketName: String): Either[Error, File] = { try { Right(getFile(key, bucketName)) } catch { case NonFatal(e) => Left(Error(s"error reading the s3 cache ${e}")) } }
val file = getFileFromWeb() file match { case Right(f) => //continue our execution case Left(error) => Log.error(error) }
val file = getFileFromWeb() file match { case Right(f) => readContents(f) match { case Right(contents) => //continue case Left(error) => Log.error(error) } case Left(error) => Log.error(error) }
def method1(): Either[E, A] def method2(a: A): Either[E, B] for { a <- method1().right b <- method2(a).right } yield b
def populateCache(): Either[PermissionsReaderError, Date] = { for { obj <- getFileFromWeb(key, bucket).right data <- readContents(obj).right permissions <- parseFileConents(data.contents).right _ = storePermissionsData(permissions) } yield data.lastMod } populateCache() match { case Right(d) => Logger.info(s"successfully updated permissions cache with last modified time ${d}") case Left(error) => Logger.error("error updating permissions cache " + error) }