技术与架构中语言章(3)之语言之争与软件工程

原创
2018/04/11 17:29
阅读数 818

前言

项目与技术部中语言选型是至关重要一个环节,是架构的重要组成部分。如果对语言选型出现错误,将会造成巨大的损失,对于初创公司,可能代表创业失败。所以章节语言选型这个架构性问题,所以本节有别上两节的全描述技术方向,主讲架构方向。

鸟菜啊简单介绍

非大学生,半自学编程语言

有7年的编程工作经历

入门语言java,因工作与自身爱好需要自学并应用到项目中有 JavaScript,c#, php, python,scala, lua,,shell,bat 。自身爱好并应用到项目有:c/c++ , 还接触过perl , object-c.目前只记得这么多了。算是经历良多。

高级语言种类

存在的高级语言多到你无法想象,如果想看世界上有多少种高级语言请点击wikipedia统计的高级语言。注意可能看得你会心慌

语言那么多,很多都没见过,也不用到。那那些是常用语言了。请看Tiobe最新排行版

高级语言的根基与魂

目前大多高级语言的解释器与编译器或vm都是用 c语言实现的。

  • 比如 java等语言都是基于jvm实现,jvm是用c与c++实现
  • chromium的v8内核是用c/c++实现的,所以node.js的c/c++实现的
  • obejct-c 看名字....你懂得!!!
  • github在搜索lug,第一个就是lub的解析器的实现,语言标示是 c
  • php,python,perl,ruby,go,等等这些语言已经占据了语言届的90%

C语言开创了括号为代码结构的先河。c语言的语法对其他基于c实现一些高级语言有很大的影响,比如 c++。java, c# , JavaScript等。

谁是世界上最好的语言

先来一个段子

某女:你能让这个论坛的人都吵起来,我今晚就跟你走。

某软件工程师:PHP是最好的语言!

某论坛真的就炸锅了,各种吵架……

某女:服了你了,我们走吧,你想干啥都行。

某软件工程师:今天不行,我一定要说服他们,PHP必须是最好的语言……

看在不要美女,还要证明PHP是世界上最好的语言。优秀的程序员上。暂且证明 PHP是世界上最好的语言。赶快与女神去滚床单。

开源

一个语言的实现是闭源的。那么语言提供的公司,提供的相关技术,也会闭源。不会制定规范。等于把扩展的大门关闭了。公司发展越来越大,对技术要的要求越来越高,对语言本身的要求,探索加强,如果闭源,那么对大型公司来说,是致命的伤害。

如何分析对语言进行分析

性能

  1. 未了性能选择 c/c++,ga 可直接编译成二进制

想什么

那么从操作系统及往上的计算机世界看,大家用高级语言做了那方面的事情

操作系统实现
  1. UNIX类Unix系统 Linux,Mac OS X,iOS
  2. Windows (不包含windows xp 与下)

上面的操作系统都是基于 c 实现的。所以在操作系统实现方面,C语言是毫无争议的唯一

  • 只有极少公司有能力踏入这个领域
  • 相对封闭的领域,关注的人很少
  • 维护软件人员的团队,不庞大,产量低,维护人员的技术水平与个人能力普遍很变态
  • 需求变化少,更新换代低,产出慢
功能软件
  1. 数据库方面软件
    1. 关系型数据库
      1. MySQL
      2. sqlserver
      3. db2
      4. oracle
    2. kv数据
      1. redis
      2. memcached
    3. ........
  2. 语言实现软件
  3. 驱动程序
  4. tpc代理服务与http代理与反向代理。
    1. lvs
    2. nginx

功能软件十分注重性能。所以功能软件的软件基本基于c/c++实现。所以在这个领域c/c++处于绝对领导地位

  • 能创造一个软件的公司也非常稀少
  • 维护软件人员的团队,不庞大,产量低,维护人员的技术水平与个人能力普遍很变态
  • 相对封闭的领域,关注的人较多,大部分只关注如何使用
  • 需求变化少,更新换代低,产出慢
人工智能

鸟菜啊,没有接触过人工智能。但是从技术咨询从得到。尤其是google的那条狗,是用python的实现。python在这个领域有绝对的优势。所以在这个领域语言方面也没有任何争议。

  • 能创造一个软件的公司也非常稀少
  • 维护软件人员的团队,不庞大,产量低,维护人员的技术水平与个人能力普遍很变态
  • 相对封闭的领域,关注的人较多,仅仅是知道
  • 需求变化少,更新换代低,产出慢
大数据

目前来说大数据基本是java的天下。大数据的应用软件基本在apache基金会里面,那些应用软件基本是java实现的。所以在这个领域语言方面也没有任何争议。

  • 能创造一个软件的公司也非常稀少
  • 维护软件人员的团队,不庞大,产量低,维护人员的技术水平与个人能力普遍很变态
  • 相对封闭的领域,关注的人较多,大部分只关注如何使用
  • 需求变化大,更新换代快,产出快
运维方面
  1. shell
  2. perl
  3. python
  • 相对封闭的群体
  • 基本每家公司必备,但是在公司比例极低
  • 基本每家公司都会工作
  • 需求变化大,更新换代快,产出快

视图应用

桌面应用
  1. c#
  2. object-c
  3. c++ qt
  4. python(pyqt)
  5. node(有道)

桌面操作系统基本是windows与苹果系统的天下的天下

移动app
  1. Android
    1. java
  2. 苹果系列
    1. object-c
  3. weex与react native 目的统一移动app,移动web,电脑web
    1. JavaScript
浏览器
  1. JavaScript
  2. html
  3. css

上面的三剑客,各占一方,谁也离不开谁,非常和睦的在一起。算是计算机语言界的奇迹与典范

趋势

现在越来越多的小型硬件系统走向Android成为趋势

大型公司喜欢使用c++,然后写好基础模块,然后对平台的api进行调用。

越来越采用夸平台型解决方案。使用夸平台的框架 比如qt,或者使用夸平台语言python或者node.js。

已嵌入浏览器的方式。或者使用JavaScript。html,css的解析,渲染内容。实现平台的统一,这个趋势尤其在易懂段越来越明显

总结

在这个领域里面,没有什么好争议。要么使用平台支持的语言,要么使用跨平台解决方案。

JavaScript在视图应用层面的分量越来越重。原因如下

  1. 可以对浏览器,移动,桌面进行统一
  2. JavaScript,html,css这三剑客对视图的编写比原声的简单得多
  3. 移动端的语言之争麻烦。比如Android的官方语言从java往kotilin转变,苹果的由object-c往swift转变。对整个移动端的冲击非常大。改变语言的过程中,使用JavaScript可以保证视图,与大量的视图逻辑不变。同时提高相同的接口调用就可以。
  • 相对活跃的群体
  • 基本每家公司必备,但是在公司占比2成左右
  • 需求变化大,更新换代快,产出快

网络服务提供语言

网络服务提供语言。分两个方向一个是对外提供tcp,udp与http。另外一个是对内提供rpc调用。

对内提供rpc调用
  1. dubbo
    1. soa
    2. 不支持多语言
    3. 只支持java
  2. spring cloud
    1. 微服务解决方案
    2. http作为网络传输协议,支持多语言,对java支持最好
    3. java实现
  3. grpc
    1. soa 解决方案
    2. http作为网络传输协议,支持多语言
    3. 有多语言的客服端,
  4. tars
    1. 微服务解决方案
    2. 多语言支持
    3. c++ 实现
对外提供tpc服务

这个领域基本是c++与java的天下,比如游戏2012年之前基本是c++,慢慢后面有一些对性能要求不高的,向java转型了。

对外提供http服务

擅长对外提供http调用的语言有如下

  1. python
  2. php
  3. net( net不讲述,操作系统限制与不开源,直接淘汰)
  4. node.js
  5. java
  6. c++ ( c++ ,实现http服务比较复杂,使用的公司比较少。只带过)
  • 非常相对活跃,庞大的群体
  • 基本每家公司必备,但是在公司占比非常高
  • 需求变化大,更新换代快,产出快

发现语言之间,只是在web开发这个领域。这个领域是最大的一个领域了。其实争论的只是开发效率而已。请下软件工程

总结

  1. 在操作系统层面 c
  2. 在性能软件方面 c/c++,性能要求不高选择java
  3. 运维方面。 python(鸟菜啊的经验,能用python解决的问题,绝对不用shell)
  4. 视图方面,尽量从架构方面优化适应JavaScript
  5. 网络服务方面,选择java
  6. 小型web开发要求效率,选择python,php,node.js。

语言转型浪潮

功能软件:c++转型java浪潮

Google的Chubby 实现是c++ Zookeeper是java Google的GFS 实现是c++, HDFS是java。google的那套大数据开发体系全是使用c++实现,现在基本有java的实现

转变的原因是 c++ 开发效率低,同时这些软件对执行性能要求不高,对操作系统要求高。

网络服务: net转型java

在16年左右,携程还是以.net为主,框架组也有java框架,可以允许部分创新项目用java做,自从换了一个新的CTO,突然决定技术转型,新开的项目强制性的使用java,携程是以.net起家的,技术积累已经相当深厚,可以说是目前国内最大的.net公司了,我有几个疑问: 1、在.net积淀浓厚的情况下突然转型带来的好处是什么? 2、公司几千.net人员怎么处理,不太可能让这些人都去学习java做项目吧,那还不如新招一些3.4年的java人呢? 3、这个重大决定,会像之前在12年左右把宝压在移动互联网这样再一次获得巨大成功吗?

携程为什么突然技术转型从 .NET 转 Java 大公司c#&.net转型java的原因有哪些?

当年选择net因为windows携带品。windows系统最早被政府接受,大学的可能大量教授.net,开发环境与运行运行环境一致的因素,所以被大量的能接受。.net是闭源的,官方提供的框架也是闭源了,让一些国外的开发者慢慢放弃了net。随着国内计算机世界越来越开发,积淀越来越多,慢慢国外的优秀思想,优秀框架传播到国内,慢慢被发现java比net更好

网络服务: php转型java

看过淘宝技术十年的朋友都知道淘宝早起是LAMP架构。两三年之后,直接换成了java。 天猫,新浪的一些页面是php写,在2014年开始慢慢的都消失了。主要是大型公司

java的Velocity框架很强大,大公司统一技术栈。node.js的出现

一些语言的抱怨

抱怨Scala

记得在15年之前,scala好火,认为是一种可以拯救世界的语言,可以替代java....几年过去在tiobe的排名从21名到现在的40,50名。

为什么公司要从Scala转到Go Scala的抱怨 Scala很难 从 Scala 迁移到 Go,永不回头

软件工程

工程与软件工程

工程是用复杂且较好的设备来进行的工作(维基百科)

软件工程是一门研究用工程化方法构建和维护有效的、实用的和高质量的软件的学科。它涉及程序设计语言、数据库、软件开发工具、系统平台、标准、设计模式等方面。(百度)

企业级应用是指那些为商业组织、大型企业而创建并部署的解决方案及应用。这些大型企业级应用的结构复杂,涉及的外部资源众多、事务密集、数据量大、用户数多,有较强的安全性考虑。

当代的企业级应用决不可能是一个个相互独立的系统。在企业中,一般都会部署多个彼此连接的、相互通过不同集成层次进行交互的企业级应用,同时这些应用又都有可能与其它企业的相关应用连接,从而构成一个结构复杂的、跨越Intranet和Internet的分布式企业应用群集。 此外,作为企业级应用,其不但要有强大的功能,还要能够满足未来业务需求的变化,易于升级和维护。

鸟菜啊认为工程是一件复杂,庞大,持续时间长,需要大量工具,需要大量人之间协作,需要不同的环节连贯合作的事情。同时需求变化大,更新换代快,产出快

出现原因

  • 公司团队规模不停的增加,合作与协调,沟通,管理成本不同提升
  • 需要实现的功能越来越多,代码量,模块,依赖 越来越多
  • 对性能要求高,数据量越来越大
  • 技术的更新换代, 技术上问题越来越多
  • 技术栈越来越复杂,应对的软件提供商越来越多。比如单体服务,rpc,soa与微服务的演进
  • 人来人走,学习曲线慢慢增加

从语言开始选择,减少,抵消上面的问题,减少技术债务。要做到减少技术债务,应该做到以下几点。

  1. 学习,研究,深入曲线低
  2. 有相对的开发效率
  3. 代码,设计,架构容易理解,
  4. 对软件生态圈,全面的支持
  5. 项目能快速搭建,部署
  6. 更加强大的容错性

符合软件工程的语言,只有java。不服看下面的分析。

开发效率

在开发效率方面,先淘汰c/c++。是公认开发效率慢的语言

编译语言

编译语言有性能上的优势

垃圾回收器,在内存方面性能比动态语言性能好

面向对象

类型的好处
  1. 类型是一种规范
  2. 类型更加容易组织代码
  3. 类型是一种优秀的代码结构
  4. 类型让代码通俗易懂
面向对象的好处
  1. 接口与抽象类,是一种规范
  2. 良好的类结构管理
  3. 基本所有设计模式都可以实现

动态类型没有重写

class Objects:
    
    
    obj = {}
    
    def __init__(self):
        self.obj = []
        
    def addValue(self):
        print("Objects")
	
	def addValue(self,de):
		print(111)

Traceback (most recent call last):
  File "D:\project\logback\pytest\test.py", line 59, in <module>
    obj.addValue()
TypeError: addValue() missing 1 required positional argument: 'de'

动态类型没有重载,无法调用


class Objects:
    
    
    obj = {}
    
    def __init__(self):
        self.obj = []
        
    def addValue(self):
        print("Objects")
   
class Aodedd(Objects):
        
    def addValue(self):
        self.addValue()
        print("Aodedd")
        
if __name__ == '__main__':
    obj = Objects()
    obj.addValue()
    
    obj = Aodedd()
    obj.addValue()

Traceback (most recent call last):
  File "D:\project\logback\pytest\test.py", line 64, in <module>
    obj.addValue()
  File "D:\project\logback\pytest\test.py", line 56, in addValue

静态类型,最好是强类型

弱类型的问题,在上章节已经讨论过。这里不进行讨论。静态类型的声明对idea提示等十分友好。声明与不声明在代码可读性上有天然之别,对声明的属性与方法进行调用的效率,成本非常低。只是在定义与修改的时候比较麻烦,不爽。但是使用很爽

字段声明的好处

下面举例,是鸟菜啊,在工作的时候,经常的遇到。有时候是鸟菜啊自己,更多的时候是团队合作出现的问题,有几次出现真心是崩溃的。居然在运行的时候出现了。

在繁多的定义了繁多的属性,有声明与无声的区别。有声明的代码通俗易懂。

/** Parent bean factory, for bean inheritance support */
	private BeanFactory parentBeanFactory;

	/** ClassLoader to resolve bean class names with, if necessary */
	private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();

	/** ClassLoader to temporarily resolve bean class names with, if necessary */
	private ClassLoader tempClassLoader;

	/** Whether to cache bean metadata or rather reobtain it for every access */
	private boolean cacheBeanMetadata = true;

	/** Resolution strategy for expressions in bean definition values */
	private BeanExpressionResolver beanExpressionResolver;

	/** Spring ConversionService to use instead of PropertyEditors */
	private ConversionService conversionService;

	/** Custom PropertyEditorRegistrars to apply to the beans of this factory */
	private final Set<PropertyEditorRegistrar> propertyEditorRegistrars =
			new LinkedHashSet<PropertyEditorRegistrar>(4);

	/** A custom TypeConverter to use, overriding the default PropertyEditor mechanism */
	private TypeConverter typeConverter;

	/** Custom PropertyEditors to apply to the beans of this factory */
	private final Map<Class<?>, Class<? extends PropertyEditor>> customEditors =
			new HashMap<Class<?>, Class<? extends PropertyEditor>>(4);

	/** String resolvers to apply e.g. to annotation attribute values */
	private final List<StringValueResolver> embeddedValueResolvers = new LinkedList<StringValueResolver>();

	/** BeanPostProcessors to apply in createBean */
	private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<BeanPostProcessor>();

	/** Indicates whether any InstantiationAwareBeanPostProcessors have been registered */
	private boolean hasInstantiationAwareBeanPostProcessors;

	/** Indicates whether any DestructionAwareBeanPostProcessors have been registered */
	private boolean hasDestructionAwareBeanPostProcessors;

	/** Map from scope identifier String to corresponding Scope */
	private final Map<String, Scope> scopes = new LinkedHashMap<String, Scope>(8);

	/** Security context used when running with a SecurityManager */
	private SecurityContextProvider securityContextProvider;

	/** Map from bean name to merged RootBeanDefinition */
	private final Map<String, RootBeanDefinition> mergedBeanDefinitions =
			new ConcurrentHashMap<String, RootBeanDefinition>(256);

	/** Names of beans that have already been created at least once */
	private final Set<String> alreadyCreated =
			Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(256));

	/** Names of beans that are currently in creation */
	private final ThreadLocal<Object> prototypesCurrentlyInCreation =
			new NamedThreadLocal<Object>("Prototype beans currently in creation");
/** Parent bean factory, for bean inheritance support */
	parentBeanFactory;

	/** ClassLoader to resolve bean class names with, if necessary */
	beanClassLoader = ClassUtils.getDefaultClassLoader();

	/** ClassLoader to temporarily resolve bean class names with, if necessary */
	tempClassLoader;

	/** Whether to cache bean metadata or rather reobtain it for every access */
	cacheBeanMetadata = true;

	/** Resolution strategy for expressions in bean definition values */
	beanExpressionResolver;

	/** Spring ConversionService to use instead of PropertyEditors */
	conversionService;

	/** Custom PropertyEditorRegistrars to apply to the beans of this factory */
	propertyEditorRegistrars =
			new LinkedHashSet<PropertyEditorRegistrar>(4);

	/** A custom TypeConverter to use, overriding the default PropertyEditor mechanism */
	typeConverter;

	/** Custom PropertyEditors to apply to the beans of this factory */
	customEditors = new HashMap<Class<?>, Class<? extends PropertyEditor>>(4);

	/** String resolvers to apply e.g. to annotation attribute values */
	embeddedValueResolvers = new LinkedList<StringValueResolver>();

	/** BeanPostProcessors to apply in createBean */
	beanPostProcessors = new ArrayList<BeanPostProcessor>();

	/** Indicates whether any InstantiationAwareBeanPostProcessors have been registered */
	hasInstantiationAwareBeanPostProcessors;

	/** Indicates whether any DestructionAwareBeanPostProcessors have been registered */
	hasDestructionAwareBeanPostProcessors;

	/** Map from scope identifier String to corresponding Scope */
	scopes = new LinkedHashMap<String, Scope>(8);

	/** Security context used when running with a SecurityManager */
	securityContextProvider;

	/** Map from bean name to merged RootBeanDefinition */
	mergedBeanDefinitions =
			new ConcurrentHashMap<String, RootBeanDefinition>(256);

	/** Names of beans that have already been created at least once */
	alreadyCreated =
			Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(256));

	/** Names of beans that are currently in creation */
	 prototypesCurrentlyInCreation = new NamedThreadLocal<Object>("Prototype beans currently in creation");

属性定义与调用循序的问题

class Field:
    
    def field(self):
        print(self.field)
        pass
    
    def addFiled(self):
        self.field
    
if __name__ == '__main__':
    field = Field()
    field.field()

<bound method Field.field of <__main__.Field object at 0x02F6E830>>

类型修改造成问题

class Objects:
    
    obj = {}
    
    def __init__(self):
        self.obj = []
        
    def addValue(self):
        self.obj[1] = 2
   
if __name__ == '__main__':
    obj = Objects()
    obj.addValue()


Traceback (most recent call last):
  File "D:\project\logback\pytest\test.py", line 53, in <module>
Hello world, laohu (__str__)
    obj.addValue()
  File "D:\project\logback\pytest\test.py", line 49, in addValue
    self.obj[1] = 2
IndexError: list assignment index out of range

对ide友好

class Field:
    
    def field(self):
        print(self.field)
        pass
    
    def addFiled(self):
        self.field
    
eclipse根本就不知道,field字段是否定义了。所以没有任何提示。疯的节奏
方法声明的好处

没有声明,可能不知道传递什么,应该传递什么类型。这些只能靠程序员自己预防,测试。如果不小心传递错误,就异常。这样的事情在鸟菜啊遇到过,有因为是团队其他成员问题,也有与其他团队,项目合作的时候,其他的不小心。在线上这样的问题,太疲劳了。

class Objects:

    def addValue(self, num):
        print(num + 1)

if __name__ == '__main__':
    obj = Objects()
    obj.addValue("1")

Traceback (most recent call last):
  File "D:\project\logback\pytest\test.py", line 56, in <module>
    obj.addValue("1")
  File "D:\project\logback\pytest\test.py", line 50, in addValue
    print(num + 1)
TypeError: Can't convert 'int' object to str implicitly

完整的语言体系

在类里面可以定义静态属性
class Objects{
	public static final String de = "niaocaia";
}
没有内置类型, 全局方法

java只有9大基本类型,其他的都是类类型。使用所有的类类型,都需要通过 new 实例化。有完整的组织结构。 python [] {} JavaScript [] {} 没有内置类型使之,理解简单,思想统一,容易扩展

当年为了找,python,JavaScript的内置类型,全局方法,真心找得累.....

注解

注解是配置的一种,注解在类,方法等地方引入。注解可以减少大量的工作量

枚举

枚举与静态变量没有区别,但他是一种明确的约束。缺点是无法继承

异常

有完善的异常体系,才能实现一个健全的软件工程项目。哪里出错,为什么出错,出错的提示是什么,不同异常不同处理

class Statement{
		
		public final synchronized List<String> statement(String name) throws RuntimeException, IOException{
			
			return Collections.emptyList( );
		}
		
		public void test(){
			try {
				this.statement( "1" );
			} catch ( RuntimeException | IOException e ) {
				log.erren(e);
			} catch (Exception e){
				thows new RuntimeException(e , "这个异常我不处理");
			}finally{
				
			}
		}
		
}

强大的api

记得当年架构终端项目的时候,选择了python找类似于java中ConcurrentHashMap功能的类,死活找不到。java.util.concurrent里面类,在python里面基本没有对应的实现。满脸闷逼。

强大的ide,调试,运行监控工具

java 与c# 拥有最强大的ide,这点大家毋庸置疑吧。ide用于提供程序开发环境的应用程序,一般包括代码编辑器、编译器、调试器和图形用户界面等工具。集成了代码编写功能、分析功能、编译功能、调试功能等一体化的开发软件服务套。所有具备这一特性的软件或者软件套(组)都可以叫集成开发环境

java 拥有强大的监控工具。有查看java进程的jps,有查线程的jstack等等,下面是jvisualvm的运行图。这些强大的监控帮助开发快速,精确的排除各种问题。从而提高开发效率。 输入图片说明

各种基础规范,标准强大的一致性

java定义很多,很多规范,这些规范给软件提供方制造了很多约束。但是方便了使用者,不需要了解是哪个软件提供方提供,更加不需要了解软件提供方如何实现的,只需引入对应规范的jar,按照规范使用就行了。

jdbc1.0规范中就定义了操作相关的接口和类位于java.sql包中。包含了DriverManager类,Driver接口,Connection接口,Statement接口,ResultSet接口,SQLException 类等。任何软件提供方都基于这些规范实现了自己的客服端。jdbc标准概要

项目搭建,发布,运行

在远古社会....java在项目搭建,发布,运行。就是一个神坑..................

输入图片说明 从图中看,java项目的发布流程,十分麻烦,而且重启出错。这是鸟菜啊的亲身经历。这是很多其他语言开发者不喜欢java的地方。

java不可能原地踏步。

maven没有出现之前,java项目的搭建,就是一个悲剧。一个新手搭建一个java项目,并且配置好,运行起来。可能好一个星期。

  1. 到个个框架的网站,去下载
  2. 导入到ide
  3. 如果 个个框架的依赖依赖不一致,版本之间的依赖不一致。作为一个搭建者可能要找可就躺了。

这是其他语言开发者最讨厌java的地方之一

自从有了maven之后,java拜托其他php的唾弃,一下从穷屌丝变成了人见人爱,花见花开的高富帅。java项目的搭建,比其他语言轻松多了。但是maven的入门门槛高了。maven的jar依赖,在模块化的领域,强于其他语言的依赖管理。

  1. java的依赖管理,是基于jar的。其他语言是基于 文件的。
  2. maven的本地,私有,中央。非常方便使用自己的发布到本地,私有服务的jar。
  3. maven强大的流程,可以test等。打成运行jar,直接可以到服务上运行。其他语言可能还要在服务上解决依赖关系

spring-boot的轰动出现,让java在运行,开发方面有一个质量的提升

  1. 使用yml,start插件机制和注释的方式基本放弃了让人唾弃的xml配置,简化了项目构建,部署,管理的成本

  2. 解决web项目启动复杂度。以前发布一个web项目,需要按照tomcat,部署在tomcat里面。现在不需要了。直接启动jar就行了

在这个方面是java的超级短板,也是其他语言使用者唾弃的地方,随着庞大的java程序员的需求,优秀的java程序员不停的提供优秀的解决方案。使之这个短板变成了java的有点

健全,完善,活跃,成熟的各种框架与库

  1. java实现了大量软件
  2. java拥有spring,mybatis等
  3. 消息中间件
  4. 大数据全家桶
  5. 大量分布式框架 ..........

总结

软件工程语言注重的在复杂情况下的效率,而不是简单开发。所以维护,生态园才是根本

展开阅读全文
加载中

作者的其它热门文章

打赏
0
0 收藏
分享
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部