{
  "@context": "https://schema.org",
  "@type": "BlogPosting",
  "@id": "https://www.vidyasource.com/blog/why-types-and-tests-are-both-essential-in-programming/",
  "url": "https://www.vidyasource.com/blog/why-types-and-tests-are-both-essential-in-programming/",
  "mainEntityOfPage": "https://www.vidyasource.com/blog/why-types-and-tests-are-both-essential-in-programming/",
  "headline": "Why Types and Tests are Both Essential in Programming",
  "description": "The arguments for types vs. tests is silly. You need both because they solve two different problems.",
  "datePublished": "2023-02-26T00:00:00.000Z",
  "author": {
    "@type": "Person",
    "name": "Neil Chaudhuri",
    "jobTitle": "President",
    "url": "https://www.linkedin.com/in/neil-chaudhuri/",
    "sameAs": "https://www.linkedin.com/in/neil-chaudhuri/"
  },
  "publisher": {
    "@id": "https://www.vidyasource.com/#organization"
  },
  "image": "https://www.vidyasource.com/img/blog/programming.jpg",
  "keywords": [
    "Programming",
    "Software Engineering",
    "TypeScript",
    "Python",
    "JavaScript",
    "Java",
    "Agile"
  ],
  "articleBody": "90% of Tech Twitter is the same arguments over and over again:\n\n* Are engineers being laid off simply not good enough? (No. Layoffs are all but random and serve, along with stock buybacks using all the cash on hand tech companies have, to impress The Street and inflate stock price.)\n\n* Does preference for remote work mean you're lazy? (No. What matters is if your customers are happy and your business is profitable, and your business should\nenable you to contribute in the easiest way possible for you and your family.)\n\n* Is HTML a programming language? (Who cares? Stop gatekeeping.)\n\n* Is Tailwind CSS a productivity boost or the spawn of Satan? (This is stupid. Mind your business. Use what you like and let others do the same.)\n\n* Should you have more unit tests or integration tests? (Shoot me.)\n\n* Must you love programming to excel? (No. Don't believe me? Then believe [Sarah Drasner](https://leaddev.com/culture-engagement-motivation/why-flow-matters-more-passion), who is smarter than both of us.)\n\nAnother common debate, and one that is more interesting, is whether you should invest in types or tests. It raises some key\nquestions about what makes each valuable, but unfortunately the debate gets lost in the haze of programming language preferences, developer experiences,\nand other tangential concerns. Still, the answer matters because it's central to improving our process so we\ncan build as efficiently and with the highest quality as possible.\n\nIt turns out you need types *and* tests because each solves completely different problems that are both important to you as a developer.\n\n## Types automate API integrity at development time\n\nThe key components of an API call—whether it's a Java method, a REST endpoint, or a Python function—are the input parameters and the output. There are infinite ways a consumer can interact with your API, but we don't want that.\n\nConsider an API call that takes first name, last name, and an amount of money parameters with no types:\n\n~~~typescript \n(firstName, lastName, amount) => {...}\n~~~\n\nEach parameter has literally infinite possible values, so our API forces consumers to be very careful. For example, it's very easy to mix up the `firstName` and `lastName` strings.\n\n>>> True story: There is a political fundraising apparatus that has switched my first and last names, so every email starts off \"Chaudhuri, we need your help!\" when they really mean \"Neil, we need your help!\" It's like my high school coach is yelling at me to donate.\n\nEven worse, they could mix up one of the string values with the number in the amount. In fact, it's very easy to put garbage of any type into each parameter, and relatively speaking almost all of it is bad. Of course\nyou can paper over the problem in a number of ways:\n\n* Intuitive parameter names like I did above\n* Logical order for parameters\n* Comments or other documentation\n* Default values or optionality for parameters (if your programming language has those features)\n\nThese things are good as a general matter, but they don't solve the problem.\n\nWe can improve the situation considerably by adding types:\n\n~~~typescript \n(firstName: string, lastName: string, amount: number) => {...}\n~~~\nNow we have ensured `firstName` and `lastName` can only be strings and `amount` can only be a number. But I know. We can still switch\n`firstName` and `lastName`. We can put a negative number in for amount. Each parameter *still* has literally infinite possible values, but we\nhave shrunk the universe of valid inputs immeasurably. [Don't let perfect be the enemy of good.](https://en.wikipedia.org/wiki/Perfect_is_the_enemy_of_good) This is progress!\n\nWe can tighten up our types further to do even better:\n\n~~~typescript \n(firstName: FirstName, lastName: LastName, amount: Currency) => {...}\n~~~\n\nHow you do this depends on the features of your programming language. Maybe it has a built-in type already for currency. Or you can define a type with\na custom implementation or as simply as a type alias. Regardless of how you get there, look how far we've come.\nNo confusing name with amount. No mixing up names. No improper values for the amount. The tigher our type constraints, the more we make life easier\nfor consumers by narrowing the field of possible values for each parameter. Yes, there are still infinite possible permutations of parameters,\nbut at least it's not \"infinite infinite.\"\n\nTypes constrain our API to limit the universe of possible inputs, and best of all, they work at development time. If API consumers make a mistake by\nsupplying a value outside the type boundary, they are going to hear about it: from the IDE, type checker, compiler, code generator. We all know the faster you find something wrong the easier\nit is to fix, and nothing works faster than types to all but guarantee the integrity of our APIs. This is the beauty of automating API integrity\nrather than wasting time as human compilers and static analyzers who inevitably get it wrong. You also get a form of documentation that helps you understand\nthe API just by looking at it.\n\nAs for outputs, constraints on return types are also valuable because as we compose functions, the return value from one call becomes the input to another.\nPrograms are essentially data pipelines of composed functions, so types guarantee the integrity of the entire call chain, which is pretty amazing.\nIf you maximize the power of types of the values going in and coming out of your API calls, and you then compose them so they fit together like Legos, you have\nmade enormous strides in maximizing the quality of your code without writing a single test.\n\nBut that isn't quite enough.\n\n## Tests *verify* your API behavior at runtime\n\nWe've used types to limit the universe of values our API consumers can apply, but how do we know we have done the\nright thing with them to satisfy our API contract and return what consumers asked for?\n\nOr more simply, does our code work? This is where tests come in.\n\nAs entire books have been written about testing and you likely already know much about it, I won't spend a lot of time on it here. What matters for\nthis discussion is that while types define APIs in development, tests act at runtime to verify your API behavior with the parameters whose types have\nalready been guaranteed. Types and tests are *complementary*. You need both.\n\n## So why the controversy?\n\nWhile it's been around for as long as static and dynamically typed languages have coexisted, in my experience the Types vs. Tests debate blew up fairly recently in the JavaScript community,\nwhere more experienced developers in particular were already comfortable acting as human compilers and static analyzers and viewed the emergence of TypeScript with skepticism. After all, types\nadd more verbosity (to varying degrees given your programming language's talent for type inference), and developers hate extra keystrokes.\nAdd to that more work like `tsconfig.json` for TypeScript or adding hints or the `typing` library in Python and you have a recipe for tension.\n\nBut at the core of the debate is one key question: \"Tests can do everything types can do, so why bother with all the ceremony?\"\n\nMy view: Nah not really.\n\nSure you can fake type safety with tests by enforcing invariants like ensuring `amount`, a `number` in the second example above, is nonnegative. That isn't *actual*\ntype safety though. It's just moving type enforcement from the interface to the implementation, which has disastrous consequences. Like all tests, \"type tests\" depend on your discipline.\nYou may not write any at all because of deadlines, or you may write bad ones that don't add value.\n\n>>> Some might say types demand discipline too. If your types are loose, you don't reap the benefits. That depends on how strongly typed the language is and how effective you are at maximizing the power of its type system. But intentionally widening types is more sabotage than lack of discipline.\n\nYou've also shifted type guarantees right, from development time to runtime, and delayed feedback as a result. This makes you slower.\n\nYou know what else makes you slower? You've chosen a manual process over automation. You've sacrificed tooling support and implicit documentation for the chance to waste time\ndoing extra work types do more reliably and cheaply. That's particularly weird since one of the primary objections to types is extra work.\n\nIn the end, substituting types with tests in your code is like substituting [Chris Hemsworth with his brother Liam](https://www.eonline.com/news/1341657/liam-hemsworth-trolls-perfect-brother-chris-hemsworth-in-marvelous-birthday-tribute)\nin the cast of your movie. You could do worse but look at how much you've lost in the process. Use types to automate API integrity and tests to verify API behavior *together* to build the most reliable and maintainable code in the shortest amount of time."
}