⚠️ Эта статья является первой подписанной статьей сообщества Nuggets, и её перепечатка без разрешения запрещена.
Автор: Брат Сяофу
Блог:bugstack.cn
Осаждайте, делитесь, растите и позвольте себе и другим что-то получить! 😄
Введение
我们不一样,就你没对象!
Да вы процессуально ориентированы!
То, что я сказал, код, который большинство кодеров душит спросом день и ночь, как бы ни приседал, не подлежит рефакторингу, только переписыванию. Зачем? Потому что затраты времени на переписывание намного экономят время, чем на рефакторинг гнилого кода. Но кто не может гарантировать, что переписанный код будет намного лучше прежнего, и им также приходится нести риск аварий переписанного кода и почти непонятного业务价值
!
Хотя код предназначен для запуска на машине, он также предназначен для просмотра людьми, и с каждой итерацией, изменением и обновлением требований разработчикам необходимо разрабатывать и запускать один и тот же код несколько раз, поэтому здесь будут задействованы.可维护
,易扩展
,好交接
специальность.
А те, кто реализует логику кода в неразумных слоях, не пишет комментарии к коду, не отправляет в соответствии со спецификациями, не форматирует, не называет и даже не пишет queryBatch, поскольку queryBitch создаст проблему невозможности рефакторинга последующего кода. Затем мы отдельно представим, как разрабатывать код, который можно рефакторить!
2. Оптимизация кода
1. Спецификация конвенции
# 提交:主要 type
feat: 增加新功能
fix: 修复bug
# 提交:特殊 type
docs: 只改动了文档相关的内容
style: 不影响代码含义的改动,例如去掉空格、改变缩进、增删分号
build: 构造工具的或者外部依赖的改动,例如webpack,npm
refactor: 代码重构时使用
revert: 执行git revert打印的message
# 提交:暂不使用type
test: 添加测试或者修改现有测试
perf: 提高性能的改动
ci: 与CI(持续集成服务)有关的改动
chore: 不修改src或者test的其余修改,例如构建过程或辅助工具的变动
# 注释:类注释配置
/**
* @description:
* @author: ${USER}
* @date: ${DATE}
*/
-
филиал: Спецификация по вытягиванию веток согласовывается заранее до разработки, например
日期_用户_用途
, 210905_xfg_updateRuleLogic -
Отправить:
作者,type: desc
как:小傅哥,fix:更新规则逻辑问题
См. спецификацию сообщения фиксации. -
Примечания: Включение аннотаций классов, аннотаций методов, аннотаций свойств и информации заголовков аннотаций классов можно установить в IDEA.
Editor -> File and Code Templates -> File Header
Рекомендуется скачать и установить плагин IDEA P3C.Alibaba Java Coding Guidelines
, единый стандартизированный метод кодирования.
2. Стандарт интерфейса
При написании интерфейса RPC возвращаемый результат должен содержать явноеCode码
иInfo描述
, иначе пользователю сложно узнать, успешен ли вызов этого интерфейса или это исключение, и что такое исключение.
Определить результат
public class Result implements java.io.Serializable {
private static final long serialVersionUID = 752386055478765987L;
/** 返回结果码 */
private String code;
/** 返回结果信息 */
private String info;
public Result() {
}
public Result(String code, String info) {
this.code = code;
this.info = info;
}
public static Result buildSuccessResult() {
Result result = new Result();
result.setCode(Constants.ResponseCode.SUCCESS.getCode());
result.setInfo(Constants.ResponseCode.SUCCESS.getInfo());
return result;
}
// ...get/set
}
Обёртка возвращаемого результата: наследование
public class RuleResult extends Result {
private String ruleId;
private String ruleDesc;
public RuleResult(String code, String info) {
super(code, info);
}
// ...get/set
}
// 使用
public RuleResult execRule(DecisionMatter request) {
return new RuleResult(Constants.ResponseCode.SUCCESS.getCode(), Constants.ResponseCode.SUCCESS.getInfo());
}
Упаковка результатов возврата: дженерики
public class ResultData<T> implements Serializable {
private Result result;
private T data;
public ResultData(Result result, T data) {
this.result = result;
this.data = data;
}
// ...get/set
}
// 使用
public ResultData<Rule> execRule(DecisionMatter request) {
return new ResultData<Rule>(Result.buildSuccessResult(), new Rule());
}
- Оба интерфейса возвращают результат определений упаковки, спецификации могут вернуть результаты. Таким образом, пакет, потребитель может быть определен единым образом
Code码
и обращаться с ним соответственно.
3. Дизайн библиотечного стола
три парадигмы: Это стандартизированное содержимое базы данных. Так называемая база данных с тремя парадигмами представляет собой набор спецификаций, которым следует следовать при разработке таблиц базы данных. избыточность полей и запрос данных, вставка и другие операции.
База данных имеет не только три нормальные формы (1NF/2NF/3NF), но также BCNF, 4NF, 5NF..., но в реальной структуре базы данных достаточно следовать первым трем нормальным формам. Дальнейшее опускание приведет к тому, что проектируемая база данных будет иметь слишком много ненужных ограничений.
0NF
- Нулевая нормальная форма означает, что никакая нормальная форма не используется, а данные хранятся с большим количеством избыточных полей таблицы, и такую структуру таблицы очень сложно поддерживать.
1NF
- Первая парадигма улучшена в отношении избыточного поля с нулевой величиной, умаляет повторяющееся поле и предназначена для избыточных данных, менее удобных для хранения и чтения структуры таблицы.
- При этом в первой нормальной форме также указано, что все поля в таблице должны быть атомарными и неразделимыми, например: нельзя хранить название отдела и обязанности таблицы сотрудников компании в одном поле. Необходимо убедиться, что каждый столбец остается атомарным
2NF
- После выполнения 1NF столбцы в таблице должны полагаться на первичный ключ, чтобы гарантировать, что каждый столбец связан со столбцом первичного ключа и не может быть косвенно связан, то есть таблица может описывать только одну вещь. Вы должны убедиться, что каждый столбец в таблице связан с первичным ключом.
3NF
- Не может быть никаких зависимостей, номер студента, ФИО, к отделению, отделение к общежитию, нужно следить за тем, чтобы каждый столбец был напрямую связан со столбцом первичного ключа, а не косвенно.
анти-три парадигмы
Три парадигмы являются ограничениями правил для проектирования структуры таблиц базы данных, но в фактической разработке допускаются локальные обходные пути:
- Иногда для того, чтобы облегчить запрос, например, в форме заказа в моментальном снимке пользователя была избыточная информация, такая как некоторая одноразовая информация о настройке пользователя.
- Данные списка из одного столбца суммируются в значение количества в итоговой таблице, что позволяет избежать операции суммирования списка, когда это удобно для запроса.
- Некоторые поля могут быть избыточными при разработке таблицы, чтобы избежать громоздкой проблемы с таблицей из-за меняющегося развития бизнеса и плохого рассмотрения.
4. Алгоритмическая логика
Обычно при разработке логики нашей реальной бизнес-функции, чтобы соответствовать некоторым сценариям с высоким параллелизмом, невозможно заблокировать и вычесть инвентарь в таблице базы данных, и невозможно напрямую зациклить большое количество операций обучения ротации, обычно мы нужно подумать 🤔 Как сделать в таком сценарии Децентрализацию и уменьшить временную сложность.
Секилл: Децентрализация
-
задний план: это план реализации всплеска активности продукта. Первоначальный план заключается в блокировке на основе идентификатора активности. Этот идентификатор блокируется во время всплеска, и пользователь освобождает его после покупки. Однако, когда набралось большое количество пользователей, произошел всплеск распространения
独占锁
Обработка бизнес-логики после возникновения аномалии, сброс блокировки. Потому что все пользователи больше не могут получить блокировку, что также привело к товару, но не может выдавать заказы. - оптимизация: Оптимизируйте статус эксклюзивного соревнования для сегментации статики и используйте идентификатор действия + инвентарный номер в качестве динамического идентификатора блокировки. Если текущему пользователю seckill не удастся заблокировать, последующие пользователи смогут продолжить выполнение seckill без каких-либо последствий. Неудачный замок будет иметь работников, чтобы компенсировать и восстановить, поэтому в конечном итоге он избежит перепроданности и непроданности.
Алгоритмы: Обратный учебник
@Test
public void test_idx_hashMap() {
Map<String, String> map = new HashMap<>(64);
map.put("alderney", "未实现服务");
map.put("luminance", "未实现服务");
map.put("chorology", "未实现服务");
map.put("carline", "未实现服务");
map.put("fluorosis", "未实现服务");
map.put("angora", "未实现服务");
map.put("insititious", "未实现服务");
map.put("insincere", "已实现服务");
long startTime = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
map.get("insincere");
}
System.out.println("耗时(initialCapacity):" + (System.currentTimeMillis() - startTime));
}
- задний план: временная сложность сбора данных HashMap составляет O(1) -> O(logn) -> O(n), но послеспециальныйОперация, на этот раз сложности, потянула O(n)
-
действовать: это определение
HashMap
Сохраните ключ бизнес-реализации и вызовите сервисную функцию с помощью ключа. но здесьkey
,Толькоinsincere
Полезно, все остальное - нереализованный сервис. Так ты видишь, что не так?- Этот код не проблема с первого взгляда, чтобы понять этот код под Arsenic!Его цель только одна: собрать все ключи в связанный список и поместить их в HashMap, а полезные ключи поместить в конец связанного списка, чтобы увеличить время получения!
- Во-первых,
new HashMap<>(64);
Почему 64 длины инициализируются по умолчанию? Поскольку длина по умолчанию равна 8, при вставке элемента, когда длина связанного списка равна 8, будет оцениваться расширение и дерево связанного списка.В это время исходный ключ будет хеширован, а все ключи не может быть сформирован в связанный список высокой временной сложности. - Во-вторых, все
key
выбираются сознательно, потому что ониHashMap
При вычислении индекса значение индекса равно 0, idx =(size - 1) & (key.hashCode() ^ (key.hashCode() >>> 16))
, так что всеkey
Хэш-коллизии должны быть в одном и том же месте.И словоinsincere
означает;不诚恳的、不真诚的
! - Наконец, первые 7 клавиш фактически бесполезны.
key
, не действует, обслуживается только последний ключ. Затем, конечно, в HashMap можно построить много таких трудоемких списков, связанных с коллизиями, чтобы удовлетворить потребности.0.75
коэффициент загрузки, не позволяйте HashMap расширяться.
На самом деле многие алгоритмы, в том числе: хеширование, инверсия, загрузка и т. д., могут использоваться во многих практических бизнес-сценариях, включая фильтрацию толпы, логику лотереи, маршрутизацию данных и т. д. Использование этих функций может уменьшить временную сложность, улучшить производительность системы и уменьшить частый отклик интерфейса.
5. Разделение обязанностей
Чтобы сделать логическую реализацию программы более расширяемой, нам обычно нужно использоватьШаблоны проектированияДля обработки структуры реализации кода каждой сцены. Использование шаблонов проектирования при разработке кода в основном отражается в определении интерфейсов, упаковке абстрактных классов и реализации унаследованных классов. Таким образом, разработка каждой функциональной области изолирована, чтобы гарантировать более гибкое добавление каждого расширения требований, и код не станет более хаотичным из-за итерации требований.
кейс
public interface IRuleExec {
void doRuleExec(String req);
}
public class RuleConfig {
protected Map<String, String> configGroup = new ConcurrentHashMap<>();
static {
// ...
}
}
public class RuleDataSupport extends RuleConfig{
protected String queryRuleConfig(String ruleId){
return "xxx";
}
}
public abstract class AbstractRuleBase extends RuleDataSupport implements IRuleExec{
@Override
public void doRuleExec(String req) {
// 1. 查询配置
String ruleConfig = super.queryRuleConfig("10001");
// 2. 校验信息
checkRuleConfig(ruleConfig);
// 3. 执行规则{含业务逻辑,交给业务自己处理}
this.doLogic(configGroup.get(ruleConfig));
}
/**
* 执行规则{含业务逻辑,交给业务自己处理}
*/
protected abstract void doLogic(String req);
private void checkRuleConfig(String ruleConfig) {
// ... 校验配置
}
}
public class RuleExec extends AbstractRuleBase {
@Override
protected void doLogic(String req) {
// 封装自身业务逻辑
}
}
Диаграмма классов
- Это должно определить структуру шаблона трафарета, используемую для интерфейса, наследования абстрактного класса, можно увидеть одновременно.
AbstractRuleBase
В абстрактном классе он отвечает за завершение определения всего логического вызова, и этот абстрактный класс отдельно изолирует некоторую общую конфигурацию и использование данных и помещает общие простые методы в свою собственную реализацию, и, наконец, определение и вызов абстрактного методы и бизнес-классRuleExec
При необходимости вы можете реализовать свои собственные логические функции.
6. Сложная логика
Случались ли с вашим кодом онлайн-аварии? Почему произошла авария, вопрос в том, сколько из десяти птиц на дереве выстрелили и сколько осталось? Например: бесшумна ли пушка, глуха ли птица, есть ли беременная, есть ли птица привязанная к дереву, есть ли птица на соседнем дереве, боится ли птица выстрелов, есть ли инвалид? птица, есть ли птица, которая стреляет? У людей глаза цветут или нет,...
Фактически, ваши онлайн-аварии в основном вращаются вокруг: подключения к базе данных и медленных запросов, загрузки и простоя сервера, ненормальной логики, идемпотентности интерфейса, защиты от дублирования данных, скорости потребления MQ, частых ответов RPC, неправильного использования инструментов и т. д.
Вот пример: пользователи платят больше баллов, что приводит к пачкам жалоб клиентов.
- задний план: Предыстория функции этого продукта, возможно, была связана с развитием значительной части исследований и разработок.Проще говоря, это должно удовлетворить потребности пользователей в использовании очков для лотереи. В левой части приведенного выше рисунка показан процесс первоначального проектирования исследований и разработок. Пользовательские баллы вычитаются через интерфейс RPC. После успешного вычета будет проведена лотерея. Однако из-за нестабильной службы RPC в тот день фактический вызов RPC завершился успешно, но тайм-аут не удался. uuid для вызова интерфейса RPC каждый раз генерируется автоматически и не имеет идемпотентности вызова. Поэтому возникает явление переплаты пользовательских баллов.
- иметь дело с: Измените процесс лотереи после аварии, сначала сгенерируйте лотерейный билет, который нужно разыграть, и вызовите интерфейс RPC из идентификатора лотерейного билета, чтобы обеспечить идемпотентность интерфейса. При сбое интерфейса RPC проводится лотерея посредством компенсации запланированной задачей. После того, как процесс был исправлен, выяснилось, что компенсационная задача выполнялась от 1 до 3 раз в неделю, что доказывало, что у интерфейса RPC действительно была проблема с доступностью, а также показывало, что проблема с процессом была давно, но Жалоб от пользователей было мало, поэтому обратной связи не было.
7. Агрегация доменов
Он недостаточно абстрактен, не может быть жестко закодирован и не может быть легко расширен. Всегда ли это ваш код? Каждый раз, когда это похоже на распродажу с молотка, он полностью жестко закодирован и связан.
Почему, потому что многие коды, написанные R&D, не имеют характеристик доменной агрегации.Конечно, это не обязательно должно быть в структуре DDD.Даже в расслоении MVC можно написать много хорошей логики агрегации. , чтобы отделить реализацию функции от бизнес-вызова.
- Design Design Domain Domine Domain Domain, создайте модель домена борьбой, разумное разделение участков логических и физических границ, установить целевые зоны и матрицу обслуживания и диаграмму архитектуры обслуживания, в соответствии с определением структуры кода модели DDD слоистые идеи архитектуры , бизнес-модели и обеспечить код модели согласованности. Благодаря вышеуказанным дизайнерским идеям, методам и процессам для руководства команды для завершения проектирования и разработки микросервисов в соответствии с DDD Design.
- Отклоняйте грязные шарики маленькие мономеры, отклоните загрязняющие функции и услуги, а также отклоните функцию OnePlus, планируя на один месяц
- Создавайте высокодоступные прикладные сервисы, которые легко справятся с высокоскоростной итерацией Интернета.
- Материализованные, собранные и организованные услуги для повышения эффективности работы человека
8. Уровни обслуживания
Если вы хотите, чтобы ваш системный инженерный код поддерживал абсолютное большинство бизнес-потребностей и выделял функции, которые можно использовать, вам в основном необходимо извлекать технические компоненты, функциональные области и бизнес-логику при разработке и реализации кода. не записывайте часто меняющуюся бизнес-логику в каждую функциональную область, а делайте функциональную область более независимой, которая может быть связана, организована и объединена бизнес-уровнем для достижения различных бизнес-требований. Таким образом, ваша функциональная зона может быть постепенно определена, и ее будет легче расширять с каждым требованием.
- Это упрощенная иерархическая логическая структура с агрегированными доменами, компонентами SDK, промежуточным программным обеспечением и оркестровкой кода, которая предоставляет некоторые общие и сжатые функции управления службами. Благодаря такому расслоению и внедрению каждого уровня можно более гибко выполнять требования.
9. Параллельная оптимизация
При разработке систем в распределенных сценариях следует максимально использовать распределенные возможности, а некоторых централизованных, распределенных вещей и блокировки базы данных следует максимально избегать при разработке программ, поскольку использование этих методов может быть использовано в некоторых крайних случаях нагрузка на систему превышает нормативную, что приводит к аварии.
- Поэтому обычно более необходимо децентрализовать обработку, использовать MQ для устранения пиков, уменьшения связанности и обеспечения согласованности данных.Также необходимо рассмотреть возможность использования Redis для уменьшения большого количества блокировок в базе данных.
- Разумное использование MQ, RPC, распределенных задач, Redis, подтаблиц подбазы данных и распределенных транзакций Только таким образом вы можете заставить свой программный код поддерживать больший объем бизнеса.
10. Возможности исходного кода
Вы когда-нибудь узнавали о структуре данных HashMap с адресацией молнии, знали о функциях хеширования и возмущения, знали, как динамически переключать источники данных с помощью Spring, как реализован и используется АОП и как MyBatis объединяется со Spring для управления объектами Bean? Да, подождите. . Кажется, что все это эссе-интервью, но в реальной разработке можно решить многие проблемы.
@Around("aopPoint() && @annotation(dbRouter)")
public Object doRouter(ProceedingJoinPoint jp, DBRouter dbRouter) throws Throwable {
String dbKey = dbRouter.key();
if (StringUtils.isBlank(dbKey)) throw new RuntimeException("annotation DBRouter key is null!");
// 计算路由
String dbKeyAttr = getAttrValue(dbKey, jp.getArgs());
int size = dbRouterConfig.getDbCount() * dbRouterConfig.getTbCount();
// 扰动函数
int idx = (size - 1) & (dbKeyAttr.hashCode() ^ (dbKeyAttr.hashCode() >>> 16));
// 库表索引
int dbIdx = idx / dbRouterConfig.getTbCount() + 1;
int tbIdx = idx - dbRouterConfig.getTbCount() * (dbIdx - 1);
// 设置到 ThreadLocal
DBContextHolder.setDBKey(String.format("%02d", dbIdx));
DBContextHolder.setTBKey(String.format("%02d", tbIdx));
logger.info("数据库路由 method:{} dbIdx:{} tbIdx:{}", getMethod(jp).getName(), dbIdx, tbIdx);
// 返回结果
try {
return jp.proceed();
} finally {
DBContextHolder.clearDBKey();
DBContextHolder.clearTBKey();
}
}
- Это структура данных массива хеш-контейнеров HashMap + связанный список + красно-черное дерево через функцию возмущения.
(size - 1) & (key.hashCode() ^ (key.hashCode() >>> 16));
Решите проблему серьезного столкновения данных. - Но на самом деле такие алгоритмы хеширования и методы адресации могут быть применены к проектированию и реализации маршрутизации базы данных, как и метод весь массив + связанный список, по сути метод библиотека + таблица тоже аналогичен.
- Код реализации базовой логики упрощения маршрутизации базы данных аналогичен приведенному выше: во-первых, мы извлекаем количество библиотечных табличных продуктов и используем их той же длины, что и HashMap.
- Когда idx вычисляет позицию индекса общей длины, ему также необходимо преобразовать эту позицию в библиотечную таблицу, чтобы увидеть, в какую таблицу попадает индекс общей длины.
- Наконец, вычисленная информация об индексе сохраняется в ThreadLocal для передачи информации об индексе, которую можно извлечь во время вызова метода.
3. Резюме
- Справедливости ради, вам почти невозможно очистить кучу гнилого кода путем рефакторинга. Чтобы быть более конкретным, вам необходимо изменить структуру кода, интеграцию объектов атрибутов и инкапсуляцию логики вызовов, но любой шаг операции может оказать рискованное влияние на исходное определение и вызов интерфейса, а также на существующий внешний вызов вашего интерфейса. также должен быть По мере обновления со своими изменениями вы можете подумать об обертывании слоя, но этот слой обертывания по-прежнему требует больших временных затрат и почти бесполезной адаптации.
- Таким образом, в реальной разработке, если мы сможем сделать эти коды способными к рефакторингу, это будет почти рефакторинг в реальном времени.Каждый раз, когда вы добавляете новые функции, новую логику и исправляете исключения, вы должны учитывать, можете ли вы передать структуру кода. , методы реализации, шаблоны проектирования и другие средства для изменения реализации необоснованной функции. Каждый раз немного оптимизации и изменений, это будет не так сложно.
- Когда вы получаете запрос, серьезно подумайте о том, какую структуру данных, логику алгоритма, режим проектирования, агрегацию доменов, оркестровку услуг, системную архитектуру и т. д. необходимо создать для выполнения таких бизнес-требований, чтобы построить более разумную и простая в использовании бизнес-модель Поддерживаемые, масштабируемые системные сервисы. Если у вас еще нет чувства к ним, вы можете прочитатьШаблоны проектированияиРукописная весна, это содержимое может помочь вам улучшить многие логические схемы программирования.