分类目录归档:编程

TypeScript + React.FC + Hook

Vue.js的使用更接近传统的Web开发,入门门槛比较低。同时双向数据绑定等特性也让Vue.js更为平易近人。在我看来Vue.js为易用性做的妥协在成就了Vue.js的同时,也制约了Vue.js,让他无法变得“伟大”。

在Node.js、React、Vue.js出现后,整个前端的表现能力越来越强,同时也变的越来越复杂。传统依靠jQuery的开发模式已无法支持现在大型SPA应用的开发。相比Vue.js,React这种高度组件化开发框架才更能代表今后前端的发展方向。

之前也看过一些React的相关教程。我一方面认同React的组件开发理念,另一方面又被React繁琐的开发体验劝退(Ant Design Pro早期版本里的登录实现十分劝退)。

近期有机会实际使用了React一段时间。相比初次接触React,现在的TypeScript + React.FC + Hook似乎才是React的完全形态。

React的高度组件化,让代码结构很自然的变的清晰(当然,过细的拆分也让人头痛)。TypeScript让很多潜在错误可以在编译阶段被发现,而且编辑器也开始变的智能很多。Hook的引入,彻底释放了React.FC的能力。相比Class Components使用Function Components的代码实现要简洁很多。

Carrot Box流程管理平台

django-lb-workflow 我开发的一个Django流程引擎APP。设计之初是以使用便捷性为目标,自带了完整的模板,希望可以方便的集成到已有系统。尽管已经将django-lb-workflow做到尽量的易用,但距离真正的开箱即用还有一段距离。

Carrot Box是一个完整的Django易用,带了权限管理、部门、角色等必要模块,真正的做到开箱即用。通过对Carrot Box的定制可以方便的改造为OA、工单系统、CRM等业务系统。

Carrot Box的主要特点:

  • 是一个完整的应用,可以直接跑起来,开箱即用。
  • 自带HR模块,支持部门、角色的定义。支持按照部门、角色设置权限。
  • 带了几个范例流程,方便熟悉系统。
  • 包含一个代码生成器的使用范例,用于熟悉如果快速的创建一个自定义流程。
  • simplewf模块使用范例,以纯配置的方式添加新流程。

Carrot Box范例站点

之前的django-lb-workflow范例站点已经切换到 Carrot Box

地址: http://wf.haoluobo.com/

管理员账号:admin 密码:password

切换为其他用户: http://wf.haoluobo.com/impersonate/search

退回管理员账号: http://wf.haoluobo.com/impersonate/stop

将Carrot Box跑起来:

make init-pyenv
make init
make run

JetBrains Quest 解谜过程

JetBrains的推广活动,解谜后可以获取三个月的免费订阅。由于是推广活动,所以解密过程不是非常难。真正让人头痛的是那糟糕的网速,不管挂不挂代理页面的打开都非常的慢。

题目一

48 61 76 65 20 79 6f 75 20 73 65 65 6e 20 74 68 65 20 73 6f 75 72 63 65 20 63 6f 64 65 20 6f 66 20 74 68 65 20 4a 65 74 42 72 61 69 6e 73 20 77 65 62 73 69 74 65 3f

解题

很明显字符串的ASCII码,使用python很容易进行解码

>>> s = "48 61 76 65 20 79 6f 75 20 73 65 65 6e 20 74 68 65 20 73 6f 75 72 63 65 20 63 6f 64 65 20 6f 66 20 74 68 65 20 4a 65 74 42 72 61 69 6e 73 20 77 65 62 73 69 74 65 3f"
>>> ''.join(chr(int(e, 16)) for e in s.split(' '))
'Have you seen the source code of the JetBrains website?'

题目二

查看首页源代码找到解谜线索

JetBrains has a lot of products, but there is one that looks like a joke on our Products page, you should start there... (hint: use Chrome Incognito mode)
It’s dangerous to go alone take this key: Good luck! == Jrrg#oxfn$

根据提示,到产品页面。其中名为“JK”的产品介绍是“dare to lean more”,点击该产品继续进行挑战。

注:之前都不知道JetBrains居然已经有这多的产品了。

题目三

补完 https://jb.gg/### 后面确实的三个数字。数字为500到5000的质数个数。

解题

到网上找了个求质数的函数,跑了一下,很快得到结果574

import math
def isprime(n):
    if n < 2:
        return False
    for i in range(2, int(math.sqrt(n)) + 1):
        if n % i == 0:
            return False
    return True
count = 0
for i in range(500, 5000):
    if isprime(i):
        count += 1
print(count)

题目四

打开上面得到的链接,其中有张图片。图片中的字符为“MPS-31816”

解题

这个题目最坑的在于这个图片实在是太大了,约有15M,死活打不开。

  1. 查看图片属性,用编辑器直接打开图片,都没有获取到有效的信息。
  2. 直接访问 https://www.jetbrains.com/MPS-31816 显示没有这个网页。
  3. 于是直接启用Google搜索 MPS-31816 在JetBrains 网站找到对应页面。注:后续会知道图片上的图标是JebBrains网站的问题区的Logo。

题目五

“The key is to think back to the beginning.” – The JetBrains Quest team
Qlfh$#Li#|rx#duh#uhdglqj#wklv#|rx#pxvw#kdyh#zrunhg#rxw#krz#wr#ghfu|sw#lw1#Wklv#lv#rxu#lvvxh#wudfnhu#ghvljqhg#iru#djloh#whdpv1#Lw#lv#iuhh#iru#xs#wr#6#xvhuv#lq#Forxg#dqg#iru#43#xvhuv#lq#Vwdqgdorqh/#vr#li#|rx#zdqw#wr#jlyh#lw#d#jr#lq#|rxu#whdp#wkhq#zh#wrwdoo|#uhfrpphqg#lw1#|rx#kdyh#ilqlvkhg#wkh#iluvw#Txhvw/#qrz#lw“v#wlph#wr#uhghhp#|rxu#iluvw#sul}h1#Wkh#frgh#iru#wkh#iluvw#txhvw#lv#‟WkhGulyhWrGhyhors†1#Jr#wr#wkh#Txhvw#Sdjh#dqg#xvh#wkh#frgh#wr#fodlp#|rxu#sul}h1#kwwsv=22zzz1mhweudlqv1frp2surpr2txhvw2

解题

很明显要用到之前的 take this key: Good luck! == Jrrg#oxfn$ 。我一开始将问题想的太复杂了,以为第一题里的内容是密钥,用xor进行解密。在网上找了个xor解密的函数,解出来一塌糊涂。

由回头仔细看了一下这所谓的密码,其实就是一个简单的字映射。

>>> s = "Qlfh$#Li#|rx#duh#uhdglqj#wklv#|rx#pxvw#kdyh#zrunhg#rxw#krz#wr#ghfu|sw#lw1#Wklv#lv#rxu#lvvxh#wudfnhu#ghvljqhg#iru#djloh#whdpv1#Lw#lv#iuhh#iru#xs#wr#6#xvhuv#lq#Forxg#dq
g#iru#43#xvhuv#lq#Vwdqgdorqh/#vr#li#|rx#zdqw#wr#jlyh#lw#d#jr#lq#|rxu#whdp#wkhq#zh#wrwdoo|#uhfrpphqg#lw1#|rx#kdyh#ilqlvkhg#wkh#iluvw#Txhvw/#qrz#lw“v#wlph#wr#uhghhp#|rxu#iluvw#s
ul}h1#Wkh#frgh#iru#wkh#iluvw#txhvw#lv#‟WkhGulyhWrGhyhors†1#Jr#wr#wkh#Txhvw#Sdjh#dqg#xvh#wkh#frgh#wr#fodlp#|rxu#sul}h1#kwwsv=22zzz1mhweudlqv1frp2surpr2txhvw2"
>>>
>>> c = ord('J') - ord('G')
>>> ''.join(chr(ord(e) - c) for e in s)
'Nice! If you are reading this you must have worked out how to decrypt it. This is our issue tracker designed for agile teams. It is free for up to 3 users in Cloud and for 10
 users in Standalone, so if you want to give it a go in your team then we totally recommend it. you have finished the first Quest, now it’s time to redeem your first prize. Th
e code for the first quest is “TheDriveToDevelop”. Go to the Quest Page and use the code to claim your prize. https://www.jetbrains.com/promo/quest/'

django-lb-workflow 近期更新

前几天又看了一下Django的Class-based views,想着django-lb-workflow的一些设计似乎还需要优化一下,于是又去折腾了一下django-lb-workflow。

Class-based views提高了代码的复用性,但过多的Mixin和继承层次让代码变的不那么容易理解。而且在面对一些“特殊”需求时会变的有些别扭。

一个列表界面搭配一个查询表单是一个很常见的操作,但想要在Django默认的ListView里添加这个查询Form并不太容易。在ListView里通过重载get_queryset方法修改查询内容。通过重载get_context_data修改context内容。按照我的理解合理的方式应当是在get_queryset函数中创建form,在form校验成功后使用form的参数作为查询条件返回查询后的queryset。但get_queryset无法直接同get_context_data函数打交道,必须先将 self.form = form 在到get_context_data中通过self.form来获取form信息。这个过程变的非常不直观和奇怪。最终我还是选择不直接继承ListView,在自定义的ListView中重载get函数,在get函数中处理form和查询。

主要更新

  • 增加“添加会签人”的功能。只有在被加签的人处理完成后,流程才可以流转到下一节点。
  • 去掉 django-el-pagination,使用Django自带的分页功能。
  • 为简化系统使用,增加 simplewf 模块。对于只有一个事项名称和内容的流程,可以不写任何代码,只需要在系统中配置流程节点。

待解决的一些问题

做了上面一些更新后,对这个项目又开始有些倦怠了。下面的这些问题可能要等到下次再对这个项目提起兴趣的时候了。

  • 流程的查看、编辑等权限通过在settings里配置校验函数实现。事实上并不太直观,操作性上也不是特别好。更合理的方式还是将权限控制这部分也放到 Class-based views 中,可以通过Minxin灵活配置。注:Django REST framework权限部分的设计比较完善,相关代码可以直接移植过来。
  • 目前还不支持Django 3.0。Django 3.0移除了部分兼容性代码,导致系统跑不起来。
  • 文档…

Telegram机器人

最近重新开始玩Ingress。好多年没玩,主要玩家已由QQ转战Telegram了。还有玩家专门为Telegram做了个Bot用来做新人接待、面基统计等相关工作。稍微研究了一下Telegram的Bot实现,发现Telegram API功能非常强大,而且使用起来也很简单,可以轻易的做出自己的机器人。

如果你想更多的了解Telegram Bot可以做什么,怎么创建一个自己的Bot建议阅读Telegram的官方文档 Bots: An introduction for developers。如果你和我一样使用Python进行开发,可以使用python-telegram-bot进行开发。

让Telegram Bot主动推送消息

一般情况下Bot都是在接收到用户的命令后被动的回复信息,如果希望机器人主动推送消息可以先手动查询chat id,然后Bot发送消息时指定为该chat id。获取chat id的方法如下:

  1. 和机器人对话。如果希望获取group的id,这需要先将机器人加到group,再@bot /xxx给机器人发消息。
  2. 访问 https://api.telegram.org/bot<YourBOTToken>/getUpdates获取消息。
  3. 访问getUpdates接口后将得到一组JSON数据,里面哪个是chat id还是比较容易识别出来的。

一个简单的机器人实例

发送命令51job,这个机器人会调用jobmonitor检查51job的岗位更新情况。

import logging
from telegram.ext import Updater, CommandHandler
from telegram.ext.dispatcher import run_async
from job import qcwy as job_qcwy
TOKEN = 'XXX'
# Enable logging
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
                    level=logging.INFO)
logger = logging.getLogger(__name__)
@run_async
def start(bot, update):
    """Send a message when the command /help is issued."""
    bot.send_message(
        chat_id=update.message.chat_id,
        text="Hi! I'm vicalloy's Bot. \r\n"
        "/51job update 51job. n"
    )
@run_async
def qcwy(bot, update):
    # 为防止其他人恶意向机器人发送信息触发该命令,这里还需要对发送人做个判断,只响应特定用户的请求。
    job_qcwy()
def error(bot, update):
    """Log Errors caused by Updates."""
    logger.warning('Update "%s" caused error "%s"', bot, update.error)
def main():
    updater = Updater(TOKEN)
    dp = updater.dispatcher
    dp.add_handler(CommandHandler("start", start))
    dp.add_handler(CommandHandler("help", start))
    dp.add_handler(CommandHandler("51job", qcwy))
    dp.add_error_handler(error)
    updater.start_polling()
    updater.idle()
if __name__ == '__main__':
    main()

挖了一个新坑-Django的工作流引擎

Python和Java相比资源的丰富程度还是要差非常多。就如工作流引擎,Java下商业和开源实现都非常多,Python的就要少很多。因为工作的关系,当初将Python下的开源工作流引擎研究了一遍,始终没有找到合适的解决方案。最终系统中的工作流模块还是自己开发的。

近来决定挖个新坑,开源一个工作流引擎。我希望这是一个认真的开源项目,也希望这个项目能帮忙有相关需求的人解决具体问题。作为一个认真的开源项目,除保证代码质量外,单元测试,文档也都将是必须的。预计这个项目的工作量会有些大,前前后后应当会持续挺长一段时间,希望不要烂尾了。

目前已经开始码代码了,如果感兴趣可以先过去看看: https://github.com/vicalloy/django-lb-workflow

关于这个项目

  • 基于Django且完全不考虑移植到其他框架。
    • 如果考虑移植性系统要复杂很多,也很难保证易用性。
  • 采用半可配置方案以平衡开发及使用的便利性。(注:“半可配置”是我自己取的名字)
    • 数据模型,表单布局,数据校验规则,特殊处理采用编码方式实现。
      • 这部分如要做灵活可配置,配置工具的开发会非常复杂,且配置项非常多,在具体配置的时候也会很麻烦。
      • 这部分功能在开发后改动的情况较少,使用代码实现要灵活的多。
    • 流程节点,审批人,流转关系采用配置方式实现。在管理后台直接通过管理界面进行配置。
      • 根据公司规定,组织结构的变更流程的流转规则,审批人的变动较为频繁,使用代码实现很不灵活,也不方便。
      • 流程节点及节点间的流转这对各类型的流程来说操作都是比较一致的,比较容易采用配置的方式实现。
      • 使用配置实现可以方面的自动画出流程图。
    • 代码生成器
      • 提供代码生成器,只需要完成数据模型的编码,代码生成器会自动生成流程的提交/查看/报表等所有框架代码。

最好的技术构架

最近看到一篇文章,里面谈通过Java替换之前的Python实现使服务的响应速度得到了很大的提升。同时又看到有公司通过Go替换Scala,取得了不错的效果。

似乎是Go>Java>Python?显然不是。

在项目启动的初期你很难预计到自己的项目最终将长成什么样子,最终能达到多大的规模。你能做的只是给出一个较清晰的中短期规划以及一个较模糊的长期规划。然后思考如何在满足要求的情况下尽快的把东西做出来。毕竟事情不会不完全按照你的预期发展,看上去在完美的构架也不可能一直完美下去。根据需求持续的演进才是正道。

关于性能:

由于需要服务海量用户,因此在提到互联网应用的时候很多人都对高性能有着异常的执着。经常听到有人说XX语言慢,XX框架慢。但实际上脱离了需求和构架单纯谈的语言/框架性能是没有意义的。就如Instagram至今依旧用着以慢著称的Django(注:其实我也挺好奇为啥没有将Django换掉。按照我的理解Django的有点是功能及资源丰富,性能方面确实没啥优势。按说Instagram对Web框架的功能需求应当非常少,换个更轻量高效的似乎会更好些?)。

另外优化的成本实际上也挺高,在早期用户不多的时候对性能的优化或许还不如直接加硬件来的实惠。

Django 2.0放弃Python 2的支持了

Django的master分支已经正式切换到Django 2.0了,其中的一个commit就是去掉Python 2支持的相关代码。这意味着从Django 2.0开始,Django将要放弃Python 2.x的支持。
对于这个消息,Reddit上一片喜大普奔。对我而言这绝对是一个好消息,毕竟我还是非常喜欢Python 3的type hints。如果放弃Python 2的支持,他们还是很有希望会加入type hints的支持。
从去年开始,不少最新的Python库只支持Python 3。另外type hints加入让甚至可以说让Python更像一个新的语言。或许Python 2终于要开始淘汰出局了。对我而言,除了老项目的维护外,新项目似乎没有什么理由再支持Python 2。

注:根据Reddit上的回复,由于model里用了太多的magic,model这部分要加入type hints还有很多问题要解决。不过可以肯定的是type hints绝对会是今后Python库的大方向,Django也是会支持的。

Python 3的type hints

近年来新出的语言Go、Rust、Swift都无疑例外的是静态类型。随着软件的越来越复杂,动态语言“太过随意”的缺点也越来越明显。此外随着IDE的发展,静态类型语言“繁琐”的缺点也得到了很好的规避。
在学习Swift的时候,Swift的类型推导给了留下了很深的印象。类型推导或许是现阶段兼顾类型检查以及动态语言简洁的最佳解决方案。
Python从3.5开始加入了type hints(类型注释)。

def greeting(name: str) -> str:
    return 'Hello ' + name

从名字“type hints”就可以看出,只是类型注释并不是强制要求。由于只是“注释”,“type hints”需要第三方工具的配合。你需要使用Mypy来对代码进行语法检查。另外PyCharm在新版本中也加入了对“type hints”的支持。

对我而言“type hints”无疑是一个非常棒的特性,让Python也具备了类似Swift的类型推导功能。希望日后的各类Python都能加入type hints的支持。另外就希望各类开发工具可以充分的利用type hints特性。

注:
Swift中使用“?”表示option,Python里则需要写成Optional[str]相比之下有些太过繁琐。

Docker

很早之前就听过Docker,当时感觉对个人使用而言Docker似乎派不是太大的用场。

  • Docker非常类似虚拟机。如果单纯出于统一开发环境的考虑,直接用虚拟机似乎还更直接一些。
  • 虚拟机+ Vagrant也可以方便的对虚拟环境进行管理,Docker在这方面似乎也木太占优势。
  • Docker通过仓库分发Images,似乎同直接复制虚拟机的镜像效果也差不了太多。
  • 由于并不需要管理大量的服务器,直接手动部署或用部署工具操作也不会太过复杂。用Docker还得学习Docker的使用,似乎也不太值得。

近期由于Discourse的缘故,实际用了一下Docker。感觉Docker确实是个不错的东西,不论是开发还是运维Docker都是值得使用的。

Docker有啥好处

  • Puppet, Chef等传统的运维工具可以实现应用的批量以及自动化的部署。但实际工作中,用户的系统千差万别,可能换个系统环境你的脚本就挂了。
  • 对开发人员,可以使用统一的虚拟机作为开发环境。但虚拟机无法直接部署到生产环境。生产环境、测试环境、生产环境无法做到统一。很可能开发环境跑的好好的,一到生产环境就出各类莫名其妙的问题。
  • Docker 容器的启动可以在秒级实现,这相比传统的虚拟机方式要快得多。 其次,Docker 对系统资源的利用率很高,一台主机上可以同时运行数千个 Docker 容器。
  • 使用Docker可做到“各类环境”的完全统一。不论用户原始的环境是什么,真正跑应用的环境都是一样的。由于在开发阶段就已经把环境完全整好了,只需要简单的几个命令即可完成部署,Docker的部署异常简单。由于不用考虑系统的差异,Dockerfile写起来相对来是比较简单的。

相关资源