{"id":19988528,"url":"https://github.com/bespoyasov/refactor-like-a-superhero-talk","last_synced_at":"2025-05-04T08:31:54.074Z","repository":{"id":47328893,"uuid":"450581610","full_name":"bespoyasov/refactor-like-a-superhero-talk","owner":"bespoyasov","description":"Source code and examples for “Refactor Like a Superhero” talk.","archived":false,"fork":false,"pushed_at":"2025-01-25T14:12:26.000Z","size":408,"stargazers_count":31,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-08T06:28:32.020Z","etag":null,"topics":["abstraction","architecture","cohesion","command-query-separation","coupling","declarative","domain-driven-design","functional-core","functional-pipeline","heuristics","immutability","metrics","refactoring","separation-of-concerns","statelessness","tests","twelve-factor","ubiquitous-language"],"latest_commit_sha":null,"homepage":"https://bespoyasov.me/slides/refactor-like-a-superhero/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bespoyasov.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"custom":["bespoyasov.me/support/","bespoyasov.ru/support/"]}},"created_at":"2022-01-21T17:29:48.000Z","updated_at":"2025-01-25T14:12:30.000Z","dependencies_parsed_at":"2023-01-20T08:17:17.628Z","dependency_job_id":null,"html_url":"https://github.com/bespoyasov/refactor-like-a-superhero-talk","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bespoyasov%2Frefactor-like-a-superhero-talk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bespoyasov%2Frefactor-like-a-superhero-talk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bespoyasov%2Frefactor-like-a-superhero-talk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bespoyasov%2Frefactor-like-a-superhero-talk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bespoyasov","download_url":"https://codeload.github.com/bespoyasov/refactor-like-a-superhero-talk/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252308167,"owners_count":21727136,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["abstraction","architecture","cohesion","command-query-separation","coupling","declarative","domain-driven-design","functional-core","functional-pipeline","heuristics","immutability","metrics","refactoring","separation-of-concerns","statelessness","tests","twelve-factor","ubiquitous-language"],"created_at":"2024-11-13T04:43:19.413Z","updated_at":"2025-05-04T08:31:49.051Z","avatar_url":"https://github.com/bespoyasov.png","language":"JavaScript","funding_links":["bespoyasov.me/support/","bespoyasov.ru/support/"],"categories":[],"sub_categories":[],"readme":"\u003e Other languages: [Russian](./docs/ru.md).\n\n# Refactor Like a Superhero\n\nRefactoring code takes effort and resources. It isn't always possible to find time for it. In this talk, I want to share technics I use that help me find time for refactoring and search for problems in the code.\n\nFrom this talk you will learn:\n\n- How to sell the idea of refactoring to the business;\n- How to spot problems in the code and start “feeling” them intuitively;\n- What buzzwords from the development world are most useful in refactoring code.\n\nIn this repository, I've collected code examples that I've used in the slides. You can find links to the slides and additional materials in the list below:\n\n- [Talk on YouTube](https://youtu.be/G7NcuYJ-HSM)\n- [Slides from the talk](https://bespoyasov.me/slides/refactor-like-a-superhero/)\n- [Sources and useful links](https://bespoyasov.me/slides/refactor-like-a-superhero/sources-en.html)\n- [Free online book about refactoring](https://github.com/bespoyasov/refactor-like-a-superhero)\n\n## Commit History\n\nEach commit in this repository is one step in the refactoring of an application. The entire commit history reflects the refactoring process as a whole.\n\nThe commit messages describe _what_ was done. Here I'll go into more detail about _why_ these changes were made and _what their benefits_ are.\n\n### [Add “Dirty” Source Code](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/2c277c71e9bbd1204d1055c5eee934dd0ba79b94)\n\nAdd an application with “dirty” source code. Our application is the cart of an online store. The cart contains a list of products, a field for entering a discount coupon and a button for sending the order.\n\nThis commit will be the starting point. We will clean up the code starting from here.\n\n### Define Refactoring Boundaries\n\nBefore we start refactoring, it's worth determining the scope of code and functionality that we're going to refactor.\n\nThis is necessary for two reasons:\n\n- we want to stay within the time and resource budget that we have;\n- with small changes, it's easier to manage them and keep track of what exactly broke the code.\n\nWe can refactor a function, a module, a subsystem, or even the whole system. But as a rule of thumb, it's better to move in _small steps_. Several small refactoring sessions are better than a single big one.\n\nIn our case, the refactoring scope is the checkout case.\n\n### [Cover Use Case with Tests](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/68877aa0fc67fd27f8ca2d432f77d78331478579)\n\nWhen refactoring, it's important to make sure that we haven't broken anything. To do this, before doing _anything_, we cover with tests the part of the code we're going to refactor.\n\nWhen we write tests, we examine the code. It's worth testing as many edge cases as possible and seeing how the code behaves in them. The information on how the application behaves with different inputs will be useful in the future.\n\nIn our case, the checkout use case is a slice of the entire application, so we need an end-to-end test. The type of tests isn't as important during refactoring as their _existence_. We can use unit tests too, if they cover the whole refactoring scope.\n\nWe can also test the app manually, but we'd better automate it. We should check the code's work often—after each, even the smallest, change. In this way, we'll be able to find out more quickly what exactly has broken the code. We'll get tired of testing everything manually very quickly 😃\n\n### [Apply Prettier](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/67dcaeeb429356518a626a9025c17d742bac5c1b)\n\nLet's start with a simple one: formatting. The more unified the code base is, the easier it's to navigate on it.\n\nIn this project, let's say we decided to use Prettier as a set of formatting rules. Let's apply it.\n\nSometimes Prettier breaks code when it wraps something onto a new line, for example. To make sure this doesn't happen, we check to see if the tests we wrote earlier pass.\n\n### [Remove “Dead” Code](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/803d6b54bd1528ce72efb6188cd92b524bc0e572)\n\nWe can also use linters, such as ESLint, for code hygiene.\n\nLinters will point out unreachable or unused code, as well as practices that the industry considers bad.\n\nUnused code we can remove. After each step, we'll check to see if the tests pass. In the future, I will stop emphasizing this. We'll just keep in mind that we test _every_ change.\n\n### [Rename `d` to `discount`](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/72661edb6c7c754b5553eafa504526db49381d4e)\n\nFor entities with unclear names, we should find out what they are responsible for.\n\nAs a rule, an “obscure name” is a signal of a poor understanding of the domain, or problems with code separation and abstraction layers (more on this later).\n\nToo short names and abbreviations are bad because they hide information about the domain. Sooner or later such a name will be misread because all the “knowledgeable” developers have left the project.\n\nWe can reduce the [bus factor](https://en.wikipedia.org/wiki/Bus_factor) by passing all the necessary information directly in the entity name. (As a last resort, in the documentation, but it gets outdated quickly, which can lead to multiple sources of information. It can become unclear which to trust: docs or the code.)\n\n### [Use Domain Term (`User`) as Entity Name](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/b84ba8460b6702f89b7e42735e95c18665cf4d82)\n\nTo make sure that everyone in the project understands each other, you can use ubiquitous language.\n\nThis language consists of domain terms. The domain is an area of knowledge that the project is modelling. These terms should be used everywhere in the design and development of the system.\n\nIn our case, we call the variable `User`. This way anyone involved in the project will be able to interpret the code and its purpose correctly.\n\n### [Declare `_userId` Closer to Where It's Used](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/03f879ae9e2bb24117d150e697a14978b278d277)\n\nWhen the code is “scattered” throughout the file, it becomes difficult to read and “scan” with your eyes during an eye-scanning.\n\nIn this case, we have to keep in mind everything that happened to the `_userId` variable before we started using it. There are two problems with this:\n\n- The variable is used _too far_ from where it's declared;\n- It can be changed anywhere in the code, we have to keep in mind all such changes.\n\nWe'll talk more about immutability later. With this commit we will solve the first problem by declaring the variable closer to where it is used.\n\n### [Declare `products` Closer to Where It's Used](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/1bf8fb1d980ee19fa6f448c098bdf1e87ac2f6e9)\n\nFor the same reasons as last time, we “defragment” this part of the code as well.\n\n### [Make Total Amount Calculation Declarative](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/63cb8917f653eeed98b81fd72fd9170f8c35c762)\n\nA declarative code is one that tells you _what_ it does. An imperative code, on the other hand, that tells you _how_ it does something.\n\nDeclarative code expresses the _intent_. It's easier to read because it hides unnecessary implementation details under clear function and variable names. Declarative code helps to express itself in terms of the level of abstraction at which the reader of the code is at that point in time.\n\n### [Rename `price` to Avoid Identical Names for Different Entities](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/86dea9d987af5aa0beb780efa916c6c0070b2929)\n\nDifferent entities can be called by the same name if they're in different contexts or if the interaction with them is separated in time.\n\nIn other cases, it's better to use different names for different entities. This prevents from confusion when reading and errors when executing code.\n\n(Identical names are especially dangerous if the code is mutable. Changing one variable may accidentally affect another with the same name.)\n\n### [Use `onSubmit` to Submit the Form](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/16313564ad6d9dc954230bba1a612b087b6482e0)\n\nOne of the “low-hanging fruit” in refactoring is code that can be replaced by language or environment features.\n\nWe can, for example, replace the helper that imitated the `.includes()` method with the method itself. Or, as in our case, don't handle two separate events (clicking on the button and pressing Enter in the field), but use the form submission event.\n\n### [Use `FormData` for Form Serialization](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/62d16cb554ffe9d708b40cdafef7e957f260b4b2)\n\nThe standard `FormData` saves us from writing a bunch of unnecessary code. (And probably solves the problem better than us.)\n\nIt's also a data structure that was specifically invented for the task of serializing forms. Using the right data structures can often determine what kind of algorithm we should use, and how effective the algorithm will be.\n\n### [Split Business Logic and Side Effects](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/aca4619f4e76526ab7b467a0cb366065a75d2193)\n\nThe business logic is the most important thing in an application. The simpler it's written, the easier it is to test, validate, and modify.\n\nI prefer to use pure functions and a functional approach to write it. Interacting with the outside world, however, is always associated with side effects.\n\nTo avoid mixing business logic and side effects, I use a code organization principle called “Functional Core / Imperative Shell”. (Or as Mark Seemann calls it, [Impureim Sandwich](https://blog.ploeh.dk/2020/03/02/impureim-sandwich/).)\n\nThe principle is to keep the logic pure and keep the side effects _around_ it. For example:\n\n- Side effect to get data from the outer world;\n- Functional core for transforming data;\n- Side effect to store data in the outer world.\n\nThis commit groups the code so that everything related to business logic is in the center of the function and all of the side effects are around it. We will also use this grouping later on.\n\n### [Decouple UI and Use Case](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/5fe6e1f3c459f98ff633ae04fdeb12b17c6f7ad6)\n\nWe apply the “Separation of Concerns” principle and separate the use case function from the component rendering. These are two different tasks, so they should be handled by different entities.\n\nWe'll also reduce the coupling between “checkout” and “displaying information on the screen” functionality. This will help us make the use case independent of the framework and libraries. It'll be easier for us to test it and check whether it meets our requirements.\n\n### [Clarify the Data Provider Name](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/cbb7a5033af28fd04b54bd01d2a6d9d2077c41c5)\n\nRefine the name of the user data provider by adding the missing details needed for this level of abstraction.\n\nSince we use data providers for different entities in the component, it's worth specifying which entity each one refers to. A name that is too abstract can be a problem to read: we'll have to keep the missing details in mind.\n\n### [Shorten Form Submission Handler Name](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/80ebc00bb9bfbf7e0a2cc3e8051ec037a99f0e07)\n\nWe have abstracted the checkout into a function. We can now use the name of this function as a _term_ to explain ourselves at the current level of abstraction.\n\nWe now can avoid duplication of the details contained in the name of the checkout function in the name of the form submit handler.\n\n### [Extract API](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/7475ae2e4acfbe5ee6b2bd2735dacacfd759c90e)\n\nHere we separate the “service” code from the rest.\n\nWorking with the API is a utility task that isn't directly related to the checkout process. We can call it “service” code, and the entity that performs it—a service.\n\nThe checkout function doesn't need to know the details of how the “data sending service” sends the data. The only thing it _needs_ to know is that when the `makePurchase` function is called, the data is sent.\n\nThis way we abstract the details, separate the responsibility between the entities and further—reduce coupling between the modules.\n\n### [Reduce Duplication](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/832b7d83e4b3cf66115298e4c1c2aebcefb25756)\n\nA set of identical actions that _have the same goal_ is duplication. We should pay attention to such repetitive actions and put them in functions, calling them by understandable names.\n\nNot all the duplication is pure evil. Sometimes, especially in the early stages of the project, we simply may not have enough data about the domain. Then it's better to mark the duplicates with special labels in the code and return to them later—when there's more information about the domain.\n\nIt often happens that two “seemingly identical” entities behave “almost the same”, but in fact they are completely different. It's better to observe them first and merge them later, if necessary.\n\nIn this case, we see two sets of identical operations with the same goal, which can be called by the same name. These operations can be extracted into a function.\n\n### [Extract Discount Calculation into a Function](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/822a36732d9d07a62b788c60ec4bea3d0e147bf1)\n\nAbstract the details by giving a clear name. This name is explained in terms understandable to the level of abstraction where the function is used.\n\n### [Replace Ternary Operator with `Math.min`](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/17e20dfc2c02823e9f97f4dba4737bdac1e09766)\n\nWe improve the declarativeness of the code by using `Math.min`.\n\nIt isn't important for us to know _how_ exactly we define the minimum value of the listed ones. But it's easier to read the intention from the function name than from the body of the ternary operator.\n\n### [Extract Cart Emptiness Check into a Function](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/403504bfd9e645b6d548f5b83c0e1e92784d21a2)\n\nAbstract the details by giving a clear name. This name is explained in terms understandable to the level of abstraction where the function is used.\n\n### [Extract Money Amount Check into a Function](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/2612d459bf32c8080d127e1b974f3a492ae5d19f)\n\nAbstract the details by giving a clear name. This name is explained in terms understandable to the level of abstraction where the function is used.\n\n### [Extract Order Creation into a Function](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/cbdda6146cf7738b07bc16e43fc47bf078b574d0)\n\nAn order is a domain entity. Each domain entity has a lifecycle of one or more states. By putting the creation of an order into a function, we focus on the states of the domain entity lifecycle and its further transformations.\n\nEntity states and transformations are dictated by business processes and events in them. Working with such functions, it's easier for us to relate real-world processes and code transformations.\n\nAlso, we get rid of all side effects in the order creation and make it so that the `createOrder` function now only returns a new order. Thus, we differentiate between functions that _return values_ and functions that _produce side effects_. This is called Command-Query Separation and it helps making code behave more expectedly and controllably.\n\n### [Fix “Lying” Names](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/6aa493589e8287418b7debd14eb0758db5e9960c)\n\nWhen we have enough information about the business processes and the application as a whole, we can infer incorrect variable names.\n\nSometimes it happens that the name is inaccurate or even false. In this case, the variable contains a user name, but is called `_userId`. Maybe this project once used names as identifiers, but not now.\n\nVariable names must be truthful, otherwise they will greatly confuse developers. With documentation, incorrect names can become a second “source of truth” from which developers will get the wrong information.\n\n### [Extract Total Price Calculation into a Module](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/138ccd221aca453b60b242552efd89288e4aa390)\n\nHere we decouple the functionality of “checkout” and “products” modules. (And if we don't decouple them, we at least make the coupling more noticeable with the direct imports).\n\nNow we don't need to refer to the module `Order` to calculate the total amount for a list of, for example, products from the promotional newsletter.\n\n### [Extract Cart Emptiness Check into a Module](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/e3b760c8c2dc3d2b3890667512ff86b8b562a60a)\n\nAgain we decouple the functionality of different modules: “cart” and “order”.\n\n### [Simplify Extracted Function Name](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/1e368520a9bb204132d44048f588ad915cfbc7b5)\n\nSince the information about the “shopping cart” is now available from the module context, we can remove the extra prefix from the function name.\n\n### [Extract Discount Applying into a Function](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/8e4858eddbb2bae523c5c99ed77d7dfe353cf659)\n\nWe work through the lifecycle of the “order” entity.\n\nAn order may be in different states: “created”, “prepared”, “shipped”, etc. One of these states in our case is “discount applied”. In business processes, this state can appear not only after the order has been created, but also in other cases.\n\nIf we're dealing with a _separate state_, it's better to make the transformation to it a separate function. Then we can test this state in isolation and use the composition to apply a discount to completely different orders.\n\nIn this case, all our data transformation functions are made as _queries_ from CQS.\n\nWe don't update the created `order` object to avoid unexpected or uncontrolled side effects on that object. Instead, we _transform_ data into the new state, “discounted order”, and return a new object. This prevents application data from going into an invalid state and causing errors.\n\n### [Make Discount Selection Declarative](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/9a06c8e4e9ef3cd20d629f00bfe99dda199ae983)\n\nInstead of `switch` we use a dictionary in which the key is the coupon and the value is the discount value.\n\nWhen written this way, we pass more information about the subject area in names: the dictionary name, the name of the value fallback. The extensibility of the code doesn't suffer, because a new coupon can be added by adding a new key-value pair to the dictionary.\n\n(This code is also more reliable, because it's impossible to make a mistake with a missing `break` in the dictionary.)\n\n### [Extract Repetitive Conditions in Variables](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/83087e073fb5197b84db429190b266eb10e4277c)\n\nWhen we check the status, we compare it a couple of times with `idle` and a couple of times with `loading`. It'll be easier for us to see the patterns in the conditions if we put these checks into variables and name them clearly.\n\n### [Use Early `return` in Render in Case of Error](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/77698649c7b24e6756ec86dc53899786b99bcf68)\n\nThe simplified condition helped us see that we can turn the condition inside out and handle the `else`-branch first.\n\nTo avoid keeping too many conditions in mind, we can use an early `return` and “filter out” unnecessary checked condition branches.\n\nThis is especially good for the render function: we can check all “problematic” cases, and then work with the main markup of the component.\n\n### [Use Early `return` in Render for Loading State](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/562d6251aaaad5b339da2cb8abebf2072e1954e6)\n\nThe previous early `return` helped “pull” the nested condition to the top level. Now we see that it can be applied again, this time to the processing of the loading condition.\n\n### [Use Direct Status Comparison](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/7bc70ea6f8a0cec8bd10d39e6ee9e1ff856fc56c)\n\nWhen we unraveled the condition, it became clear that the remaining check can be replaced by a single unchecked status. We check the list of possible states of this component and make sure that this is the case.\n\n### [Compactify Condition by Changing Check Order](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/576fe79895dac904055d0cbdfeb010f5ad4e66d5)\n\nIn this way we unravel the condition to the end and make it flat.\n\n### [Abstract “Service” Error Catching Code](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/3ad5cf8a5e71a65dbc1e6405f61002b9699b6faa)\n\nError handling is also a functionality whose implementation details are not important to the business logic. We can bring error catcher into “service”. This will make the checking declarative, decouple functionality, and reduce possible duplication.\n\nWe can also make sure that the use of this code is convenient within the functional pipelines. This way we make the code flat, which in turn makes it easier to understand.\n\nWe'll use the result container to make it easier to handle failures. Now we'll know exactly in what format to expect a response from \"unsafe\" functions. The concrete container implementation heavily depends on the project, its style, and requirements.\n\nI don't claim this implementation to be a “canonical” one. Instead, I encourage you to investigate your project and see if some container implementation is alrady used. Also, take a look at existing solutions like [fp/ts](https://github.com/gcanti/fp-ts) before implementing containers from scratch.\n\n### [Use Anti-Corruption Layer for API](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/37e22983809bfd6ac9e7aadc09614d791a7eee3e)\n\nWe use dependency inversion, so that the use case depends not on a particular implementation of the API service, but on the interface—the contract on the behavior of such a service.\n\nThis decouples the code even further and allows you to replace the service with another service in production, as well as with mocks during tests.\n\n### [Split UI Logic and Use Case Logic](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/adf63312b71d1df9877a6050be4952fce1d928ec)\n\nWhen processing and submitting a form, we not only need to call the use case function, but also perform some operations related to the UI. The latter are UI logic, which should not be mixed up with the former.\n\nWith this commit, we decouple the UI and the use case call by adding a command and its handler. This way we divide the responsibility between the component (responsible for the UI) and the command handler (responsible for handling the use case and providing it with all the necessary data).\n\n### [Check if Use Case is Now Easier to Test](https://github.com/bespoyasov/refactor-like-a-superhero-talk/commit/c1d1e766594695c6b9652a2b7ba277618845cde7)\n\nHere we write tests independent of React and UI. The use case function can now be tested like a regular asynchronous function. We don't need any additional technology or special infrastructure to do this.\n\nWe can also change the data sending service without using global mocks or complex testing setup.\n\n## Conclusion\n\nIn this example, I've collected examples of most of the techniques that I use in my daily work. But this is far from all that's useful in refactoring.\n\nI've gathered a complete list of all the techniques, useful books, posts, and other talks in the links below:\n\n- [Main Heuristics](https://bespoyasov.me/slides/refactor-like-a-superhero/?full#takes)\n- [Technics and How-Tos](https://bespoyasov.me/slides/refactor-like-a-superhero/?full#conclusion)\n- [Complete List of Sources](https://bespoyasov.me/slides/refactor-like-a-superhero/sources-en.html)\n\n## About Author\n\nAlex Bespoyasov, consultant at [0+X](https://0x.se). Been writing code for more than 10 years. Have a [technical blog](bespoyasov.me), teach and mentor other developers.\n\n- [0x.se](https://0x.se)\n- [bespoyasov.me](https://bespoyasov.me)\n- [Twitter](https://twitter.com/bespoyasov_)\n- [Telegram](https://t.me/bespoyasov)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbespoyasov%2Frefactor-like-a-superhero-talk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbespoyasov%2Frefactor-like-a-superhero-talk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbespoyasov%2Frefactor-like-a-superhero-talk/lists"}