Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Рефакторинг и обратное проектирование] Задание 1 #1

Open
tamazlykar opened this issue Nov 11, 2018 · 0 comments

Comments

@tamazlykar
Copy link
Owner

tamazlykar commented Nov 11, 2018

  1. Ленивый класс и класс данных. Класс не делает ничего. В текущей реализации можно заменить на интерфейс или выделить функции и добавить в класс.

    export class Todo {
    title: string;
    isCompleted: boolean;
    created: any;
    constructor(title: string) {
    this.title = title;
    this.isCompleted = false;
    }
    }

  2. Каждый элемент имеет текущее состояние (Добавлен, Изменен или Удален). Из-за этого код содержит множество switch условий, в разных классах, что будет затруднять дальнейшее сопровождение. Если потребуется вносить изменения, то придется найти все switch условия и изменить каждый.

    private handleData(todoList: TodoMetadata[]) {
    todoList.forEach(todo => {
    switch (todo.type) {
    case ChangeType.added:
    this.addListData(todo);
    break;
    case ChangeType.modified:
    case ChangeType.removed:
    this.updateListData(todo);
    break;
    }
    })
    }

    switch (tempTodo.type) {
    case ChangeType.modified:
    this.handleModifiedChangeType(tempTodo, newTitle);
    break;
    case ChangeType.removed:
    this.handleRemovedChangeType(newTitle);
    break;
    }

Ангуляр это MVVM фреймворк, основными блоками которого являются "компоненты" и "сервисы".

  • Компонент это класс, связанный с View, который может передавать данные во View и реагировать на события View. Он является View Model из MVVM. Класс должен получать данные и отображать их. В идеале без какой либо логики. Компоненты делятся на smart и dumb, которые содержат логику (знают как получить данные, создать что-то и тд) и которые не содержат логику, а только отображают данные, соответственно.
  • Сервис это класс с Dependency Injection. Сервисы должны содержать всю бизнес логику и обратку в приложении.
  1. Компонент todo-item.component.ts, который отвечает за отображение на экране одного элемента списка, содержит больше количество логики внутри себя. Это затрудняет понимание класса и создает путаницу. Из очевидного:
  • Необходимо вынести код, который отвечает за открытие диалоговых окон и их вид.
  • Необходим вынести код, который отвечает за обработку конфликтов при параллельном изменении одних и тех-же данных в разных сессиях.
  1. Странное решение сгруппировать все типы действий, которые можно совершить над элементов списка и передать их через один "Output" (выход) в родительский класс, вместо того чтобы создать на каждое действие свой выход.

    private create() {
    this.emitAction(ActionType.add);
    }
    private update() {
    this.emitAction(ActionType.update);
    }
    public remove() {
    this.emitAction(ActionType.remove);
    }
    private emitAction(type: ActionType) {
    this.action.emit({ type, todo: this.todo });
    }

    В итоге из-за этого имеем лишний switch.
    public onItemAction(action: Action) {
    switch (action.type) {
    case ActionType.add:
    this.add(action.todo.data);
    break;
    case ActionType.remove:
    if (action.todo.type !== ChangeType.removed) {
    this.remove(action.todo);
    }
    this.removeListData(action.todo);
    break;
    case ActionType.update:
    this.update(action.todo);
    break;
    }
    }

    Если не вдаваться в код, то так же странно, что элемент списка имеет действие "создать". По идее, над элементом можно совершить 2 действия или обновить или удалить. В идеале необходимо избавиться от этого "лишнего" действия.

  2. Компонент todo-list.component.ts сам создает новые элементы списка. Если у нас будут другие компоненты, где можно создать новый элемент, то потом придется менять код создания во всех местах. Создание должно проходить в единственном месте. Необходимо его вынести в сервис.

    .then(() => this.todoService.add(new Todo(title)));
    return;
    }
    this.add(new Todo(title));

  3. Компонент todo-list.component.ts оперирует двумя интерфейсами для элементов. Где-то используется Todo, а где-то TodoMetadata. Это вводит путаницу.

    private add(todo: Todo) {
    this.todoService.add(todo);
    }
    private update(todo: TodoMetadata) {
    this.todoService.update(todo);
    }
    private remove(todo: TodoMetadata) {
    this.todoService.remove(todo);
    }

    Тем более класс TodoMetadata зависит от Todo. Можно было бы изначально использовать 2 класса. Первый, как модель хранится на сервере, второй, серверная модель + дополнительные данные, типо id и прочее, которые уже используются приложением, без лишней вложенности.
    export class Todo {
    title: string;
    isCompleted: boolean;
    created: any;
    constructor(title: string) {
    this.title = title;
    this.isCompleted = false;
    }
    }
    export interface TodoMetadata {
    id: string;
    type: ChangeType;
    data: Todo;
    }

  4. Временное поле.
    Данное поле заполняется и используется только когда существует конфликт при одновременном изменении одного и того же элемента. Данное поле должно удалиться при выделении логики и конфликтах в самостоятельный класс.

    private tempTodo: TodoMetadata;

  5. Компонент todo-item.component.ts, имеет функциональность изменения заголовка элемента. В текущей реализации мы сами проверяем целостность данных, введенных пользователем. Данный функционал можно реализовать через Reactive Form и добавить валидацию предоставляемую формами, и сделать более гибкую настройку. К тому же при изменении требований по валидации, очень легко и можно добавлять свои собственные функции для валидации ввода.

  6. Компонент todo-item.component.ts содержит много логики, которой он содержать не должен. Данный компонент должен лишь отображать список Todo. Компонент в свою очередь знает как получить данные, как обрабатывать эти данные в зависимости от типа с сервера и на основании решения добавляет или удаляет в список, создает новые списки Todo.

  7. Отсутствует обработки ошибок.
    Сервис может выбросить ошибку, при неверных данных, а так как используется класс без геттеров и сеттверов, то поле может быть не валидным или быть удалено.

    if (!id) {
    throw Error('Todo list ID should be provided!');
    }

    if (!this.currentList) {
    throw Error('Сurrent list reference is not installed');
    }

    Но, в коде который вызывает эти функции отсутствует перехватчик ошибок и код может поломаться.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant