Hello World - 方法论
type: channel
link: http://blog.38data.com/index.php/category/method/
items: 一些心得，不定期更新[2025-11]
items: 管理心得，不间断记录
items: 软件架构师应该知道的97件事之概括
items: 新项目别一上来就用微服务
items: 一人公司方法论
items: 软件外包思考 二 验收
items: 软件外包思考 一
items: 亲测推荐 2021 年 SaaS 技术栈：Docker、Django、Traefik 和 IntercoolerJS
items: 我成功开发了一个 SaaS 项目，技术栈是这样的
items: 写代码有这16个好习惯，可以减少80%非业务的bug

一些心得，不定期更新[2025-11]
type: item
date: 2023-11-20T14:50:00+08:00
description: 只要利益不发生冲突，别人说话一般不要去反驳。人际交往的高段位技巧，热情大方，一问三不知。你真正要做的事，连神明都不要讲，安静的做成功了再说，是以秘城，言以懈息。努力克制自己的情绪，学会赞美和闭嘴。给别人办事，一定要装的很难办，给领导送礼一定要装的很自然，给爱人花钱，一定要装得很痛快，请别人吃饭，一定要装得很大气，和人谈生意，一定要装得很成功，和人谈感情，一定要装得很纯洁，和人谈工作，一定要装得很专业，不能喝酒时，一定要装得很醉，不能赴约时,一定要装得很失落，不能帮忙时，一定要装的很难过。做人一定要有城府，逢人只说三分话，不可全抛一片心。你要是想看透人心，只需要落魄一次就够了。也为人在落魄的时候，身边的牛鬼蛇神都会露出真实面目。德不配位，财不配身，怎么破，很简单，就是习惯它，升官了，静默半年别折腾，赚钱了，放手里半年不花，就行了。处理问题，包括应急事件，狭路相逢和退一步海阔天空都不可取，通用的是沉默是金和让子弹飞，有奇效。刷视频，多看看打架斗殴、车祸集锦、意外身亡的，危机意识和避险意识会潜移默化。多读历史，人虽然会变得冷漠，但是能够提高生存能力，你死我活才是本质。社会感悟1、改命 选妻2、成事 借势3、立威 沉默4、服众 果断5、上位 贵人6、守业 制衡7、破局 舍弃8、避祸 低调9、谈判 底牌10、止损 狠心11、见识 远行12、人脉 主动13、机遇 胆识14、平安 示弱15、信任 靠谱16、人心 让利17、赚钱 信息差18、藏锋 糊涂19、人性 吃亏20、长久 后路买房要点1、判断房主是否着急售卖 看挂牌周期、降价记录； #调研#客观情况#时机2、不谈缺点，只说适合，表达想要； #输出#同理心3、哭穷，借的、经济不景气； #输出#同情心4、不说心理价位，只说越便宜越好； #输出#博弈5、与人打交道，心理博弈，让别人舒服； #方法论

管理心得，不间断记录
type: item
date: 2022-09-18T18:17:00+08:00
description: 兼职管理1、响应时间 微信响应时间 超过5分钟 2次 中止合作2、培养能力 经验、工具3、收益高于预期4、工程师和质量关于裁员裁员名单是根据个人在公司工作期间对代码的贡献来制定和排名的。高效工作总结：0、必胜信心1、结果导向2、完成时间3、物理专注公司管理思路：互相投资、互相信任，非传统主雇关系1、培养人，把能力传授给下面的人2、放权3、分享机制小团队项目组基本管理：1、放手，新问题主动处理、老问题交给下属处理，借此制定标准处理问题流程化；2、榜样，有困难主动承担、有问题主动冲锋；3、让功让利，向上让功、向下让利；温和派领导人管理思路：1、立功，对公司有贡献；2、握权，能够影响员工收入组成40%、考核评分、项目奖金；3、守信，不轻易承诺、一旦承诺必须兑现；4、立标杆，培养典型员工进步并树立标杆；团队凝聚力1、身先士卒，带动员工积极性；2、知人善任，用人长处；3、勇于背锅；4、尊重、感谢，公约机制；提高员工工作效率1、责任到人；2、限定时间；3、确定标准；4、重复一次；5、检查机制；6、验收考核；老版轻松X成就感V想明白，布置下去1、会算账，不算公司赚多少钱、算员工能赚多少钱；2、会画饼，公司壮大时候做到位置、发展前景；3、会激发，你是专家我不行、顶梁柱；

软件架构师应该知道的97件事之概括
type: item
date: 2022-05-15T21:49:00+08:00
description: 架构师是一种神秘的职位，据说每个架构师都有密不可传的方法，当然我们不信，更多的是只可意会不可言传。就是说了我们也不会懂，因为还每到“火候”。所能做的就是，当我们到这种火候的时候我们能想起来曾经有过架构师这么说过，然后我们就可以更自信的向前大步走....1、客户需求重于个人简历要想拥有漂亮的个人简历：我们常常向客户推荐技术、手段，甚至方法论来解决问题，使用时髦的编程技巧和流行的范式，有时候根本不是寻求解决问题的最佳方案。积累一批满意的客户，选择切合实际的技术解决他们的难题，让他们乐于推荐你才是最好的履历。2、简化根本复杂性，消除偶发复杂性根本复杂性指的是与生俱来的、无法避免的困难。比如，协调全国的空中交通就是一个“天生的”复杂问题，必须实时跟踪每架飞机的位置。偶发复杂性：是人们解决根本复杂性的过程中衍生的。架构师的责任在于解决问题的根本复杂性，同时避免引入偶发复杂性。怎么做？尽量选择源自实际项目的框架，警惕那些象牙塔里面的产品。3、关键问题可能不是出在技术上简单的项目也会翻船，而且这不是个别情况。大多数项目是人完成的，人才是项目成败与否的基础。如果团队里有人工作方式不正确，拖项目后腿怎么办？有一种非常古老但很完善的技术可以帮助你解决问题。它可能是人类历史上最重要的技术创新，这就是对话。有几个简单的对话技巧可以显著改善对话效果：不要把对话当成对抗。不要带着情绪与人沟通。尝试通过沟通设置共同的目标。4、以沟通为中心，坚持简明清晰的表达方式和开明的领导风格沟通必须简明清晰，没有人愿意阅读冗长的架构决策文档，架构师言简意赅的表达观点是项目成功的必要条件。架构师往往忽略了自己也是领导者。作为领导者我们必须获得同伴的尊敬才能顺利开展工作。所有的成员都希望有明确的沟通和开明的领导。只能这样才能改善沟通效果，建立团结健康的工作环境。5、架构决定性能大家似乎理解，事实并未如此，有些架构师认为简单的更换底层架构就足以解决应用的性能问题，他们很可能轻信了“经测试产品性能超出竞争对手25%”，比如从4ms到3ms，这1ms放在一个性能极低的架构里几乎可以忽略不计。归根结底，所有产品和架构必须遵循分布式计算和物理学的基本原理：运行应用和产品的计算机性能有限，通过物理连接和逻辑协议实现的通信必然有延时。因此，应该承认架构才是影响应用性能和可伸缩性的决定因素。性能参数是无法简单的通过更换软件，或者“调优”底层软件架构来改善的，我们必须在架构的设计和重新设计上投入更多的精力。6、分析客户需求背后的意义顾客和最终用户通常提出的所谓需求，只是他们心目中可行的解决方案，并不是问题唯一的解决途径，当了解顾客的需求背后的意义，我们可以为顾客解决真正的问题并可能降低难度。7、起立发言许多架构师都是从技术岗位上成长起来的，他们擅长和机器打交道，然而架构师更需要与人打交道，无论劝说开发人员接受具体的设计模式，还是向管理层解释购买中间件的利弊，沟通都是达成目标的核心技能。有经验的架构师会很重视推销自己的想法也明白有效沟通的重要性，其中一个简单又实用的技巧是在2人以上的场合发表意见时请“站起来”，起立发言非常重要尤其是当其他人坐着的时候。当你站起来的时候无形中添加一种权威和自信，自然就控制住了场面，听众不会随意打断你的发言，这些都会让你的发言效果大为改观，你会发现站立可以更好的用双手和肢体语言。在10人以上的场合，起立发言方便你与每位听众保持视线接触。眼神交流、肢体语言等表达方式在沟通中的作用不可小觑。起立发言还可以让你更好的控制语气、语调、语速和嗓门，让你的声音传的更远。当你讲到重点内容时，注意放慢语速。发声技巧也能显著改善沟通效果。比沟通事半功倍，起立发言是最简单、有效的方法。8、故障终究会发生硬件会出错，于是我们增加冗余资源来提升系统的可靠性，同时也增加了至少有一台设备出错的概率。软件会出错，增加额外的监控程序也会出错。于是我们又为自动化增加监控，结果是更多的软件，导致更高的故障率。类似的如：三里岛核电站泄漏事故既然必然会出错就需要事先设计好防范故障的模型，以应对威胁系统安全的意外情况。9、我们常常忽略自己在谈判我们都面临过削减预算的要求，如果资金运转促襟见肘，技术方案只能委屈求全。比如如下情景：“我们真的需要这东西吗？”项目投资人发难道。尽管真的需要，我们通常也不能这么回答，因为此时我们是在谈判，此时我们需要认清自己的角色，不能把自己当成工程师，而且投资人明白他在和你谈判，我们应该这样回答"真的需要吗"这类问题：“单台服务器每天至少崩溃3次，没有第二台我们甚至无法跟董事会演示，事实上我们需要4台服务器，构成2组，这样在需要时断开一组而不必被迫关闭系统。即使有一台出现意外，也不影响系统正常运行”10、量化需求速度快不能算作需求，响应灵敏和可扩展也不能算需求，因为我们无法客观…

新项目别一上来就用微服务
type: item
date: 2022-02-13T14:17:33+08:00
description: 微服务变得越来越理所当然，似乎我们一直生活在微服务的世界中。很多时候，我们常常讨论微服务采用与否、如何选型等问题。但本文作者 Arnold Galovics 想讨论的是，为什么一个全新的项目从开始就使用微服务通常是个坏主意。很长一段时间以来，他都在思考这个问题。最近，当他与其他开发人员交谈并询问他们如何启动一个全新项目时，答案几乎都是：这儿用一个微服务，那儿用一个微服务，用户管理用一个微服务，身份验证用一个微服务，鉴权用一个微服务，session 管理用一个微服务等等。因此，关于微服务，Arnold 想基于他过去工作项目的一手经验，讲讲别人没有讲过的一些东西，他撰写了一篇题为《不要从微服务开始，单体架构才是你的朋友》（Don’t Start With Microservices – Monoliths Are Your Friend）的文章。Arnold 的文章很快在技术社区引发热议。有持赞同意见的人直言，微服务对于大多数普通需求来说是一种“矫枉过正”，还有人提出微服务有个 Arnold 没提到的更严重的缺点——将事情分成模块需要时间，并且涉及做出我们可能不知道答案的决定。“启动新产品时，最重要的是尽快启动并运行产品，以便人们可以试用并提供反馈。而根据收到的反馈，我们往往可能会意识到需要构建与现有的完全不同的东西。我见过很多工程劣质的成功产品，也见过很多设计精良的产品失败。产品的成功与其设计的好坏无关。速度往往是最重要的因素。”另外，有条热门评论提出了个有意思的问题：为什么没有人谈论介于这两者之间的架构——模块化单体？对此，有回复说道“因为没有新发明的架构称为‘模块化单体’——单体从一开始就应该是模块化的。”该回复进一步指出，微服务不是单体应用不好而诞生的答案，人们的理解在某些地方出现了问题，这也可能是因为很多人不知道应该在代码中构建模块，然后大量的单体最终成为“意大利面条式”代码，就像现在许多微服务架构那样。有人对此表示赞同并表示，“模块化单体”只是“代码中关注点的适当分离”，其实从一开始就存在。但也有人提出反对意见，认为“模块化单体”要比“分离关注点”要更复杂，并不完全是一回事。一千个人眼中有一千个哈姆雷特，我们将 Arnold Galovic 的这篇文章翻译出来，希望能为读者带来一些参考价值。以下是他的分享内容：理想中的微服务我们先来看看，多数文章提到的一些微服务的主要优势有哪些：故障隔离消除技术锁定更容易理解更快的部署可伸缩性是的，这些都不是书中的虚假承诺，但我也必须对你说实话，使用微服务的话，你的系统很难实现这些承诺。下面让我一一列举这些优势。故障隔离。由于应用程序由多个服务组成，因此如果其中一个服务宕机或出现问题，则只会影响系统的那个部分。以 Netflix 为例，当你观看节目时，你并不关心推荐。因此，如果它们有一个服务来处理当前观众，为他们提供视频流；它们有另一个服务来处理个人用户推荐。如果推荐服务宕机，系统中最重要的功能（例如观看节目）不会受到影响。故障被隔离了。消除技术锁定。想想单体应用。它是一个巨大的应用程序，有成百上千个 API，管理数百个数据库表。这个应用程序是用 Java 写的，团队花了 5 年时间开发它。一种奇特的新语言出现了，纸面上带来更好的性能、提供更好的安全性等等。这可能是 Go 或 Rust，团队想试验下该语言及其技术栈。他们如何在一个单体应用中做到这一点呢？他们做不到，因为这是一个单独的部署包。你可以将应用程序的一部分切换到不同的语言，但这并不容易做到。使用微服务时，不同的服务可以使用不同的技术栈。服务 A 可以用 Java 写，服务 B 可以用 Go 写，服务 C 可以用Whitespace写，如果你有勇气这么做的话。更容易理解。当你有多个服务负责整个功能的一小部分时，这个服务本质上会更小，因此更容易理解。更快的部署。在常规的单体应用系统中，要么完全部署，要么根本不部署。你需要部署一个包，这是一个要么全有要么全无的场景。使用微服务，你有机会独立部署，这意味着，如果你想要部署推荐服务的一次升级（回到 Netflix 的例子），你可以部署单个服务并节省大量时间。可伸缩性。我的最爱。你可以通过启动多个实例来增加特定功能的容量，从而扩展服务。像前面举的例子，如果人们在 Netflix 上查看大量推荐，它们可以很容易地启动多个推荐服务的实例来应对负载。在单体应用环境中，你要么扩展应用程序的每一个部分，要么什么都不扩展。现实生活中的微服务我要用残酷的事实打击你，我的朋友。我并不是说这些优势无法实现，但是你、你的项目、你的组织必须非常努力才有可能实现这些优势。基础设施要求下面让我从微服务的一个最大困难——基础设施开始讲起。绝对是 10 r6g 的真实照片。在 K8S 上运行的单个登录应用程序的 16x…

一人公司方法论
type: item
date: 2022-02-07T21:55:00+08:00
description: 作者和授权信息本文由 Easy 撰写。Weibo: https://weibo.com/easyTwitter: https://twitter.com/easychenYoutube: https://www.youtube.com/c/Easychen(欢迎大家关注和订阅，等 Youtube 订阅过 1000 ，我会试试制作本方法论的视频版)本文在 cc-by-nc-sa 协议发布。您可以复制、发行、展览、表演、放映、广播或通过信息网络传播本作品，但必须署名作者并添加链接到本文。不得为商业目的而使用本作品。仅在遵守与本作品相同的许可条款下，您才能散布由本作品产生的派生作品为什么有这篇文章不管是独立开发还是IT课程，一个人做业务也好几年了，最近开始回过头整理通过实践获得的认知，并尝试将其梳理为一个方法论。当然这个体系还不完善，但一直没有找到同一个方向又更为完善的。所以不如自己来整理和维护，对自己而言可以定期回顾修正，读过的大家也可以来参与补充。什么是一人公司这个方法论，我把它叫做「一人公司方法论」。那首先什么是「一人公司」呢？字面的理解就是一个人运营的公司，但实际上它指代的是比较少的人运营的小公司，一般来说1~3个人运营的公司，也可以把它放到一人公司的范围以内。其他一些形式，比如说一个人再加上很多的兼职一块运营的公司，其实也可以看成一人公司。所以从人数上来定义一个公司，实际上并不是很准确。我更喜欢另外一个层面的定义：「 一人公司就是建立在个人品牌之上的公司。」这个定义更为准确，它是说整个公司的业务和品牌影响力都主要源于基于一个人。它周围可能有一些辅助运营的团队，有一些外包、有一些兼职，甚至全职助理的角色，那也是一人公司。为什么要单独来观察这一类公司呢？因为我觉得它是以个体创造财富的典型。之前我翻译过一篇趋势报告，叫做「百万美金的一人公司」。说的就是越来越多的一人公司，可以做到百万美金的价值。当然，直接盈利达到百万美金的不多，但是以 100 万美金估值卖掉的却不少，而且正变得越来越多。一人公司的特点优点下面我们来看看一人公司的特点。先看优点。第一个显而易见的优点就是成本低。因为整个公司只有一个人，所以无需办公场所等硬性成本；也没有长期雇员，所以它没有固定人工成本。这里需要注意，固定人工成本，实际上是一个会引入风险的成本。很多程序员创业副业喜欢做外包，但是如果你做一家外包公司，就会纠结于固定人工成本。比如在你规模小的时候，接到几个大单子，就需要扩展人员来完成开发。但是如果做完这些项目以后，接不到同样数量的活，你还却依然需要支付同样的薪资来维持团队。这就成为了一个很高的风险。你又不能把员工开掉，下次需要时再招。先不说这样干下次还能不能招到人，每次团队磨合和培养的成本就非常高。回到低成本上来，因为你只有一个人，你不需要协同，所以没有沟通成本，很多事情可以保质保量的快速完成。再一个，因为你没有团队，个人的话，想在哪个城市就可以在哪个城市。现在一些新一线和二线城市的生活成本非常低，生活环境也非常舒适，如果可以把业务放在一线城市，然后生活在其他城市的话，不但生活成本低，而且生活品质反而会得到提高，这也是一个非常划算的地方。因为成本低，相应的对收入的压力就小。一个每月只能挣 10 万的业务，对大公司来讲可能成本都收不回来，但对于一人公司来讲，去掉成本和税都是自己的，很可能可以活得挺滋润。也正是因为存在这些结构性的市场空白，才让一人公司可以存在并得到发展。缺点一个人的精力是有限的说完优点，下面我们来说一下缺点。首先就是一个人的时间和精力是非常有限的。因为如果我们一天工作10个小时，一周工作5天，那一周其实就50个小时的工作时间。如果把这50个小时的工作时间均摊到各种要做的事情上边，就会发现其实每一件事都分不了太多时间，这会造成整体业务进展慢。同时，因为就一个人，所以必须在多种业务之间来回切换，这会带来一些额外成本。比如说我们正在编程、正在做架构设计的时候，是在进行深度思考，如果这时候有一些紧急但不重要的事情插入进来，就会把我们从深度思考中拉出来，之后需要再花很多时间才能重新进入到这个状态里边去，甚至可能再也回不到当时的状态，从而丢失掉一些很好的想法。尤其是对一些创造性高的工作来讲，这是非常可惜的。一个人需要做全部事第二个缺点就是，一人公司往往要求我们一个人把整个链条上的所有事情都做了。原因很简单，因为整个公司就你一个人，你不做就没有人做。这样带来的一个非常明显的问题，就是工作量的大额增加。即使很多没有难度的事情，处理细节也会消耗大量的时间。另外还有一个更严重的问题，「麻雀虽小、五脏俱全」。它不但要求工作量，还对技能有要求。如果你缺乏特定的技能，就需要投入上百个小时的学习时间，而且还不一定能学得好。更有一些大型公司具有的资源，一人公司可能是不具…

软件外包思考 二 验收
type: item
date: 2021-07-20T09:27:00+08:00
description: 交付物软件100%实现需求明细列表所有功能，即100%满足业务需求的软件。文档项目验收验收方式1、将要交付的软件安装于指定服务器，并完成调试和上线；2、完成培训后，业务验收人员根据需求明细列表实现情况进行验收评价，研发验收人员根据以下内容进行验收评价。文档验收1、文档齐全（参考如上文档清单）；2、文档内容描述准确, 没有歧义和错误的表达；3、文档内容容易理解, 通过使用适当的术语、图形表示、详细的解释来表达；4、文档对主要功能和关键操作尽量提供应用实例。界面验收1、界面设计符合自己公司的设计规范；2、外包团队需提供与软件适配的浏览器、手机、PAD等品牌与版本号清单；3、各界面需要做好PC、手机、PAD等UI兼容与机器适配；4、原则上，浏览器至少需适配Chrome、Safari、火狐、IE8以上；5、原则上，手机至少需适配苹果、小米、华为、vivo、OPPO、三星、魅族。功能验收1、功能验收范围覆盖（接口、数据库存取、页面功能）；2、提供单元测试用例、集成测试用例和系统测试用例；3、提供BUG管理跟踪记录表；4、提供质量分析报告。性能验收1、提供性能测试报告；2、相关重要指标达到以下要求：安全验收1、软件中的敏感数据需以密文方式存储；2、软件需有留痕功能，即保存用户的操作日志、系统异常日志、接口调用数据日志等；3、软件中各种用户的权限分配合理；4、扫描出的安全漏洞（包含但不限于：越权访问、XSS跨站攻击、SQL注入、文件上传漏洞、跨站请求伪造等）外包团队需修复完毕。用户验收1、外包团队需提供稳定的用户验收环境和联调环境；2、业务场景功能测试不通过数的比例<1.5%；3、不存在严重等级为1的错误；4、不存在严重等级为2的错误；5、严重等级为3的错误数量≤5；6、所有提交的问题都已得到修复；7、以上功能，用户验收测试通过后，由用户负责人签署验收通过确认书。源码交接如涉及到源码交接，按下列规范进行验收和交接。交接前提条件1、需提供用户验收通过确认书；2、涉及交接的软件，原则上建议接受交接软件所有功能，不建议交接软件部分功能模块；3、跟薪资类无关的软件或功能，所有功能需在线上稳定运行不少于3个月；跟薪资类相关的软件或功能，所有功能需在线上稳定运行不少于6个月；4、线上稳定运行既线上可用率，需满足：最近3至6个月内，线上没有出现影响20人以上或数据错误的严重bug，且每月线上bug数不超过3个。源码验收1、代码应只保留跟本项目相关的代码，无效代码应一律去除；2、数据库应只保留跟本项目相关的表、视图、存储过程、函数、触发器、定时job等，无效内容应一律去除；3、特别注意合理做好数据表结构设计，适当冗余提升性能；4、代码结构清晰无冗余，注释完整有效，避免硬编码；5、但凡不符合源码验收规范的，外包团队需修复完毕。其他注意点1、对于外包团队的软硬件选型，建议业务部门邀请本公司IT团队一起参与决策；2、与外包团队商签署的商务合同和补充协议等，建议业务部门邀请本公司IT团队一起参与制定；3、外包团队使用的环境、数据库、网络、语言、框架、技术、组件等需事先获得本公司IT团队认可；4、如外包项目不符合或无法满足上述验收规范的，建议商务层面延长付款周期、扣除相应款项或终止合同；5、每一笔合同款在支付给外包团队之前，除了需获得用户验收通过确认书之外，还应通过IT团队验收；6、以上内容建议附加进商务合同，成为其中一部分。

软件外包思考 一
type: item
date: 2021-07-04T22:26:00+08:00
description: 软件外包存在风险，外包人员技术、态度、交付能力，如果想通过合同或者诉讼降低风险，由于太多的未知因素和太多的主观性，不现实。因此唯一的外包原则应该是：如果外包人员做得不好，有能力随时终止合作且可控费用损失和项目交付。可以尝试渐进式方法，首先废除传统开发外包大瀑布方式（例如签订需求URS、项目总金额、进度款支付）（不过目前大部分外包会坚持使用瀑布法，并签订大额的预付合同），尝试新方案，项目按照功能或者阶段划分为多个子合同，做小项分包，或者改为签订人力外包合同。针对我们想要构建的功能，拟定一个顺序列表。找几名开发人员，最好是独立的自由职业者，但如果同意以下流程，开发工作室也没问题。对于每名开发人员，挑选列表中最重要的功能，与他们讨论功能需求、预算和成本。让他们实现那个特性并测试。让一名内部人员审核他们的 PR，测试升级后的 App，并标出有问题的地方。符合要求后，合并并部署该特性，这样，所有创始人/用户就可以继续审核该 App，并提供反馈或者根据需要调整。如果我们对他们所做的工作感到满意，就挑选下一个我们希望他们实现的功能，然后再次重复这个过程。如果我们对他们的工作不满意，就解雇他们，并寻找替代者。当前需要做的工作，整理敏捷开发平台或者公共开发平台，并且参照以下原则：客户合作胜于合同谈判个体和互动胜于流程可运行的软件胜于详细的文档响应变化胜于遵循计划参考文章：Experiences working with an Outsourced Dev Shop

亲测推荐 2021 年 SaaS 技术栈：Docker、Django、Traefik 和 IntercoolerJS
type: item
date: 2021-03-14T23:29:00+08:00
description: 我最近发布了个人对Django做为一款优秀应用框架的一些考虑。本文基于此从架构角度做进一步扩展，介绍从开发到生产环境的整体技术栈考虑。2018 年至今，我一直使用该技术栈构建一些小型 SaaS 应用。本文最初发布于 www.simplecto.com，经原作者授权，由 InfoQ 翻译并分享。整体技术栈随处部署的 Linux 服务器和虚拟机：我使用了 Azure、Digital Ocean 和 Scaleway，并计划在 2021 年将所有部署迁移到Hetzner提供的专用服务器上。Docker：就是我们常用的 Docker.Traefik：使用 LetsEncrypt 证书的反向代理和 TLS。Postgresql：运行在 Docker 中的数据库。Django：同样运行在容器中。IntercoolerJS：提供平滑易用的类 Ajax 前端应用支持。Intercooler 的创作者在 2021 年发布了HTMX，是 IntercoolerJS 的更新换代。Sentry：捕获生产环境中软件缺陷。只需在配置文件中添加几行配置。Bitbucket Pipelines 替代 CI/CD：鉴于 CI/CD 引入了过多繁琐无用的工具，我在 2021 年不再对个人项目考虑 CI/CD。ZeroTier：实现 VPN 和控制层。我在开发小型项目时，采用本地 Docker 容器运行测试，进而直接推送到生产环境。我不考虑使用繁琐的 CI/CD，而是选择了 Bitbucket Pipelines。上图给出了我所采用技术栈的概览，图中有很多需要详细展开阐述的部分。下面换成列表方式展示。虚拟机DockerDjango挂载数据磁盘卷使用长时间运行 Django 命令做为 Workers挂载数据磁盘卷Postgres挂载数据磁盘卷TraefikZero-TierSSH托管环境即便是无服务器架构，也需要一个云服务托管环境。我个人推荐Azure、Digital Ocean和Scaleway。每家都为计算、联网、存储和基本服务提供了充分的选项，支持用户任何构建需求。同样推荐Hetzner，它提供了各服务层级的硬件、服务和价格。虚拟机一些企业应用和个人副业（side projects），并不需要同时为成千上万的用户提供 TB 级数据服务，因此可扩展性并非主要关注问题。对于此，我们可选用最小托管服务选项，通常不高于每月 20 美元。即便是服务价格相对最贵的 Azure，也可选用 Burstable 服务质量的虚拟机。个人推荐Scaleway的开发层级服务器。注意：在我的技术栈中并没有 Kubernetes，因为我并未考虑可扩展性。Docker为确保新的虚拟机运行在最新版 Docker 上，我并没有依赖操作系统本身，而是使用了 curl|bash 方式，即：curl -s https://get.docker.com | sudo bash 运行上面一行命令，就能获取最适用于当前运行环境的最新版本。Traefik 实现反向代理Traefik 对我简直是天赐之选。尽管 Nginx 也很强大，但其并非针对 Docker 环境构建。Traefik 的两个杀手级特性，为我节省了大量时间：使用 LetsEncrypt 实现自动 TLS。简而言之，一旦设置，无需操心。结合适用的 API 和 DNS 服务提供商，还可以使用 DNS 验证。使用 Docker label 实现无需重新加载的自动配置。一旦新服务发布，Traefik 通过监听所有 Docker 相关服务而自动发现更改。这使得服务的添加、移除和合并非常方便，不存在任何麻烦。我对 Traefik 唯一意见是学习曲线略为陡峭。用户必须自行确定如何进行配置，包括配置文件、命令行选项、YAML、Docker label，乃至组合使用。提示：我发布了自己使用的Traefik生产环境配置文件，供参考。Postgres 数据库亲测推荐，PostgreSQL 从不会令我失望。PostgreSQL 容器可毫无问题地添加到任何项目中。我只需简单地启动容器，绑定端口，挂接数据卷到主机磁盘，仅此足矣。docker-compose.yml version: '3.1' services: db: container_name: postgres hostname: postgres image: postgres:11 restart: always environment: POSTGRES_PASSWORD: secretsonly volumes: - ./data:/var/lib/postgresql/data ports: - 5432:5432 networks: - web networks: web: external: tr …

我成功开发了一个 SaaS 项目，技术栈是这样的
type: item
date: 2021-03-08T10:32:16+08:00
description: 作为一名忠于内心的工程师，每当我看到一家公司发布有关它们技术栈的文章时，我都会泡一杯咖啡，坐下来耐心阅读，看看有没有新的发现。了解其他公司业务背后隐藏的一些技术十分有趣。就像娱乐八卦一样，只不过这是技术层面的探索。几个月前，我开始开发另一个 SaaS，该项目经历无数次迭代。幸运的是，尽管项目仍处于早期阶段，但是很多网站已经对其进行了集成。作为一个自负盈亏的独立创业者，我相信正是由于专注于自动化，才让我能为来自 80 多个国家和地区的客户提供可靠服务，并且每周持续提供新功能。当我想要了解服务的运行情况或者其他方面的信息时，我会尝试利用我熟悉的工具。当然，我也明白，在一些特殊情况下这些工具并不会帮到我。现在，我简要地介绍下平时使用的一些工具。非常重要的一点是，虽然工具列表看起来很长，并且有一些是非常规且不常用的选项，但实际上我在基础架构上花费的时间很少，如果有的话，每个月平均下来也就是几个小时。还有一点就是个人推荐就像是开处方一样，我认为对我非常有用的一些工具，可能并不适合你。一定要考虑自己的实际情况，并利用好当下你熟悉的工具。编程语言多年来，我学习和使用过好几种编程语言，但是对于独立项目，我特别挑选出两种编程语言。这两种编程语言可以在生产力以及可靠性上取得很好的平衡。Python：很多项目的后端代码都是用 Python 实现的。它可以让我能够以较快的速度发布新功能。另外，我使用 mypy 用于类型提示，这方便我进行代码管理。Typescript：我以前会有意地避开前端开发的工作。直到大约 4 年前，我发现并开始使用 Typescript。它让我感觉写前端的工作体验更好了，现在我使用它并结合 React 框架一起构建我的项目。框架理论上，我会在这里介绍很多这方面的内容，但是相关论坛上有不少介绍，我也是站在巨人的肩膀上学到很多知识。因此我只想介绍几个非常不错的框架：Django：该框架简直就是独立开发者的宝库。你在该行业中工作的时间越长，你越能体会到避免重复造轮子带来的幸福感。这一框架可以让你走的更远，因为它的功能实在是太全面了，应用场景也很广泛。推荐阅读Instagram如何优化Python提高服务性能、Sentry项目、10大Django构建的网站了解一下 Django 的使用场景。对我来说，该框架不管在性能还是功能方面都能满足我的需求。React：数据展示相关的 Web 应用是使用 React + Webpack 构建的。在长时间使用 Angular 后，我最终切换到 React，因为它是支持可插拔的视图层，不会对其他功能造成影响。我使用性能表现不错的django-react-templatetags将 React 组件嵌入到我的 Django 模板中。NextJS：我使用它进行页面、文档等的加载。它让我能重用各种 React 组件，并且可以提高静态页面的性能以及 SEO 优势。Celery：我使用该框架用于后台/定时任务的管理。该框架的学习成本较高，但是一旦你了解了它的工作原理，并应用到项目中后，你就能体会到该框架的稳定性和可靠性了。Bootstrap 4：我基于 Bootstrap 构建前端应用。它节省了我很多时间，并且文档资料详细丰富。这就是我选择使用它的原因。数据库我最初将所有数据都存储在 SQLite 数据库中，对数据进行备份意味着要将副本数据复制到 S3 之类的对象存储中。之前对于测试过的一些小型站点来说，没有什么问题。但是，随着项目的功能及页面越来越多，我需要更多专门的数据库来支持这些功能：Clickhouse：我相信 Clickhouse 是为数不多的随着时间的推移而经久不衰的技术之一。说实话，这是一款十分给力的数据库，它能够实现原先在低配置硬件上几乎无法实现的功能。PostgreSQL：我必用的关系数据库。默认配置合理，经历了充分的市场检验并且与 Django 深度集成。在 Panelbear 中，PostgreSQL 主要用于与分析无关的应用数据存储；对于分析用的数据，我使用 Django 实现了一个简单的接口从 Clickhouse 查询数据。Redis：我在很多场景中使用了 Redis，比如缓存、速度限制、任务队列以及作为有生命周期的键值存储。Redis 功能强大且性能稳定，社区文档也十分丰富。部署工具与这篇文章描述的一样，我不会将我的基础设施视为宝贝一样对待。服务器和集群本来就是一个工具而已。所以如果某一台服务器出现问题，用另外一台正常的服务器替换一下就好了。这意味着所有的操作在 git 仓库中被描述为代码逻辑，并且我不会通过 SSH 登陆服务器进行一些操作。你可以将这个描述视为一个模板，可以通过一个命令将整个基础架构克隆到任何的 AWS 服务中。这在灾难恢复时也会对我有所帮助。我只需要运行一些命令，…

写代码有这16个好习惯，可以减少80%非业务的bug
type: item
date: 2020-12-07T09:01:38+08:00
description: 每一个好习惯都是一笔财富，本文整理了写代码的16个好习惯，每个都很经典，养成这些习惯，可以规避多数非业务的bug！希望对大家有帮助哈，谢谢阅读，加油哦~公众号：「捡田螺的小男孩」修改完代码，记得自测一下「改完代码，自测一下」 是每位程序员必备的基本素养。尤其不要抱有这种侥幸「心理：我只是改了一个变量或者我只改了一行配置代码，不用自测了」。改完代码，尽量要求自己都去测试一下哈，可以规避很多不必要bug的。方法入参尽量都检验入参校验也是每个程序员必备的基本素养。你的方法处理，「必须先校验参数」。比如入参是否允许为空，入参长度是否符合你的预期长度。这个尽量养成习惯吧，很多「低级bug」都是「不校验参数」导致的。? 如果你的数据库字段设置为varchar(16),对方传了一个32位的字符串过来，你不校验参数，「插入数据库直接异常」了。 ?修改老接口的时候，思考接口的兼容性。很多bug都是因为修改了对外老接口，但是却「不做兼容导致」的。关键这个问题多数是比较严重的，可能直接导致系统发版失败的。新手程序员很容易犯这个错误哦~所以，如果你的需求是在原来接口上修改，，尤其这个接口是对外提供服务的话，一定要考虑接口兼容。举个例子吧，比如dubbo接口，原本是只接收A，B参数，现在你加了一个参数C，就可以考虑这样处理。//老接口 void oldService(A,B);{ //兼容新接口，传个null代替C newService(A,B,null); } //新接口，暂时不能删掉老接口，需要做兼容。 void newService(A,B,C); 对于复杂的代码逻辑，添加清楚的注释写代码的时候，是没有必要写太多的注释的，好的方法变量命名就是最好的注释。但是，如果是「业务逻辑很复杂的代码」，真的非常有必要写「清楚注释」。清楚的注释，更有利于后面的维护。使用完IO资源流，需要关闭应该大家都有过这样的经历，windows系统桌面如果「打开太多文件」或者系统软件，就会觉得电脑很卡。当然，我们linux服务器也一样，平时操作文件，或者数据库连接，IO资源流如果没关闭，那么这个IO资源就会被它占着，这样别人就没有办法用了，这就造成「资源浪费」。所以使用完IO流，可以使用finally关闭哈FileInputStream fdIn = null; try { fdIn = new FileInputStream(new File("/jay.txt")); } catch (FileNotFoundException e) { log.error(e); } catch (IOException e) { log.error(e); }finally { try { if (fdIn != null) { fdIn.close(); } } catch (IOException e) { log.error(e); } } JDK 7 之后还有更帅的关闭流写法，「try-with-resource」。/* * 关注公众号，捡田螺的小男孩 */ try (FileInputStream inputStream = new FileInputStream(new File("jay.txt")) { // use resources } catch (FileNotFoundException e) { log.error(e); } catch (IOException e) { log.error(e); } 代码采取措施避免运行时错误（如数组边界溢出，被零除等）日常开发中，我们需要采取措施规避「数组边界溢出，被零整除，空指针」等运行时错误。类似代码比较常见：String name = list.get(1).getName(); //list可能越界，因为不一定有2个元素哈 所以，应该「采取措施，预防一下数组边界溢出」，正例：if(CollectionsUtil.isNotEmpty(list)&& list.size()>1){ String name = list.get(1).getName(); } 尽量不在循环里远程调用、或者数据库操作，优先考虑批量进行。远程操作或者数据库操作都是「比较耗网络、IO资源」的，所以尽量不在循环里远程调用、不在循环里操作数据库，能「批量一次性查回来尽量不要循环多次去查」。（但是呢，也不要一次性查太多数据哈，要分批500一次酱紫）正例：remoteBatchQuery(param); 反例：for(int i=0;i<n;i++){ remoteSingleQuery(param) } 写完代码，脑洞一下多线程执行会怎样，注意并发一致性问题我们经常见的一些业务场景，就是先查下有没有记录，再进行对应的操作（比如修改）。但…