Как фронтенд-инженеры могут сохранять энтузиазм (1)

JavaScript

Для такого рода вещей, если они часто повторяются, легко наскучить, почувствовать скуку и потерять первоначальный энтузиазм.

  • Незавершенные дела нужны, день за днем ​​чувствовать, что работа скучная и физическая;
  • Если я делаю слишком много на C-конце, я чувствую, что бизнес-логика не является сложной и скучной, а требования к дизайну жесткими и особенно раздражающими;
  • Если я делаю слишком много на B-конце, я чувствую, что пишу платформу каждый день, и у меня нет шансов играть крутые спецэффекты, когда я каждый день сталкиваюсь с безвкусными данными;
  • Я сделал слишком много технических построений, и я устал видеть то, что я сделал;
  • Исследуйте некоторые причудливые вещи, которые не имеют особого смысла для содержания работы;
  • Хочется использовать новейшие технологии, но исторические причины проекта пока вздыхают...

Естественно, я потерял свой первоначальный энтузиазм, не мог найти чувство выполненного долга и даже задавался вопросом, не подхожу ли я для фронтенд-работы, стоит ли мне менять работу или карьеру?

Как сохранить энтузиазм фронтенд-инженеров (1)

Как сохранить энтузиазм фронтенд-инженеров (2)

Избегайте повторения одних и тех же действий одним и тем же способом снова и снова

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

Оптимизация кода и улучшение качества кода

Когда вы хотите скопировать, вы должны думать о том, где инкапсулировать, где извлечь логику и где повторно использовать код.

Не дублируйте фрагмент кода, который в основном одинаков

Когда вы начнете, вы, возможно, написали такой код:

<a>首页</a>
<a>关于我们</a>
<a>合作</a>
<a>加入我们</a>

Позже выяснилось, что vue умеет v-for, react умеет map, а натив умеет циклически вставлять последний append во фрагмент.

Если это более очевидно, вы можете найти его, если это не очевидно и может быть повторно использовано, как я могу его найти? Снова,При копировании код можно использовать повторно. Например, общий сценарий применения antd Form:

<Form>
  <Item label="名称">
  {getFieldDecorator('name', {
    rules: [{
      required: true,
      message: '请输入名称',
    }],
  })(<Input />)}
  </Item>
  <Item label="描述">
  {getFieldDecorator('desc', {
    rules: [{
      required: true,
      message: '请输入描述',
    }],
  })(<Input />)}
  </Item>
  <Item label="类型">
  {getFieldDecorator('type', {
    rules: [{
      required: true,
      message: '请选择类型',
    }],
  })(<Checkbox />)}
  </Item>
</Form>

Подпрограммы те же, и структура такая же, поэтому мы поддерживаем объект конфигурации для поддержания этой формы:

const items = [
  {
    label: '名称',
    key: 'name',
    decorator: {
      rules: [{
      required: true,
      message: '请输入名称',
    }],
    },
    component: <Input />
  },
  // ...
]

Другой пример — очень длинный, если код фоновой ошибки обрабатывается во внешнем интерфейсе, очень распространенный фрагмент кода:

// before
if (type === 1) {
  console.log('add')
} else if (type === 2) {
  console.log('delete')
} else if (type === 3) {
  console.log('edit')
} else {
  console.log('get')
}

// after
const MAP = {
  1: 'add',
  2: 'delete',
  3: 'edit',
  4: 'get',
}
console.log(MAP[type])

Уменьшите дублирование кода, настроив объекты, зациклив рендеринг

Имейте менталитет «слишком ленив, чтобы кодировать»

Например, тип действия redux

const FETCH_LIST = 'FETCH_LIST'
const FETCH_LIST_SUCCESS = 'FETCH_LIST_SUCCESS'
const FETCH_LIST_FAILED = 'FETCH_LIST_FAILED'
const FETCH_USERINFO = 'FETCH_USERINFO'
const FETCH_USERINFO_SUCCESS = 'FETCH_USERINFO_SUCCESS'
const FETCH_USERINFO_ERROR = 'FETCH_USERINFO_ERROR'

Очень аккуратный и удобный код, но все они имеют общие черты: асинхронные запросы, типы запросов, успешные запросы и неудачные запросы. Каждый раз, когда мы добавляем новую, мы сначала заходим сюда, чтобы скопировать три строчки, а потом ее меняем. Поскольку это почти то же самое, мы можем написать генератор типов:

function actionGenerator(k = '') {
  const key = k.toUpperCase()
  return {
    ...(k
      ? {
        [`FETCH_${key}`]: `FETCH_${key}`,
        [`FETCH_${key}_SUCCESS`]: `FETCH_${key}_SUCCESS`,
        [`FETCH_${key}_ERROR`]: `FETCH_${key}_ERROR`,
      }
      : {}),
  };
}
// 从此以后,action_type代码行数大大减少

Другой пример — повторное присвоение объекта в функции:

// before
obj.a = 1
obj.b = 2
obj.c = 5
// after
const newVals = {
  a: 1,
  b: 2,
  c: 5
}
// 如果业务里面的obj很依赖原本引用,不能改变原对象
Object.keys(newVals).forEach(key => {
  obj[key] = newVals[key]
})
// 如果业务里面的obj不依赖原本引用,可以改变原对象
obj = { ...obj, ...newVals}
// 以后要改什么,我只要去改一行newVals就可以

Другой пример - копия страницы, мы можем вынести ее в файл для единой конфигурации, и очень удобно потом модифицировать

<header>练习不足两年半的练习生</header>
<section>我只是一个练习生</section>
<ul>
  <li>唱</li>
  <li>跳</li>
  <li>rap</li>
</ul>
<footer>联系方式:000</footer>
const CONSTANT = {
  title: '练习不足两年半的练习生',
  desc: '我只是一个练习生',
  hobbies: ['唱', '跳', 'rap'],
  tel: '000'
}

<header>{CONSTANT.title}</header>
<section>{CONSTANT.desc}</section>
<ul>
  {
    CONSTANT.hobbies.map((hobby, i) => <li key={i}>{hobby}</li>)
  }
</ul>
<footer>联系方式:{CONSTANT.tel}</footer>

Это тот, который выглядит так, как будто написано больше кода, он становится сложнее. В общем случае этого не требуется.для оперативных нужд, это решение легко справляется с копирайтингом, который можно изменить в любой момент, и его легко изменить, и вам не нужно заботиться о структуре страницы, вам не нужно идти в html, чтобы найти где копирайтинг, так и напрямую пиши файл и ставь вещи типа КОНСТАНТ. И этот объект тоже можно использовать повторно, так что не будет ситуации «подмена копии и подмена десятков страниц».

Есть и другой сценарий, возможно, мы написали много такого кода:

function sayHi(name, word) {
  console.log(`${name}: ${word}`)
}
const aSayHi = () => sayHi('a', 'hi')
const aSayGoodbye = () => sayHi('a', 'goodbye')
const aSayFuck = () => sayHi('a', 'fuck')

Конечно, это очень простой сценарий: если функцией sayHi передается много параметров, и многие из них повторяются, код будет избыточным. В это время необходимо использоватьчастичная функцияОптимизируйте это:

const aSay = (name) => sayHi('a', name)
const aSayHi = () => aSay('hi')
const aSayGoodbye = () => aSay('goodbye')
const aSayFuck = () => aSay('fuck')

Используйте тернарные и сокращенные выражения, чтобы привести несколько примеров

// before
if (type === true) {
  value = 1
} else {
  value = 2
}
//after
value = type ? 1 : 2

// before
if (type === DEL) {
  this.delateData(id)
} else {
  this.addData(id)
}
// after
this[type === DEL ? 'delateData' : 'addData'](id)
// or
;(type === DEL ? this.delateData : this.addData)(id)

// before
if (!arr) {
  arr = []
}
arr.push(item)
// after 这个属于eslint不建议的一种
;(arr || (arr = [])).push(item)

// before
if (a) {
  return C
}
// after
return a && C

Последний пример, такой как повторяющийся процесс назначения клавиш, можно упростить с помощью переменного ключа.

switch(key) {
  case 'a':
  return { a: newVal }
  case 'b':
  return { b: newVal }
  case 'c':
  return { c: newVal }
}
// after
return { [key]: newVal }

Однако, как бы привычно это ни было на тот момент, и насколько хорошо был написан код, комментарии тоже нужно писать.Основные алгоритмы, общедоступные компоненты и общедоступные функции особенно требуют комментариев.

/**
 * 创建树状组织架构
 * @param {Object} orgs
 * @param {Array} [parent=[]]
 * @param {Boolean} check 是否需要校验
 */

Резюме: Код короткий, без повторов, и вы не устанете читать его самостоятельно, извлекая логику, инкапсулируя публичные функции и незаметно улучшая качество кода. Конечным преимуществом является то, что это ускоряет эффективность разработки, а также улучшает опыт разработки и чувство достижения: «Наконец-то я не копирую каждый день. Глядя на мой простой и элегантный код, я хочу делать все больше и больше потребностей. ."

Как сделать так, чтобы операционные нужды не были скучными

Большинство компаний сосредотачиваются на потребностях бизнеса.Помимо повторяющихся потребностей их основных продуктов, другие обычно являются вспомогательными. Операционные требования обычно имеют характеристики краткосрочности, высокой частоты и сроков выполнения.

Операционное действие может иметь несколько режимов, несколько макетов отображения и несколько логик.Операции продукта будут случайным образом комбинироваться, и лучшее решение будет скорректировано в соответствии с данными.Это метод работы сценария - тест ab.

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

Начнем с примера простой страницы с информацией о пользователе:

render() {
  const { name, score } = this.state.info
  return (
    <main>
      <header>{name}</header>
      分数:<section>{score}</section>
    </main>
  )
}

Добавьте адаптационный слой

Мы стараемся не трогать основной общедоступный логический код и не говорим «просто добавьте if». Внедрение нового кода может привести к другим ошибкам (одно из распространенных заблуждений: если я добавлю строку или две, это не вызовет ошибок), есть определенный риск.

Возвращаясь к теме, если вы вдруг захотите сказать, что эта активность собирается тянуть счет другой игры, вы можете напрямую изменить запрос, а затем изменить все поля компонента.Конечно, это метод. Если вы хотите изменить его обратно вскоре после изменения, это рвота кровью? Очевидно, нам нужен адаптационный слой:

function adapter(response, info) {
  return Object.keys(newConf).reduce((res, key) => {
    res[key] = response[newConf[key]]
    return res
  }, {})
}
// before
function fetchA() {
  return request('/a')
}
fetchA.then(res => {
  this.setState({
    info: { name: res.nickname, score: res.counts }
  })
})

// after 直接修改原请求函数
function fetchA() {
  return request('/a').then(res => {
    // 把适配后的结果返回,对外使用的时候不变
    return adapter(res, {
      name: 'nickname',
      score: 'counts'
    })
  })
}

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

Расширение: Что делать, если необходимо изменить множество интерфейсов? На этом этапе нам нужно вести таблицу конфигурации, чтобы сохранить запрос и объект адаптации, вместо того, чтобы напрямую изменять предыдущий код.

const cgiMAp = {
  '/a': {
    name: 'nickname',
    score: 'counts'
  },
  // ...
}

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

function reqGenerator(cfg) {
  return Object.keys(cfg).reduce((res, key) => {
    res[key.slice(1)] = () => request(key).then(r => adapter(r, cfg[key]))
    return res
  }, {})
}
const reqs = reqGenerator(cgiMAp)
reqs.a()

Строгое соблюдение компонентности

В предыдущем примере со страницей с информацией о пользователе: что, если на странице с информацией о пользователе необходимо заполнить больше контента, что если вы не хотите отображать счет?

В этом случае вы должны сначала подтвердить со стороны продукта, какой контент должен быть в будущем, а какой изменится. Для изменяемой части мы напрямую используем контент для чтения:

class App extends Component {
  // ...
  render() {
    const { name, score } = this.state.info
    return (
      <main>
        <header>{name}</header>
        <section>{this.props.children}</section>
        分数:<section>{score}</section>
      </main>
    )
  }
}

Таким образом, пока верхний слой компонента обертывает содержимое персонализированного компонента, все в порядке.

<App>
  <section>我只是一个练习生</section>
  <ul>
    <li>唱</li>
    <li>跳</li>
    <li>rap</li>
  </ul>
</App>

Конечно,Это определенно не так простоЛюди непостоянны, теперь скажите, что заголовок никогда не изменится, развернитесь и покажите его вам: если пользователь не участвовал, то отобразите еще одну серую подсказку, если у пользователя высокий балл, добавьте угловую отметку к его заголовку, если вы списать деньги, сменить название скина

Мы по-прежнему продолжаем как можно меньше изменять основные принципы логики и сначала извлекаем компонент из заголовочной части:

const [IS_NO_JOIN, IS_PAY, IS_SCORE_HIGH] = [1, 2, 3]
const MAP = {
  [IS_NO_JOIN]: 'no-join',
  [IS_PAY]: 'has-pay',
  [IS_SCORE_HIGH]: 'high-score',
}
function Header(props) {
  const [type, setType] = useState('normal')
  useEffect(() => {
    // 用名字获取用户身份
    requestTypeByName(props.children).then(res => {
      setType(res.type)
    })
  }, [])
  return (
    <header
      className={classnames(MAP[type])}
    >
      {props.children}
    </header>
  )
}

Основная логика остается неизменной, структура и порядок рендеринга также остаются неизменными. Для более настраиваемых функций мы управляем логикой рендеринга, отображаемыми компонентами, отображаемой копией и т. д. из верхнего родительского компонента.После сборки верхнего родительского компонента он передается основному компоненту через реквизиты. Этот процесс похож на коллегу, который ранее написал основную логику рендеринга.Заголовок компонента написан, Коллега b не несет ответственности за это, но B является разработчиком этого требования, поэтому положение рендеринга должно быть скорректировано и адаптировано и внедрено в основные логические компоненты, написанные коллегой a. Конечная производительность заключается в том, что управление передается b, и b может вносить изменения.Это также менее навязчивое, менее рискованное и более масштабируемое решение.

"Удачно слил горшок", а кинул документ б, а б ушел с работы с улыбкой объяснив логику - это более изящное и стабильное решение, и его все понимают

И наоборот, если мы позволим изменить(Предполагая, что основной модуль очень сложен и не может быть запущен быстро, его можно удерживать только с помощью a):

// 加样式n行
// 加处理state逻辑、加业务逻辑而且不能影响原有逻辑,改得小心翼翼
// 改字段来适配,又几行
  render() {
    const { name, score } = this.state.info
    return (
      <main>
        <header className="xxx">{name}</header>
        <section>{this.props.children}</section>
        分数:<section>{score}</section>
      </main>
    )
  }
// after coding: mmp,b的需求为什么要我出来帮忙,还要我从头开始看需求并了解需求

После того, как смена закончилась, он в сети, и вдруг оператор сказал позже, или ххх.... В это время попросите теневую область в сердце А.

Интерфейс конфигурации операции

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

// 让配置写在一个可视化配置平台上
// const cgiMAp = {
//   '/a': {
//     name: 'nickname',
//     score: 'counts'
//   },
//   // ...
// }
function reqGenerator(cfg) {
  return Object.keys(cfg).reduce((res, key) => {
    res[key.slice(1)] = () => request(key).then(r => adapter(r, cfg[key]))
    return res
  }, {})
}
request('/config').then(res => {
  const reqs = reqGenerator(res.cgiMAp)
  reqs.a()
})

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

  • Как улучшить пользовательский опыт, если интерфейс зависает
  • Как мы можем держать страницу под контролем, например, мониторинг, точки захоронения
  • Как сделать страницу надежной и противостоять разрушительному воздействию различных машин и случайных операций пользователей

Наконец

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

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

Обратите внимание на официальный аккаунт «Другой интерфейс», изучите интерфейс с другой точки зрения, быстро растем, играйте в новейшие технологии и исследуйте различные черные технологии вместе.