是什么造成中国软件产业的悲剧

中国的软件产业虽然也有长足的发展,但现实中,我们没有真正意义上的软件巨头型企业。

作者 I 会说话的波吉

来源 I 会说话的波吉

(ID: gh_901266027a80 )

经历了这么多年的风风雨雨,作为中国软件的从业者,我常常在思考,为什么中国的软件产业还是很低端,并没有太多的优秀的软件问世,反而我们的邻国俄罗斯,最近这二十年完全无法和中国的经济发展相比较,但在软件行业里,前有大家基本上无法离开的 Nginx,后有现在已经大规模被使用中的 Clickhouse,这些都是有能力影响全世界的产品。

中国的软件产业虽然也有长足的发展,但现实中,我们没有真正意义上的软件巨头型企业,大量基础软件被外国垄断,这究竟是为什么呢?

波吉结合自己这么多年的观察,总结了以下几个点供大家参考:

01

信息系统大行其道

这个可能跟中国软件产业的发展有关,最早期的中国软件公司,本质上都要么是做对欧美日本的外包产业,要么就是本质上是微软,Oracle,SAP 这些巨头公司产品在中国的代理商(美其名曰ISV),其实都是使用特定的基础软件帮助各行各业完成信息化改造,但各行各业的信息化随着业务变化是不同的,需要大量的定制化,所以无可避免的就是形成了软件=做工程的这么个状态,大量的现在台面上的中国软件公司,本质上就是拿着老外的产品到各个产业做施工队,这也深深的影响了甲方,而且这个影响非常深远。

第一层影响,中国大量的 SaaS 创业者本质上都是在信息系统上创业,没有什么核心竞争力,基本上都是各种流程再造,但满足不了甲方需求,最终沦落为新时代的施工队。

第二层影响,中国的大甲方天然就习惯了施工队模式,导致了中国软件行业很多时候就是个外包模式。

02

项目能孵化出产品?

所有软件行业的从业者们都有一个幻想,通过先完成一个最基础的 MVP 模型,然后找甲方进行以项目方式试用,最后能够通过在项目的实战中总结经验完成产品化,最终能够拿出一个完美的产品在行业内复制。

然而,由于大部分的中国软件从业者都是信息系统的创业,加上很多时候一个抽象的信息系统必然需要实施,甚至对甲方业务流程等各方面的咨询实施培训(见 SAP),往往中国的软件创业者又无法输出相应的管理学和流程梳理等最佳实践,为了通过项目形式完成交易,最终一个客户被满足了,但积累的并不是产品,而是一个客户案例,一个行业案例,然后找下一个客户进行定制,最后成功的和自己的前辈们一样,成了某个基础产品的集成商和交付商。

03

销售驱动自毁长城

现在在中国软件行业(其实也是舶来品)特别流行一个概念叫 PLG,所谓产品驱动增长,与之相对的是 SLG,所谓销售驱动增长。

但波吉认为,这个说法本身就很有问题,无论是任何一个行业,不管 2B2C,不管是汽车,电子消费品,服装,难道不都是产品力为王么?难道产品不好好做,意味着研究所谓如何销售吗?所谓销售驱动增长,尤其在软件行业,这背后传递的是什么呢?我很难想象一个强调销售套路超过产品本身的公司,能做出什么好的产品?于是这些销售们为了拿单子,完成自己的指标,也逼迫公司将一个个标准化产品去满足各种奇奇怪怪的客户需求,最后走入了死胡同,一旦销售团队崩溃,这个公司也就崩溃,因为客户本身不是为产品的价值买单,我见过太多销售驱动的产品,最终甲方根本没有将产品用起来。

04

政府的羊毛最好撸

政府信息化数字化也进展了非常多的年头,中国各个地方,大大小小的软件公司,有很多都是政府信息化工程的施工队,这也是中国软件公司非常庞大的一个群体,他们往往又都是重要的集成商,于是乎随着自主可控的概念兴起,一些全国性的所谓信创软件公司和这些地方上的软件公司沆瀣一气,打着旗号撸政府相关的羊毛。

这一类的软件公司本质上的动力不是做一个好软件,而是如何做一个满足政策自主可控需求的软件,在这种出发点下,各地政府又要满足中央的自主可控的目标,事实上形成的产业链很难说对中国软件产业发展有什么帮助,对提升中国的软件实力有什么帮助。类似中国的新能源汽车市场,那些为了仅仅是获取国家补贴的所谓新能源车,什么质量大家都心知肚明。

05

大型企业的汉尼拔情结

中国的大型企业客户,大甲方们,由于一开始受信息化时代的合作模式影响,天然的看待中国的软件公司就是工程队,所以人天模式大行其道。

把一切中国的软件都看成是低技术含量的人天可交付的系统,并且一定要源代码,所谓自主可控。再加上大量的中国软件供应商很多只不过是开源软件的魔改厂商,所以让这些大型企业的技术决策者都一个个变成了技术选型的汉尼拔,硬生生需要将一个完整的软件产品看成一个个分片,他们的心里思考的就是软件只不过就是招一堆工程师改吧改吧就能完成需求的东西。最近的银监会出台了一个国有银行管理外包的政策,基本上把软件就定义成了人头工程,在这种情况下我很难想象这个领域会产生一个优秀的软件企业,有的只不过是给银行提供技术人员人头外包的人力管理公司。

06

互联网公司的技术妄念

中国还有一个貌似被看成全村希望的互联网公司,在大众的眼里,互联网公司技术实力强,人员素质高,互联网公司中的工程师也经常发布很多技术观点,甚至大有中国软件技术引领者的味道。然后现实却非常的残酷,中国互联网公司的本质业务并不是软件,是电商,是社交,是媒体,是买菜,但并不包含软件。软件技术只是互联网公司通过互联网实现自己业务的手段而已,本质还是信息系统。

大部分中国的互联网公司所谓的技术仅仅只不过是在国外的开源软件基础上实现一系列的封装,一系列的优化,美其名曰就是技术实力了,但本质上只是白剽了国外开源软件,而不是购买国外商业软件,然后本质上还是系统集成开发而已,唯一区别可能是面向自己公司的业务,不是外包身份。

中国的互联网公司也产生了一些优秀的软件,但都是把这部分业务变成了独立的软件公司,如云计算,才有可能有发展的价值。

简而言之,互联网公司的一些技术只不过是吃饭的手段,而软件公司本身开发产品是身家性命,岂可同日而语。所以互联网公司所谓的自研都不过是技术团队妄念,对核心业务毫无帮助的事情,无论公司还是个人发展都没有任何意义。

路在何方?

面对这么多的想象,其背后反映出了的本质问题是什么?

中国软件产业本身最缺乏的恰恰是一群真正意义上的软件从业者,这群人的目标应该是真正打造出有价值的软件产品,目标应该是将软件的核心竞争力与世界一流的软件产品相抗衡。并且这一些软件不应该还是那些传统的信息化,数字化的项目定制化的软件。而应该是数据库,中间件,基础软件,Photoshop/CAD/EDA等专业软件。

这才是中国软件的未来,只不过面对目前错综复杂的国际形势和当前严峻的经济环境,有多少企业能坚持做好产品,坚持用好的产品改变甲方的刻板印象,坚持到春暖花开的那一天…..

转自:https://mp.weixin.qq.com/s/YBb6GmpLfjfzaGblEI2VcQ

我做了一个App,如何让别人限时使用?

假设有这样一个场景,你接了一个私活,帮别人做一个软件,软件没有联网功能。东西做好以后,客户还没有给钱,说要先试用一下。你选择了相信客户,把软件发送给了他。然后他就把你拉黑了。

为了避免这种情况发生,你首先想到的办法,肯定是把过期时间写死到代码里面,时间到了App自动销毁。对方付钱以后,你再把这个写死的时间延长或者去掉。再重新编译后发给客户。

但问题是,每次重新编译代码并发给用户是非常麻烦的事情,有没有更简单的办法呢?能不能软件始终是一个软件,但是给用户一个注册码,这个注册码里面标记了有效时间。等到过期以后,只需要给用户一个新的注册码,就可以继续使用了。

看到这里,有同学肯定会想,怎么在注册码指定有效期呢?首先这个时间肯定不能是明文的,否则用户把它一改,岂不是就可以自行延长了。

但如果加密的话,就必须把解密算法放到软件里面,一旦用户对程序进行初步的反编译,就能拿到解密算法或者对称加密的密钥。

因此,我们只能使用非对称加密。而非对称加密里面,通过公钥加密,使用私钥解密。如果我们要让软件从注册码里面解码出有效时间,难道要在软件里面放私钥?

私钥不能泄露,因此放到软件里面的只能是公钥。但是难道能使用私钥加密,用公钥解密?

实际上,真的可以这样做,但这不叫做私钥加密公钥解密,这叫做私钥签名(sign),公钥验证(verify)。并且,使用这个方法有一个好处,就是有效时间可以直接明文存放,不怕用户修改。因为一旦修改了,签名就匹配不上。

假设我们有一个字符串message,使用私钥,可以对这个字符串进行签名,获得一个签名字符串signature。而我们用公钥,可以验证message是否能够生成签名字符串signature。如果message发生了修改,或者signature发生了修改,或者messagesignature同时发生了修改,公钥验证都会失败。

各个语言都有非对称加密相关的第三方库。我们用Python中的PyCryptodome来进行演示。

首先,我们在macOS下面,生成一对公钥和私钥:

ssh-keygen -t rsa

根据提示输入密钥的储存路径就可以了,如下图所示:

我做了一个App,如何让别人限时使用?

在当前文件夹,生成了私钥sign和公钥sign.pub

接下来,使用pip安装PyCryptodome:

pip install pycryptodome

接下来,导入公钥和私钥:

>>> from Crypto.PublicKey import RSA
>>> with open('sign'as f:
...  private = f.read()
...
>>> with open('sign.pub'as f:
...  public = f.read()
...
>>> private_key = RSA.import_key(private)
>>> public_key = RSA.import_key(public)

由于我们之前生成密钥使用的是SHA256算法,因此我们需要用SHA256算法对需要签名的数据生成摘要。这一步在签名和验证签名的时候都需要做。

>>> from Crypto.Hash import SHA256
>>> digest = SHA256.new()
>>> message = 'expire: 2022-03-01'
>>> digest.update(message.encode())

接下来,对这个数据进行签名:

>>> import base64
>>> from Crypto.Signature import PKCS1_v1_5
>>> signer = PKCS1_v1_5.new(private_key)
>>> code = signer.sign(digest)
>>> signature = base64.b64encode(code)
>>> print(signature.decode())

运行效果如下图所示:

我做了一个App,如何让别人限时使用?

现在,你只需要把字符串expire: 2022-03-01和签名字符串xbelbTNpq8M...很长一串...发送给客户就可以了。

客户把过期时间的字符串和签名字符串输入到软件以后,软件使用公钥来验证这个字符串是不是由自己对应的私钥签名的:

>>> message = 'expire: 2022-03-01'
>>> signature = 'xbelbTNpq8MCFkSxGBoTq7SwQ+oqHRAObrj5p8K2gyY+7uWs5dXGjsQ+GP2XTS5YskCtGjYIBZmAmeM5ey69lRQyk5S1m7t68pYNbUvf3o39Ym0rcmK7XGkBh3euZzVeRErs4JCl7ffTbfcqM4aAsWldDKESrZvaDNQ5DkC8VRYHPBfZfScHqPw/zcHCMRhC9Dch8j9eQlnk8/UKY0MM92jXT4map94PzZRfMLkD4vsciZTtMJm4a42UiiWDUpA6zIgQCYru2YyKspS1uZFE51atYP5DcgPWvJUVRDJS/ZjdPfi9chRjx0dS/Df1sFEreZ7myzXAJP7Y8FA6rvi7EZLlHZ1ViM9tTJp9ut/ZlKgnPAuDCp1JSyKMUk/doVqzUjTqTNHuORe+p3Hhb+xkCASyD8eUH+CyEDVLRcDkSMH5U3o/uONnOQao2o9dbkGiSYNkToElQJ2v20S3MnncPciij8H7iI2dDp1dwt8bkcZOD+E1Tf88LMvRaxB7YnhJ'
>>> digest = SHA256.new()
>>> digest.update(message.encode())
>>> reader = PKCS1_v1_5.new(public_key)
>>> reader.verify(digest, base64.b64decode(signature.encode()))
True

但如果你篡改了message的内容,那么验证就会失败,如下图所示:

我做了一个App,如何让别人限时使用?

软件第一次验证通过以后,就可以把这个过期时间的字符串和签名字符串一起用文件的形式存到硬盘上,每次启动软件的时候都检查一遍。发现合法并且没有过期就正常运行。发现过期了或者不合法就就重新弹出输入注册码的对话框。

转自:https://mp.weixin.qq.com/s/LvXhTj_3OLqK-7kinV9UZg

 

 

 

 

给foobar2000添加快速播放功能,改变foobar的播放速度

看多了网上的视频,可以1.25, 1.5, 2倍速播放,今天在听一个音频时,实在是太慢,所以想把播放的速度搞个倍速播放。

首先需要下载一下foobar的插件Effect DSP,

下载地址在:https://www.foobar2000.org/components/view/foo_dsp_effect

下载后,foobar==>library==>configure==>components==>install 安装

安装后重启一下foobar

启用倍速播放,如图,先将 Tempo Shift 加入到 active DSPs中,然后将要加减的速度调整到你要的数值。

解锁网易云变灰音乐

综合自:https://github.com/Tencent/TencentKona-8

音乐平台的版权之争,相信大家都不陌生,像周杰伦、林俊杰等这样拥有大批量听众的歌手的版权,更是各大平台重点抢夺对象,因为他们可以为平台带来大量的粉丝用户。

这个开源项目火了!直接解锁网易云变灰音乐,谁用谁爽

仅2020年,网易云音乐就大手笔的与数十家版权公司达成了独家合作。如今,坐拥千万级曲库的网易云音乐,却似乎仍难摆脱用户的不满。比如在2018年,网易云突然下架周杰伦的歌曲,就引发众多用户强烈不满,流失大量的音乐用户。
今天,猿妹就和大家分享一个可以解锁网易云音乐客户端变灰歌曲的神器——UnblockNeteaseMusic,可以支持如下特性:
  • 使用 QQ / 虾米 / 百度 / 酷狗 / 酷我 / 咪咕 / JOOX 音源替换变灰歌曲链接 (默认仅启用一、五、六)

  • 为请求增加 X-Real-IP 参数解锁海外限制,支持指定网易云服务器 IP,支持设置上游 HTTP / HTTPS 代理

  • 完整的流量代理功能 (HTTP / HTTPS),可直接作为系统代理 (同时支持 PAC)

UnblockNeteaseMusic支持indows 客户端,UWP 客户端,Android 客户端,Linux 客户端 (1.2 版本以上需要自签证书 MITM,启动客户端需要增加 –ignore-certificate-errors 参数),macOS 客户端(726 版本以上需要自签证书),iOS 客户端(配置 https endpoint 或使用自签证书)和网页版(需要自签证书,需要脚本配合)
说了这么多,还是直接看效果展示吧:
Windows 客户端

这个开源项目火了!直接解锁网易云变灰音乐,谁用谁爽

UWP 客户端

这个开源项目火了!直接解锁网易云变灰音乐,谁用谁爽

Linux 客户端

这个开源项目火了!直接解锁网易云变灰音乐,谁用谁爽

macOS 客户端

这个开源项目火了!直接解锁网易云变灰音乐,谁用谁爽

Android 客户端

这个开源项目火了!直接解锁网易云变灰音乐,谁用谁爽

UnblockNeteaseMusic的安装使用
使用 npx

nbsp;npx @nondanee/unblockneteasemusic
或使用 Docker

nbsp;docker run nondanee/unblockneteasemusic

nbsp;docker-compose up
配置参数

nbsp;unblockneteasemusic -h
usage: unblockneteasemusic [-v] [-p port] [-a address] [-u url] [-f host]
                           [-o source [source ...]] [-t token] [-e url] [-s]
                           [-h]

optional arguments:
  -v, --version                   output the version number
  -p port, --port port            specify server port
  -a address, --address address   specify server host
  -u url, --proxy-url url         request through upstream proxy
  -f host, --force-host host      force the netease server ip
  -o source [source ...], --match-order source [source ...]
                                  set priority of sources
  -t token, --token token         set up proxy authentication
  -e url--endpoint url          replace virtual endpoint with public host
  -s, --strict                    enable proxy limitation
  -h, --help                      output usage information
创建者表示:本项目不提供线上demo,请不要轻易信任使用他人提供的公开代理服务,以免发生安全问题。
使用方法可以选择修改Hosts或者设置代理的方式,自己挑选一种即可。这里和大家介绍设置代理的方法:PAC 自动代理脚本地址 http://<Server Name:PORT>/proxy.pac,全局代理地址填写服务器地址和端口号即可
这个开源项目火了!直接解锁网易云变灰音乐,谁用谁爽
当然代理工具和方法有很多,你也可以使用其他方式。

这个开源项目火了!直接解锁网易云变灰音乐,谁用谁爽

目前,UnblockNeteaseMusic已经在GitHub上标星 13.1K,累计分支 2K(GitHub地址:https://github.com/nondanee/UnblockNeteaseMusic),感兴趣的伙伴们千万别错过了。


10 个有用的软件开发原则

作者 | Kevin Mahoney
来源 | 架构头条

我总结了一些软件开发原则。在这些原则中,大多数都是以简化系统为核心。在我看来,简单的系统会更可靠,更容易修改,而且一般更容易使用。当观念发生改变时,我希望更新它们。

1 剔除无效状态

我把这一点排第一,是因为我认为它是最重要、最强大的原则之一。

你可能在定义类型时听到过这个词,但其实这个原则适用于所有与表示数据相关的地方——例如数据库设计。

它不仅可以减少系统的状态数量(从而变得更简单),还能减少无效状态的数量!你的系统不需要处理这些无效状态,因为它们在你的程序中实际上是不可表示的。

这不只是一个小技巧,它可以极大简化你的系统,并防止出现各种类型的 bug。这有一些例子。

https://kevinmahoney.co.uk/articles/applying-misu/

2 数据一致性让系统更简单

对数据施加一致性规则,减少了系统需要处理的状态数量。这是从上一个原则派生而来的。

定义

这里说的是一致性的普遍含义:即数据遵循某些规则,并且在任意时刻都始终遵循这些规则。这一定义与 ACID 有关,但不要与 CAP 混淆起来了。

规则可以是任何东西,例如,你的信用永远不能变成负数,或者私密的帖子不应该被其他人看到。它不仅限于外键或惟一索引,尽管它们也是有效的规则。

和数据库一样,应用程序也可以通过使用 ACID 事务来加强一致性。如果能在数据库级别强制保持一致性是最好的,但在实际中,对稍微复杂一点的东西来说,这样做并不常见。

实用建议

任何限制或损害一致性的行为都会导致复杂性。这就引出了以下这些实用的建议:

让系统更简单:

  • 更少的数据库 (理想情况下是一个)

  • 规范化,减少冗余数据

  • 一个“好的”数据库设计

  • ACID 事务

  • 更多的数据约束

让系统更复杂:

  • 多个数据库

  • 冗余或非正规化数据

  • 糟糕的数据库设计

  • 较少(或没有)数据约束

当然,有时候让系统变复杂也是有正当理由的,我并不想让复杂性变成一个“肮脏的”词。请参阅后面的一个原则“杀鸡不要用牛刀”。

我认为这个原则是当今软件工程中最被低估的原则之一。一致性问题经常被忽视。很多问题,我敢说大多数问题,基本上都是一致性问题——数据不符合某些期望。

参见附录,了解不一致性是如何导致复杂性的。

https://kevinmahoney.co.uk/articles/my-principles-for-building-software/#appendix-a-inconsistency-results-in-complexity

3 数据设计先行

这个问题,“代码还是数据?”,哪一个在 10 年后更有可能继续存在。

代码可以被丢掉重写,但数据很少会这样。

数据比代码更重要。代码的唯一目的是转换数据。

在设计新系统时,最好先从数据库和数据结构开始,并在此基础上开发代码。要考虑可以在数据上施加的约束并实施它们,理想情况下是通过表示数据的方式进行的。

代码设计是数据设计的下一步。数据模型越简单、越一致,代码就会越简单。

你们把流程图给我看,但把表藏起来,我就一头雾水。你们把表给我看,通常我就不需要你们的流程图,它们会不言自明。—— Fred Brooks

糟糕的程序员关心代码。好的程序员关心数据结构和它们之间的关系。—— Linux 之父 Linus Torvalds

4 杀鸡不要用牛刀

这是软件开发人员最常犯的错误。

这个原则是说,当你在做需要付出复杂性代价的权衡时,要确保权衡的必要性得到经验证据的支持。

常见错误:

  • 试图构建一个复杂的“可伸缩”系统,可以伸缩到你可能永远都不需要的规模。

  • 在不考虑需求或成本的情况下,让服务尽可能地小。

  • 在非性能瓶颈的地方优化性能,增加不一致性或复杂性。

建议:

  • 尽可能从最简单、最正确的系统开始

  • 对性能进行度量

  • 如果不能解决实际问题,就不要付出复杂性代价或违反其他原则。

  • 有些优化可以不进行度量,因为它们的成本非常低或为零。例如,为了保证你想要执行的操作具有你想要的性能,使用正确的数据结构。

  • 的确,有时候经验本身就能告诉你是否做出了正确的权衡。但如果你能证明,那就更好了。

  • 当你必须做出选择时,请选择正确性和简单性,而不是性能。

  • 在某些情况下,正确而简单的代码是性能最好的代码!

真正的问题是程序员在错误的地方和错误的时间花了太多的时间在担心效率上。过早优化是编程中所有(或者至少是大部分)罪恶的根源。——计算机科学家 Donald Knuth

5 避免为了局部简单性而增加全局复杂性

也就是避免为了让系统的一部分变得更简单,而导致整个系统变得更复杂。

这种交换通常是不平等的。追求局部的简单性会导致全局复杂性的增加,而且是数量级的。

例如,使用较小的服务可以让这些服务变得更简单,但一致性的降低和对更多进程间通信的需求让系统变得更加复杂。

6 识别内在的复杂性

有时候事情本身就很复杂,你不能把问题简单化。

任何这样的尝试都只会让系统变得更加复杂。

7 使用的技术越少,系统就越简单

深入理解一小部分技术要比只是表面理解很多技术好。

更少的技术意味着更少的东西要学习和更少的运维复杂性。

8 集中精力学习概念,而不是技术

不要太关心技术的复杂细节,因为你可以随时查阅它们。你要学习底层的基本概念。

技术会变化,概念却是永恒的。你学到的概念将被用在更新的技术中,你就可以更快地学会新技术。

例如,不要太关注 React、Kubernetes、Haskell、Rust 的表面细节。

重点学习:

  • 纯函数式编程

  • 关系型模型

  • 规范的方法

  • 逻辑编程

  • 代数数据类型

  • 类型类 (通用的和特定的)

  • 借位检查器 (仿射 / 线性类型)

  • 依赖类型

  • Curry-Howard 同构

  • 同像性(Homoiconicity)

  • VirtualDOM

  • 线性回归

  • ……

9 代码一致性很重要

有时候,具有一致性的代码比“正确”的代码更重要。如果你想要改变代码库中某些代码的行为,就要修改它所有的实例。否则的话,就只能忍受。

代码的可读性更多地与一致性(而不是简单性)有关。人们通过模式识别来理解代码,所以请重复 (和记录) 模式!

10 分享原则很重要

如果你和队友之间的共同原则越多,就能越好地在一起工作,而且你会越喜欢和他们在一起工作。

11 附录:不一致性导致的复杂性

这是我能想到的最简单的例子,希望能毫不费力地与现实问题联系起来。

假设一个数据库有两个布尔变量 x 和 y,你的应用程序有一个规则,即 x = y,可以通过使用一个事务修改这两个变量来执行这个规则。

如果这个规则被正确执行,那么数据只有两种状态:(x = True,y = True) 或 (x = False,y = False)。

基于这个规则的函数“toggle”就非常简单。你可以读取其中一个值,并将两个值都设置为反向值。

现在,假设你将这两个变量放到不同的数据库中,并且不能再被一起修改,那么会发生什么?

因为你不能确保 x = y 的一致性,所以数据可以有两种以上的状态:(x = True,y = False) 或 (x = False,y = True)。

  • 如果你的系统处于这些状态中的一种,你应该使用哪个值?

  • 当处于其中的一种状态时,“toggle”函数的行为是怎样的?

  • 在写入新值时,如何确保两次写入都成功?

这些问题没有正确的答案。

当然,如果我们一开始就遵循“剔除无效状态”的原则,那么将只有一个变量!

原文链接:https://kevinmahoney.co.uk/articles/my-principles-for-building-software/