Git Product home page Git Product logo

refactor-like-a-superhero's Introduction

Refactor Like a Superhero

Book cover

It is a book about how to refactor code efficiently and without pain. In it, we'll discuss the benefits of refactoring for development and business, explore how to search for problems in your code, and investigate possible solutions for those problems.

We will use code examples primarily in JavaScript and sometimes in TypeScript. However, the techniques we're going to discuss can be used in other high-level languages as well. So if you don't code in JS/TS but feel comfortable around them, you might find something that you can adopt to your language too.

If you like the book, give it a ⭐️ on GitHub and share the link with other developers who might want to read it!

Manuscript

The book is available in 2 languages:

Currently WIP translations:

If you are interested in translating it into other languages, please, contact me. I'll be happy to discuss details!

Ebook and Web Version

You can also read the book online or download it as a PDF or Epub:

Errata and Feedback

If you found a typo or an error, please, open an issue or a pull request in this repository. I'll also be glad to hear your ideas and code snippets that can make the examples in the book more descriptive.

You can find all previous fixes and updates in the commit history of this repository.

License & Copyright

All materials are © 2022 Alex Bespoyasov. The work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.

CC BY-NC-ND 4.0

refactor-like-a-superhero's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

refactor-like-a-superhero's Issues

Глава 12. Обработка ошибок. Проблемы выбрасывания. Сигнатура функции

Проблемы

Сигнатура функций не сообщает, что они могут выбросить ошибку — мы можем узнать об ошибках только из исходников.

Тут я сразу подумал о типе never. Вроде мы можем этим намекнуть, что в коде может быть брошена ошибка. Да, мы не понимаем, что именно это за ошибка через типы как у тебя ниже, FetchUserError или ParseUserError. Но в контексте фразы, читается так, что never чисто технически, но грубо, может намекнуть на наличие выбрасывания через сигнатуру. Может быть это стоит упомянуть как-то.

15 - Архитектура

Опечатка в примере кода. Как я понимаю, должно быть auction.participants.filter(ownsLot)

// При выводе участников, которые победили по лотам:
function defineWinners(auction) {
  return { ...auction, winners: participants.filter(ownsLot) };
}

Ниже, пропущен предлог в

Обычно его стоит добавлять места, где есть

Suggestion about structural typing

Когда читал Типы для описания домена возникли мысли о структурной типизации, потому что обычно читая примеры кода, где статическая типизация во фронте, думаешь сразу о Typescript. Из-за этого перед врезкой "Подробнее", напрашивается еще одна врезка, например, "К слову", где можно упомянуть о структурной типизации, и что из-за неё у нас не будет 100% защиты от использования "неправильного" типа по смысловому неймингу домена, как в случае с номинативной.

Были ли такие мысли и опустил это намеренно, чтобы не перегружать текст? Что думаешь?

В целом, по тексту всей книги не нашел упоминания структурной типизации. Может быть стоит где-то сделать про это вброс в контексте рефакторинга или чего-то ещё, только пока не знаю, что предложить, так как дальше книгу не читал ещё.

Chapter 12. Error handling. Add info about js global error handlers

In our project we have global error handler for all errors. It's pretty easy to handle because we have one entity for Error handling. If something goes wrong in Error handling we going to ErrorService and work only with this entity.

We throw all errors (panic errors) and they catched by listeners.

`class ErrorService {
errors: ProjectError[] = [];
constructor (window) {
this.global = window;
}

listen() {
  global.addEventListener('error', (e) => {
    
    // error object creation and pushing error to errors array. We can add additional logic (e.g. counter of errors if there is multiple same errors on page, sending data to Sentry and etc.)
  })

  global.addEventListener('unhandledRejection', (e) => {
    //same here
  })

}

}

//at root level of app
const errorService = new ErrorService(window);
errorService.listen();
`

Глава 11. Сайд эффекты. Неизменяемость по умолчанию. Терминология "изменение массива"

Привет. Возможно ерунда и не стоит капать вглубь, поэтому смотри сам, стоит ли править, но просто опишу свои мысли.

Неизменяемость по умолчанию

Действия внутри функции меняют массив items

Вот тут смотря что имеется ввиду под "изменениями массива". Для меня это добавление, удаление или замена элемента. Тут же мы получили массив ссылок на объекты, и вернули этот же массив с этими же ссылками на объекты. Ничего по сути не изменилось. Замутировали как раз объекты. Поэтому фраза Действия внутри функции меняют массив items читается как-то странно. Да, в целом, понятно из примера что имеется ввиду, но могут найтись люди, которым этот момент тоже может показаться странным. Да и то, что тут подымается тема мутации, работе по ссылке вроде как заставляет более аккуратно относиться к словам про изменения. Поэтому меня так зацепила эта фраза "меняют массив". Сам пример и цепочка рассуждений хорошая. Вот, думал, может чуть-чуть как-то слова про изменение массива вначале подобрать, чтобы было технически "правильнее" что ли, а не поверхностно-человечески, в духе "ну да, в целом обычный человек может сказать что массив поменялся, раз поменялось что-то в одном из контейнеров, что этот массив хранил":)

Просто мысли:) Возможно это всё и не нужно, поэтому через ишью, а не ПР:)

Глава 13. Интеграция модулей ошибок. Зависимости.

Источник

Говоря о зацеплении и интеграции модулей, стоит упомянуть управление зависимостями. Под зависимостями для простоты будем иметь в виду любой код, который используется нашим. Например, в функции randomInt кроме двух аргументов мы используем метод Math.random — это зависимость:

Предложение кажется не законченным, возможно стоит что-то добавить?

Website source?

First of all, thanks a lot for your book :) I was wondering if it is possible to share the website source: https://refactoring-book.vercel.app/en.
I read that it was developed with Svelte, but I need help finding the source—many thanks for considering my request.
David

Возможная ошибка примера Законы де Моргана

Когда пробую понять эти преобразования, возникает какое-то противоречие, как будто где-то ошибка.

Глава

// Вынесем 2-е вложенное условие в переменную:
const hasAdvantage = hasHeavyArmor || hasResistance;

// Заметим, что по первому закону де Моргана
// 1-е вложенное условие превратится в !hasAdvantage:
//
// !A || !B === !(A && B)
//
// A -> hasHeavyArmor
// B -> hasResistance
//
// !hasHeavyArmor || !hasResistance
//    === !(hasHeavyArmor && hasResistance)
//    === !hasAdvantage

// Тогда всё условие станет выглядеть так:
if (hasHighScore && !hasAdvantage) {
} else if (!hasHighScore && hasAdvantage) {
}

Либо я неправильно применяю, но у меня в голове так должно быть:

const hasAdvantage = hasHeavyArmor || hasResistance;
накидываем отрицание на две стороны
!hasAdvantage = !(hasHeavyArmor || hasResistance)
по закону это так
!(hasHeavyArmor || hasResistance) = !hasHeavyArmor && !hasResistance

И глядя на то, что у тебя написано !hasHeavyArmor || !hasResistance, в

// !hasHeavyArmor || !hasResistance
//    === !(hasHeavyArmor && hasResistance)
//    === !hasAdvantage

вызывает вопросы:)

Но я даже пример собрал, и if (!hasAdvantage) { и if (!hasHeavyArmor || !hasResistance) { не взаимозаменяемыми выходят.

Глава 11. Сайд эффекты. Сценарии тестирования readLogEntry

Команды и запросы

// readLogEntry.test.ts

describe("when given an ID", () => {
  it("should call the logger service with that ID", () => {
    const spy = jest.spyOn(logger, "getById");
    readLogEntry("test-entry-id");
    expect(spy).toHaveBeenCalledWith("test-entry-id");
  });
});

// createLogEntry.test.ts

describe("when given an ID", () => {
  it("should call the logger service create with that ID and default entry data", () => {
    const spy = jest.spyOn(logger, "createEntry");
    createLogEntry("test-entry-id");
    expect(spy).toHaveBeenCalledWith("test-entry-id", timeStub, "Access");
  });
});

С тестом createLogEntry ок, тестируем видимое поведение - вызов (эффект). Со сценарием вызова лога в readLogEntry тоже ок. Но что с другими сценариями? Да, чтобы не раздувать всеми тестами текст, вроде можно опустить. Но выше мы вводили читателя в тестирование возвращаемого результата. А сейчас как будто лишили его этих проверок, показав важность лишь проверки вызова. Но тут такие моменты. Если мы из readLogEntry уберем return, то тест пройдет. Мы можем написать тест на сценарий возврата null без мока логгера. Но сценарий ветки, где возврат значения после отработки логгера ведь тоже важен? Вдруг код изменят так, что вызов лога останется, но возврат потеряется. И такое без мока logger.getById не сделать? То есть, от моков мы в этом сценарии не уйдем? Или я чего-то не понял:)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.