从横向和纵向两个维度寻求复杂问题的答案

22 篇文章 7 订阅
订阅专栏

欢迎大家关注公众号「JAVA前线」查看更多精彩分享文章,主要包括源码分析、实际应用、架构思维、职场分享、产品思考等等,同时欢迎大家加我个人微信「java_front」一起交流学习

1 多维度思维

在知乎上看到了这个有意思的问题:一头牛重800公斤,一座桥承重700公斤,牛应该怎么过桥。初看题目我们不难得出两个方案:桥梁加固、等待牛体重降至700公斤。

这两个方案显然是正确的,但是我们不能就此止步。因为这类问题考察的是思维方法论,直接给出答案反而不是最重要的,对于这个问题我们可以从合理性、结构化、可行性三个维度进行分析。


1.1 合理性分析

一头800公斤的牛要通过承重700公斤的桥,这个需求本身合理吗?我们可以从必要性、紧迫性、替代性这三个维度提出三个问题:

第一个问题问必要性:牛为什么要过桥,到底什么事情非要过桥不可

第二个问题问紧迫性:如果非要过桥,那么这个过桥的需求是否紧急

第三个问题问替代性:有没有什么替代方案,是否可以坐船或者绕路走


1.2 结构化分析

如果经过讨论结果是牛非过桥不可,那么我们再思考牛怎么过桥的方案。这里可以使用结构化思维,将大问题拆分为小维度,尽量做到不遗漏和不重复。影响过桥的因素有这几个维度:桥的维度、牛的维度、资源维度、环境维度。

桥的维度:加固桥使承重大于800公斤

牛的维度:等待牛的体重小于700公斤

资源维度:使用一台吊机把牛运过去

环境维度:取消环境重力


1.3 可行性分析

我们从桥的维度、牛的维度、资源维度、环境维度给出了方案,那么选择哪个方案呢?这就需要我们进行可行性评估,因时因地在资源制约下选择当前最合适的方案。

加固桥方案经济成本较高,等待牛的体重小于700公斤时间成本较高,取消环境重力技术难度较高,所以使用一台吊机把牛运过去这个方案目前看来最合适。


1.4 多维度思考

经过我们从合理性、结构化、可行性三个维度梳理之后,虽然答案没有什么新颖之处,但是思维过程很清晰,思考方法也可以应用在其它问题。之所以思维过程清晰,是因为我们没有一上来直接给出答案,而是从多个维度对为题进行了分析,所以增加维度可以使思考过程更清晰和有章可循。


2 纵向思维与横向思维

思考维度可以从多方面进行充实,其中最常见的是增加横向和纵向两个维度,本文也着重讨论两个维度。总体而言横向扩展的是思考广度,纵向扩展的是思考深度,而应用在不同场景中细节又各有不同。


2.1 时间管理四象限

时间管理理论四象限法则从重要和紧急两个维度建立了一个四象限坐标,可以帮助我们解决主次不分的问题。当我们分配工作时间时,结合四象限法则,重要且紧急的任务优先级最高,而不要急于处理不重要且不紧急的任务。

01 四象限法则.jpg


2.2 金字塔原理

金字塔思维的核心思想并不复杂:一件事情可以总结出一个中心思想,这个中心思想可以由三至七个论点支持,每个论点再可以由三至七个论据支持,基本结构图如下:

金字塔原理内在结构可以从纵向和横向两个维度分析,纵向结构体现了结论先行和以上统下原则,横向结构体现了归类分组和逻辑递进原则。关于金字塔原理详细分析请参看我的文章 金字塔思维怎么指导技术系统优化。

05 金字塔原理.jpg

文章分析到这里,我们发现纵向和横向思维有助于厘清思路和增加条理性,下面我们来看看纵向和横向思维怎样帮助程序员处理复杂问题。


3 架构设计如何应用纵横思维

我们分析一个创建订单业务场景,当前有A、B、C三种订单类型,A类型订单价格9折,物流最大重量不能超过8公斤,不支持退款。B类型订单价格8折,物流最大重量不能超过5公斤,支持退款。C类型订单价格7折,物流最大重量不能超过1公斤,支持退款。按照需求字面含义平铺直叙地写代码也并不难实现:

public class OrderServiceImpl implements OrderService {

    @Resource
    private OrderMapper orderMapper;

    @Override
    public void createOrder(OrderBO orderBO) {
        if (null == orderBO) {
            throw new RuntimeException("参数异常");
        }
        if (OrderTypeEnum.isNotValid(orderBO.getType())) {
            throw new RuntimeException("参数异常");
        }
        // A类型订单
        if (OrderTypeEnum.A_TYPE.getCode().equals(orderBO.getType())) {
            orderBO.setPrice(orderBO.getPrice() * 0.9);
            if (orderBO.getWeight() > 9) {
                throw new RuntimeException("超过物流最大重量");
            }
            orderBO.setRefundSupport(Boolean.FALSE);
        }
        // B类型订单
        else if (OrderTypeEnum.B_TYPE.getCode().equals(orderBO.getType())) {
            orderBO.setPrice(orderBO.getPrice() * 0.8);
            if (orderBO.getWeight() > 8) {
                throw new RuntimeException("超过物流最大重量");
            }
            orderBO.setRefundSupport(Boolean.TRUE);
        }
        // C类型订单
        else if (OrderTypeEnum.C_TYPE.getCode().equals(orderBO.getType())) {
            orderBO.setPrice(orderBO.getPrice() * 0.7);
            if (orderBO.getWeight() > 7) {
                throw new RuntimeException("超过物流最大重量");
            }
            orderBO.setRefundSupport(Boolean.TRUE);
        }
        // 保存数据
        OrderDO orderDO = new OrderDO();
        BeanUtils.copyProperties(orderBO, orderDO);
        orderMapper.insert(orderDO);
    }
}

上述代码从功能上完全可以实现业务需求,但是程序员不仅要满足功能,还需要思考代码的可维护性。如果新增一种订单类型,或者新增一个订单属性处理逻辑,那么我们就要在上述逻辑中新增代码,如果处理不慎就会影响原有逻辑。为了避免牵一发而动全身这种情况,设计模式中的开闭原则要求我们面向新增开放,面向修改关闭,我认为这是设计模式中最重要的一条原则

当需求变化时通过扩展而不是通过修改已有代码来实现变化,这样就保证代码稳定性。扩展也不是随意扩展,因为事先定义了算法,扩展也是根据算法扩展,用抽象构建框架,用实现扩展细节。标准意义的二十三种设计模式说到底最终都是在遵循开闭原则。

那么如何改变平铺直叙的思考方式?这就要为问题分析加上纵向和横向两个维度,我选择使用分析矩阵方法,其中纵向表示策略,横向表示场景。

06 分析矩阵.jpg

3.1 纵向做隔离

纵向维度表示策略,不同策略在逻辑上和业务上应该是隔离的,本实例包括优惠策略、物流策略和退款策略,策略作为抽象,不同的订单类型去扩展这个抽象。在设计模式中策略模式非常适合这种场景。

3.1.1 优惠策略

// 优惠策略
public interface DiscountStrategy {
    public void discount(OrderBO orderBO);
}

// A类型订单优惠策略
@Component
public class TypeADiscountStrategy implements DiscountStrategy {

    @Override
    public void discount(OrderBO orderBO) {
        orderBO.setPrice(orderBO.getPrice() * 0.9);
    }
}

// A类型订单优惠策略
@Component
public class TypeBDiscountStrategy implements DiscountStrategy {

    @Override
    public void discount(OrderBO orderBO) {
        orderBO.setPrice(orderBO.getPrice() * 0.8);
    }
}

// A类型订单优惠策略
@Component
public class TypeCDiscountStrategy implements DiscountStrategy {

    @Override
    public void discount(OrderBO orderBO) {
        orderBO.setPrice(orderBO.getPrice() * 0.7);
    }
}

// 优惠策略工厂
@Component
public class DiscountStrategyFactory implements InitializingBean {
    private Map<String, DiscountStrategy> strategyMap = new HashMap<>();

    @Resource
    private TypeADiscountStrategy typeADiscountStrategy;
    @Resource
    private TypeBDiscountStrategy typeBDiscountStrategy;
    @Resource
    private TypeCDiscountStrategy typeCDiscountStrategy;

    public DiscountStrategy getStrategy(String type) {
        return strategyMap.get(type);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        strategyMap.put(OrderTypeEnum.A_TYPE.getCode(), typeADiscountStrategy);
        strategyMap.put(OrderTypeEnum.B_TYPE.getCode(), typeBDiscountStrategy);
        strategyMap.put(OrderTypeEnum.C_TYPE.getCode(), typeCDiscountStrategy);
    }
}

// 优惠策略执行器
@Component
public class DiscountStrategyExecutor {
    private DiscountStrategyFactory discountStrategyFactory;

    public void discount(OrderBO orderBO) {
        DiscountStrategy discountStrategy = discountStrategyFactory.getStrategy(orderBO.getType());
        if (null == discountStrategy) {
            throw new RuntimeException("无优惠策略");
        }
        discountStrategy.discount(orderBO);
    }
}

3.1.2 物流策略

// 物流策略
public interface ExpressStrategy {
    public void weighing(OrderBO orderBO);
}

// A类型订单物流策略
@Component
public class TypeAExpressStrategy implements ExpressStrategy {

    @Override
    public void weighing(OrderBO orderBO) {
        if (orderBO.getWeight() > 9) {
            throw new RuntimeException("超过物流最大重量");
        }
    }
}

// B类型订单物流策略
@Component
public class TypeBExpressStrategy implements ExpressStrategy {

    @Override
    public void weighing(OrderBO orderBO) {
        if (orderBO.getWeight() > 8) {
            throw new RuntimeException("超过物流最大重量");
        }
    }
}

// C类型订单物流策略
@Component
public class TypeCExpressStrategy implements ExpressStrategy {

    @Override
    public void weighing(OrderBO orderBO) {
        if (orderBO.getWeight() > 7) {
            throw new RuntimeException("超过物流最大重量");
        }
    }
}

// 物流策略工厂
@Component
public class ExpressStrategyFactory implements InitializingBean {
    private Map<String, ExpressStrategy> strategyMap = new HashMap<>();

    @Resource
    private TypeAExpressStrategy typeAExpressStrategy;
    @Resource
    private TypeBExpressStrategy typeBExpressStrategy;
    @Resource
    private TypeCExpressStrategy typeCExpressStrategy;

    @Override
    public void afterPropertiesSet() throws Exception {
        strategyMap.put(OrderTypeEnum.A_TYPE.getCode(), typeAExpressStrategy);
        strategyMap.put(OrderTypeEnum.B_TYPE.getCode(), typeBExpressStrategy);
        strategyMap.put(OrderTypeEnum.C_TYPE.getCode(), typeCExpressStrategy);
    }

    public ExpressStrategy getStrategy(String type) {
        return strategyMap.get(type);
    }
}

// 物流策略执行器
@Component
public class ExpressStrategyExecutor {
    private ExpressStrategyFactory expressStrategyFactory;

    public void weighing(OrderBO orderBO) {
        ExpressStrategy expressStrategy = expressStrategyFactory.getStrategy(orderBO.getType());
        if (null == expressStrategy) {
            throw new RuntimeException("无物流策略");
        }
        expressStrategy.weighing(orderBO);
    }
}

3.1.3 退款策略

// 退款策略
public interface RefundStrategy {
    public void supportRefund(OrderBO orderBO);
}

// A类型订单退款策略
@Component
public class TypeARefundStrategy implements RefundStrategy {

    @Override
    public void supportRefund(OrderBO orderBO) {
        orderBO.setRefundSupport(Boolean.FALSE);
    }
}

// B类型订单退款策略
@Component
public class TypeBRefundStrategy implements RefundStrategy {

    @Override
    public void supportRefund(OrderBO orderBO) {
        orderBO.setRefundSupport(Boolean.TRUE);
    }
}

// C类型订单退款策略
@Component
public class TypeCRefundStrategy implements RefundStrategy {

    @Override
    public void supportRefund(OrderBO orderBO) {
        orderBO.setRefundSupport(Boolean.TRUE);
    }
}

// 退款策略工厂
@Component
public class RefundStrategyFactory implements InitializingBean {
    private Map<String, RefundStrategy> strategyMap = new HashMap<>();

    @Resource
    private TypeARefundStrategy typeARefundStrategy;
    @Resource
    private TypeBRefundStrategy typeBRefundStrategy;
    @Resource
    private TypeCRefundStrategy typeCRefundStrategy;

    @Override
    public void afterPropertiesSet() throws Exception {
        strategyMap.put(OrderTypeEnum.A_TYPE.getCode(), typeARefundStrategy);
        strategyMap.put(OrderTypeEnum.B_TYPE.getCode(), typeBRefundStrategy);
        strategyMap.put(OrderTypeEnum.C_TYPE.getCode(), typeCRefundStrategy);
    }

    public RefundStrategy getStrategy(String type) {
        return strategyMap.get(type);
    }
}

// 退款策略执行器
@Component
public class RefundStrategyExecutor {
    private RefundStrategyFactory refundStrategyFactory;

    public void supportRefund(OrderBO orderBO) {
        RefundStrategy refundStrategy = refundStrategyFactory.getStrategy(orderBO.getType());
        if (null == refundStrategy) {
            throw new RuntimeException("无退款策略");
        }
        refundStrategy.supportRefund(orderBO);
    }
}

3.2 横向做编排

横向维度表示场景,一种订单类型在广义上可以认为是一种业务场景,在场景中我们要将独立的策略进行串联,模板方法设计模式适用于这种场景。

模板方法模式定义一个操作中的算法骨架,一般使用抽象类定义算法骨架。抽象类同时定义一些抽象方法,这些抽象方法延迟到子类实现,这样子类不仅遵守了算法骨架约定,也实现了自己的算法。既保证了规约也兼顾灵活性。这就是用抽象构建框架,用实现扩展细节。

// 创建订单服务
public interface CreateOrderService {
    public void createOrder(OrderBO orderBO);
}

// 抽象创建订单流程
public abstract class AbstractCreateOrderFlow {

    @Resource
    private OrderMapper orderMapper;

    public void createOrder(OrderBO orderBO) {
        // 参数校验
        if (null == orderBO) {
            throw new RuntimeException("参数异常");
        }
        if (OrderTypeEnum.isNotValid(orderBO.getType())) {
            throw new RuntimeException("参数异常");
        }
        // 计算优惠
        discount(orderBO);
        // 计算重量
        weighing(orderBO);
        // 退款支持
        supportRefund(orderBO);
        // 保存数据
        OrderDO orderDO = new OrderDO();
        BeanUtils.copyProperties(orderBO, orderDO);
        orderMapper.insert(orderDO);
    }

    public abstract void discount(OrderBO orderBO);

    public abstract void weighing(OrderBO orderBO);

    public abstract void supportRefund(OrderBO orderBO);
}

// 实现创建订单流程
@Service
public class CreateOrderFlow extends AbstractCreateOrderFlow {

    @Resource
    private DiscountStrategyExecutor discountStrategyExecutor;
    @Resource
    private ExpressStrategyExecutor expressStrategyExecutor;
    @Resource
    private RefundStrategyExecutor refundStrategyExecutor;

    @Override
    public void discount(OrderBO orderBO) {
        discountStrategyExecutor.discount(orderBO);
    }

    @Override
    public void weighing(OrderBO orderBO) {
        expressStrategyExecutor.weighing(orderBO);
    }

    @Override
    public void supportRefund(OrderBO orderBO) {
        refundStrategyExecutor.supportRefund(orderBO);
    }
}

3.3 复杂架构设计

上述实例业务和代码并不复杂,其实复杂业务场景也不过是简单场景的叠加和交织,我们无外乎也是通过纵向做隔离、横向做编排寻求答案。

07 纵向隔离横向编排.jpg

纵向维度抽象出能力池这个概念,能力池中有一个一个能力,不同的能力按照不同业务维度聚合,例如优惠能力池,物流能力池,退款能力池。我们可以看到两种程度的隔离性,能力池之间相互隔离,能力之间也相互隔离。

横向维度将能力从能力池选出来,按照业务需求串联在一起,形成不同业务流程。因为能力可以任意组合,所以体现了很强的灵活性。除此之外,不同能力既可以串行执行,如果不同能力之间没有依赖关系,也可以如同流程Y一样并行执行,提升执行效率。


4 数据分片如何应用纵横思维

现在有一个电商数据库存放订单、商品、支付三张业务表。随着业务量越来越大,这三张业务数据表也越来越大,查询性能显著降低,数据拆分势在必行。那么数据拆分可以从纵向和横向两个维度进行。


4.1 纵向分表

纵向拆分就是按照业务拆分,我们将电商数据库拆分成三个库,订单库、商品库。支付库,订单表在订单库,商品表在商品库,支付表在支付库。这样每个库只需要存储本业务数据,物理隔离不会互相影响。

02 纵向分表.jpg


4.2 横向分表

按照纵向拆分方案,现在我们已经有三个库了,平稳运行了一段时间。但是随着业务增长,每个单库单表的数据量也越来越大,逐渐到达瓶颈。

这时我们就要对数据表进行横向拆分,所谓横向拆分就是根据某种规则将单库单表数据分散到多库多表,从而减小单库单表的压力。

横向拆分策略有很多方案,最重要的一点是选好ShardingKey,也就是按照哪一列进行拆分,怎么分取决于我们访问数据的方式。


4.2.1 范围分片

如果我们选择的ShardingKey是订单创建时间,那么分片策略是拆分四个数据库,分别存储每季度数据,每个库包含三张表,分别存储每个月数据:

03 横向分表_范围分表.jpg

这个方案的优点是对范围查询比较友好,例如我们需要统计第一季度的相关数据,查询条件直接输入时间范围即可。这个方案的问题是容易产生热点数据。例如双11当天下单量特别大,就会导致11月这张表数据量特别大从而造成访问压力。


4.2.2 查表分片

查表法是根据一张路由表决定ShardingKey路由到哪一张表,每次路由时首先到路由表里查到分片信息,再到这个分片去取数据。我们分析一个查表法思想应用实际案例。

Redis官方在3.0版本之后提供了集群方案RedisCluster,其中引入了哈希槽(slot)这个概念。一个集群固定有16384个槽,在集群初始化时这些槽会平均分配到Redis集群节点上。每个key请求最终落到哪个槽计算公式是固定的:

SLOT = CRC16(key) mod 16384

一个key请求过来怎么知道去哪台Redis节点获取数据?这就要用到查表法思想:

(1) 客户端连接任意一台Redis节点,假设随机访问到节点A
(2) 节点A根据key计算出slot值
(3) 每个节点都维护着slot和节点映射关系表
(4) 如果节点A查表发现该slot在本节点,直接返回数据给客户端
(5) 如果节点A查表发现该slot不在本节点,返回给客户端一个重定向命令,告诉客户端应该去哪个节点请求这个key的数据
(6) 客户端向正确节点发起连接请求

查表法方案优点是可以灵活制定路由策略,如果我们发现有的分片已经成为热点则修改路由策略。缺点是多一次查询路由表操作增加耗时,而且路由表如果是单点也可能会有单点问题。


4.2.3 哈希分片

现在比较流行的分片方法是哈希分片,相较于范围分片,哈希分片可以较为均匀将数据分散在数据库中。我们现在将订单库拆分为4个库编号为[0,3],每个库包含3张表编号为[0,2],如下图如所示:

04 横向分表_哈希分表_1.jpg

我们选择使用orderId作为ShardingKey,那么orderId=100这个订单会保存在哪张表?因为是分库分表,第一步确定路由到哪一个库,取模计算结果表示库表序号:

db_index = 100 % 4 = 0

第二步确定路由到哪一张表:

table_index = 100 % 3 = 1

第三步数据路由到0号库1号表:

04 横向分表_哈希分表_2.jpg

在实际开发中路由逻辑并不需要我们手动实现,因为有许多开源框架通过配置就可以实现路由功能,例如ShardingSphere、TDDL框架等等。


5 文章总结

复杂问题不过是简单问题的组合和交织,横向和纵向维度拆分问题不失为一种好方法。纵向做隔离是指将不同业务形态进行隔离,能力池之间进行隔离,能力之间也进行隔离。横向做编排是指从能力池中灵活选择能力,进行组合和编排,形成各异的业务流程。希望本文对大家有所帮助。

欢迎大家关注公众号「JAVA前线」查看更多精彩分享文章,主要包括源码分析、实际应用、架构思维、职场分享、产品思考等等,同时欢迎大家加我个人微信「java_front」一起交流学习

【光剑书架上的书】书评推荐《佛教史》杜继文
程序员光剑
09-04 107
【光剑书架上的书】《佛教史》杜继文 书评推荐语 摘要 在《光剑书架上的书》系列推荐中,杜继文的《佛教史》以其严谨的学术态度、全面的视野和深刻的洞见,成为了理解佛教历史与文化的必备读物。本书不仅详尽地描绘了佛教从古印度起源到现代西方传播的历程,而且深入探讨了佛教教义、教派、僧侣制度以及
复杂、繁杂、庞杂:图解七种代码耦合类型
lt_xiaodou的博客
09-04 395
第一本文区分了复杂、繁杂、庞杂这一组概念,复杂和繁杂虽然都比较难处理,但是复杂是可以理出头绪的,而繁杂最终会积重难返。我们应该尽量避免繁杂的代码。复杂和繁杂加上数量维度就成为庞杂。第二本文介绍了七种代码耦合类型,根据耦合程度由高到低排序分别是:内容耦合、公共耦合、外部耦合、控制耦合、标记耦合、数据耦合和非直接耦合。我们应该尽量写耦合度低的代码。第三本文由一个复杂订单场景实例出发,重点介绍了非直接耦合类型,可以看到即使是复杂场景,通过合理的设计也可以优雅实现,希望本文对大家有所帮助。
回溯问题(二):组合和问题及回溯问题横向去重和纵向去重
qq_42138662的博客
06-25 335
组合总和 给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的数字可以无限制重复被选取。 1、问题抽象与代码实现 1)问题抽象 2)代码实现 class Solution { private: vector<vector<int>> result; vector<int> path; void backtracki..
02-问题思考维度:抓住核心用户、场景化分析、需求收集与辨别、用户故事
Serendipity_zyx的博客
03-04 1923
第二章问题思考维度:抓住核心用户、场景化分析、需求收集与辨别、用户故事
横向纵向维度寻求复杂问题答案
BASK2311的博客
03-10 557
复杂问题不过是简单问题的组合和交织,横向纵向维度拆分问题不失为一种好方法。纵向做隔离是指将不同业务形态进行隔离,能力池之间进行隔离,能力之间也进行隔离。横向做编排是指从能力池中灵活选择能力,进行组合和编排,形成各异的业务流程。希望本文对大家有所帮助。作者:JAVA前线链接:https://juejin.cn/post/7208559891605602361。
2星|《麦肯锡与贝恩的团队管理智慧》:从投入、产出两个维度把下属分到4个象限...
weixin_33709219的博客
11-17 183
麦肯锡与贝恩的团队管理智慧 英文原版出版于2015年。内容是如何管理下属。作者从领导力的投入、工作的产出两个维度把下属划分到4个象限中,每个象限又细分出几个类型的工作者,然后针对不同类型的工作者,给出领导者的策略,给出具体的案例。 总体感觉是偏简单,简化后的两个维度不能全面概括领导工作的主要方面。另外书中的信息浓度也偏低。 总体评价2星。 以下是书中一...
数据分析师必学第一课:构建完整的指标体系
博文视点(北京)官方博客
07-17 1333
掌握理论知识和编程知识可以被看作入职数据分析师的“敲门砖”。掌握了这些知识,表示候选人对于成为数据分析师有了良好的准备,可以说“万事俱备,欠东风”,而“东风”就是一些实际工作内容和相应的技巧。 数据人员如何创造价值 随着大数据的发展,公司的数据库中存储着大量的数据,这些数据大多是公司内部技术人员通过埋点获取的,也有些是通过第三方机构获取的。如何充分利用这些数据,创造价值,推动公司的发展,是数据分析师所应该思考的。 作为数据分析师,经常被问到: XXX数据最近上升/下降了,是什么原因造成的? 新上线的功能给
批发零售行业:成长与防御,两个维度的渠道价值-0705-海通证券-30页.pdf
最新发布
07-25
本报告从批发零售行业在成长和防御两个维度的价值出发,深入探讨了行业的集中度提升、新零售实践、以及面临的风险等关键点。 首先,在“成长”的维度中,报告指出批发零售行业的集中度正在加速提升,主要体现在行业...
教学目标四个维度_【智慧】育人目标导向的跨学科课程设计
weixin_39806388的博客
11-18 2754
将知识按照学科的划分开展分科教学,有利于学生对知识体系的整体把握和理解,但割裂了学生与真实世界的有机联系。在学校教育走向开放、多元,对人才的需求走向综合型、创新型的今天,对学科知识进行整合,提高学生综合运用知识去观察问题、分析问题、解决问题的能力,展开跨学科课程的学习显得尤为重要。2019年,学校借助区重点项目的平台优势,投身课题--“育人目标导向下跨学科课程体系建构的研究”经过近两年的...
高等教育心理学试题及答案---副本.pdf
12-04
这两种研究方法各有优缺点,横向研究能快速发现差异,但难以控制变量;纵向研究可揭示稳定性,但可能面临被试流失等问题。 2. **发生认知论**:由皮亚杰创立,关注儿童认知的发生和发展规律,认为认知发展是通过...
四种常见数据模型(维度模型、范式模型等)
08-17 7347
一篇文章搞懂数据仓库:四种常见数据模型(维度模型、范式模型等) 不吃西红柿丶 2020-12-04 14:05:00 10860 收藏 60 分类专栏: 数据仓库 文章标签: 数据模型 范式模型 雪花模型 版权 数据仓库 专栏收录该内容 16 篇文章127 订阅 订阅专栏 目录 写在前面 一、为什么要进行数据仓库建模? 二、四种常见模型 2.1 维度模型 2.1.1 星型模型 2.1.2 雪花模型 2.1.3 星座模型 2.2 范式模型 2.3 Data Vault模型 2.4 ..
长文多图:结合DDD讲清楚编写技术方案的七大维度
JAVA前线技术专栏
10-01 711
欢迎大家关注公众号「JAVA前线」查看更多精彩分享文章,主要包括源码分析、实际应用、架构思维、职场分享、产品思考等等,同时欢迎大家加我个人微信「java_front」一起交流学习 1 为什么要写技术文档 回顾软件开发历史,我们可以将其分为程序设计时代、程序系统时代和软件工程时代三大历史阶段。 在程序设计时代(1946-1956),软件开发主要依赖于个人编程技巧,技术文档只要存在个人开发者的大脑即可,因为没有沟通和协作需要,编写技术文档也不具有紧迫性。 在程序系统时代(1956-1968),计算机性能显著.
MSSQL表分区的创建
weixin_30809333的博客
09-28 110
最近在做项目数据库优化过程中,考虑了数据库表分区的方案,MSSQL2005新增了表分区的概念,现在我用测试表来做一次表分区。表分区可以把不同数据放到不同数据库文件,按物理地址来隔开数据,理论情况下如果服务器是多磁盘,多CPU,还做了磁盘阵列后,查询操作效率会更明显。 现在基本所有数据库都存在表分区的概念,但MSSQL表分区一些细节又不一样,我现在也是有一定的了解,因此本篇文章不做很细的原理性质的...
技术人员的横向纵向发展
weixin_30375247的博客
01-07 345
工作的前一年半,我是雄心勃勃,信心十足,但这次跳槽后,几个月的思考,逐渐感觉到了我的“一度冰寒”...      对IT从业人员长期职业生涯规划的缺失,正在造就越来越多高薪水,低价值的老IT人.      每位IT经理都想招到最好的员工.这些员工最好拥有本科以上文凭,毕业于名校;攻读计算机,电子工程,通讯等专业;在学校期间涉猎广泛:从硬件到软件无一不知,各种开发语言拿得...
举例说明层次分析的三大原则_《搞定》一个境界、两个维度、三大原则让你轻松搞定繁重的事务...
weixin_39553653的博客
11-20 891
文/定石不知道,你现在是不是还是这种情况,要做的事情一大堆,单位的事情要忙,家里的事情要忙,孩子的事情要忙,父母的事情要忙。各种各样的事情,好像都急,干着这个,想着那个,另一个还放在心上不踏实,整体忙得脚不沾地。可是到月底一看,什么都没干好,单位领导训,家里爱人吵,孩子闹,父母怨,如果要让我描述一下你的状态,就一个字"忙"。唉!啥时候是个头呀!学习,学习提高工作效率、时间管理,使用各类管理辅助工具...
软件需求的层次
power1952的专栏
07-02 2164
软件需求的层次
横向拆分与纵向拆分
江城宴的博客
03-17 4324
表的拆分分为横向拆分(记录的拆分)和纵向拆分(字段的拆分)。拆分表的目的:提高查询速度。   1.横向拆分     我们从一个案例去解释,情景是这样的:某某博客,有50W的博客量,有2w的用户,发现随着用户和博客数的增加,查询速度日渐下降,现在要对博客表blog与用户表user进行优化。   表结构如下: 复制代码 1 create table blog( 2 bid ...
纵向拆分和横向拆分
安善良民弱女子的博客
11-09 7393
纵向拆分:通过对业务进行梳理,根据业务的特性把应用拆开,不同的业务模块独立部署。 例如:商品购买流程可拆分为: 订单管理 订单稽查 新增产品 产品查询 客户管理 历史查询横向拆分:将核心的、公共的业务拆分出来,通过分布式服务框架对业务进行服务化,消费者通过标准的契约来消费这些服务。服务提供者独立打包、部署和演进,与消费者解耦。 例如业务1:订单创建服务 库存查询 移动支付服务 等 业务2
数据分析中常用分析思路对比分析解析(二) 数据分析中常用分析思路对比分析解析(二)
weixin_43186694的博客
04-16 1302
对比是识别事物的基本方法对比——横向纵向及多维度对比比值比率背后的逻辑指标的逻辑与管理指标对标的层次和维度标杆管理与榜样的力量。 4.3 比值比率背后的逻辑 最常见的对比是大小的对比、数量的对比,例如销售额的对比、人数的对比、时间长短的对比。使用不同的对比指标会得到不同的结论。 我们把对比标准的选择叫作对比的视角,对比视角不同,就会得出不同的结论。例如将小强和小明对比,从身高的角度对比,就有了高...
GridView固定表头实例:横向滚动与纵向固定
"该资源提供了一个关于在ASP.NET中使用GridView控件实现固定表头、横向滚动和纵向固定的实例。主要涉及的技术点包括CSS样式、GridView属性设置以及可能遇到的问题和解决方案。" 在Web开发中,GridView是一个常用的...
写文章

热门文章

  • Maven学习六之利用mvn deploy命令上传包 164447
  • Mybatis中的resultType和resultMap 162930
  • Java异常分类 143964
  • WebService报错javax.xml.ws.soap.SOAPFaultException: javax.xml.ws.WebFault.messageName() 62718
  • org.apache.maven.plugins:maven-resources-plugin:2.4.3 55114

分类专栏

  • 【JAVA】综合 35篇
  • 并发编程学习笔记 3篇
  • DUBBO 17篇
  • 大数据学习笔记 10篇
  • Netty学习笔记 5篇
  • Spring学习笔记 4篇
  • 【JAVA】线程 7篇
  • 【JAVA】spring 4篇
  • 【JAVA】mybatis 3篇
  • 【JAVA】web 1篇
  • 【JAVA】eclipse 4篇
  • 【服务器】weblogic 1篇
  • 【服务器】tomcat 2篇
  • 【服务器】webService 1篇
  • 【操作系统】概述 3篇
  • 【操作系统】Linux 2篇
  • 【项目管理】Git 1篇
  • 【数据库】综合 10篇
  • 【网络】综合 5篇
  • 【网络】netty 5篇
  • 【网络】加密解密 2篇
  • 【专业知识】综合 2篇
  • 【大数据】综合 11篇
  • 【缓存】Redis 2篇
  • 【架构】架构设计 22篇

最新评论

  • 商品领域十二张基础表设计思路与实现

    zhongmiao111: 请问类目表为什么不可以只有一个呢

  • 六个思考维度:DDD + SpringBoot工程九层结构图解与实战

    jssd: 有没有代码仓可以看

  • 长文多图一步步讲清楚:DDD理论、建模与代码实现全流程

    solihawk: 非常详细,ddd代码实现很清晰

  • 警惕看不见的重试机制:为什么使用RPC必须考虑幂等性

    qq_44651127: 加锁会降低性能,取消重试机制万一网络波动发送失败无法消费一样会造成幂等问题。

  • 多图详解:七种具体方法增强代码可扩展性

    JAVA前线: 谢谢欢迎关注

最新文章

  • 技术系统出现故障怎么定责?法学家、经济学家与商人的三种思路
  • MySQL连接空闲时间超过8小时报错原因与延伸知识
  • 浅析分布式业务一致性方案
2024年4篇
2023年15篇
2022年17篇
2021年19篇
2020年21篇
2017年7篇
2016年22篇
2014年15篇
2013年7篇
2012年8篇

目录

目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

天下网标王外贸网站怎么优化排名合作关键词网站优化大型网站完整优化方案武汉网站优化平台网站目标关键词优化咨询网站文章怎么去做seo优化网站seo关键词优化价格新乡网站排名优化哪家不错青岛网站优化多少钱网站排名优化皆选金苹果江都网站整站优化网站排名优化算什么职业鄂州外包网站优化价格png优化网站网站优化公司 大家好企业网站优化与管理京东商城网站优化方案怎样做网站seo优化网站流量优化工具网站分页面怎么优化新乡网站建设优化渠道电话seo网站排名优化教程大城专业网站优化企业普陀区360网站优化案例江西网站关键词排名优化阳江公司网站关键词优化推广西秀区分类网站优化优化排名网站安全易速达网站搜索引擎优化免费提供试用网站优化能做什么香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声卫健委通报少年有偿捐血浆16次猝死汪小菲曝离婚始末何赛飞追着代拍打雅江山火三名扑火人员牺牲系谣言男子被猫抓伤后确诊“猫抓病”周杰伦一审败诉网易中国拥有亿元资产的家庭达13.3万户315晚会后胖东来又人满为患了高校汽车撞人致3死16伤 司机系学生张家界的山上“长”满了韩国人?张立群任西安交通大学校长手机成瘾是影响睡眠质量重要因素网友洛杉矶偶遇贾玲“重生之我在北大当嫡校长”单亲妈妈陷入热恋 14岁儿子报警倪萍分享减重40斤方法杨倩无缘巴黎奥运考生莫言也上北大硕士复试名单了许家印被限制高消费奥巴马现身唐宁街 黑色着装引猜测专访95后高颜值猪保姆男孩8年未见母亲被告知被遗忘七年后宇文玥被薅头发捞上岸郑州一火锅店爆改成麻辣烫店西双版纳热带植物园回应蜉蝣大爆发沉迷短剧的人就像掉进了杀猪盘当地回应沈阳致3死车祸车主疑毒驾开除党籍5年后 原水城县长再被查凯特王妃现身!外出购物视频曝光初中生遭15人围殴自卫刺伤3人判无罪事业单位女子向同事水杯投不明物质男子被流浪猫绊倒 投喂者赔24万外国人感慨凌晨的中国很安全路边卖淀粉肠阿姨主动出示声明书胖东来员工每周单休无小长假王树国卸任西安交大校长 师生送别小米汽车超级工厂正式揭幕黑马情侣提车了妈妈回应孩子在校撞护栏坠楼校方回应护栏损坏小学生课间坠楼房客欠租失踪 房东直发愁专家建议不必谈骨泥色变老人退休金被冒领16年 金额超20万西藏招商引资投资者子女可当地高考特朗普无法缴纳4.54亿美元罚金浙江一高校内汽车冲撞行人 多人受伤

天下网标王 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化