只要利益不发生冲突，别人说话一般不要去反驳。人际交往的高段位技巧，热情大方，一问三不知。你真正要做的事，连神明都不要讲，安静的做成功了再说，是以秘城，言以懈息。努力克制自己的情绪，学会赞美和闭嘴。给别人办事，一定要装的很难办，给领导送礼一定要装的很自然，给爱人花钱，一定要装得很痛快，请别人吃饭，一定要装得很大气，和人谈生意，一定要装得很成功，和人谈感情，一定要装得很纯洁，和人谈工作，一定要装得很专业，不能喝酒时，一定要装得很醉，不能赴约时,一定要装得很失落，不能帮忙时，一定要装的很难过。做人一定要有城府，逢人只说三分话，不可全抛一片心。你要是想看透人心，只需要落魄一次就够了。也为人在落魄的时候，身边的牛鬼蛇神都会露出真实面目。德不配位，财不配身，怎么破，很简单，就是习惯它，升官了，静默半年别折腾，赚钱了，放手里半年不花，就行了。处理问题，包括应急事件，狭路相逢和退一步海阔天空都不可取，通用的是沉默是金和让子弹飞，有奇效。刷视频，多看看打架斗殴、车祸集锦、意外身亡的，危机意识和避险意识会潜移默化。多读历史，人虽然会变得冷漠，但是能够提高生存能力，你死我活才是本质。社会感悟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、与人打交道，心理博弈，让别人舒服； #方法论
兼职管理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件事之概括
架构师是一种神秘的职位，据说每个架构师都有密不可传的方法，当然我们不信，更多的是只可意会不可言传。就是说了我们也不会懂，因为还每到“火候”。所能做的就是，当我们到这种火候的时候我们能想起来曾经有过架构师这么说过，然后我们就可以更自信的向前大步走....1、客户需求重于个人简历要想拥有漂亮的个人简历：我们常常向客户推荐技术、手段，甚至方法论来解决问题，使用时髦的编程技巧和流行的范式，有时候根本不是寻求解决问题的最佳方案。积累一批满意的客户，选择切合实际的技术解决他们的难题，让他们乐于推荐你才是最好的履历。2、简化根本复杂性，消除偶发复杂性根本复杂性指的是与生俱来的、无法避免的困难。比如，协调全国的空中交通就是一个“天生的”复杂问题，必须实时跟踪每架飞机的位置。偶发复杂性：是人们解决根本复杂性的过程中衍生的。架构师的责任在于解决问题的根本复杂性，同时避免引入偶发复杂性。怎么做？尽量选择源自实际项目的框架，警惕那些象牙塔里面的产品。3、关键问题可能不是出在技术上简单的项目也会翻船，而且这不是个别情况。大多数项目是人完成的，人才是项目成败与否的基础。如果团队里有人工作方式不正确，拖项目后腿怎么办？有一种非常古老但很完善的技术可以帮助你解决问题。它可能是人类历史上最重要的技术创新，这就是对话。有几个简单的对话技巧可以显著改善对话效果：不要把对话当成对抗。不要带着情绪与人沟通。尝试通过沟通设置共同的目标。4、以沟通为中心，坚持简明清晰的表达方式和开明的领导风格沟通必须简明清晰，没有人愿意阅读冗长的架构决策文档，架构师言简意赅的表达观点是项目成功的必要条件。架构师往往忽略了自己也是领导者。作为领导者我们必须获得同伴的尊敬才能顺利开展工作。所有的成员都希望有明确的沟通和开明的领导。只能这样才能改善沟通效果，建立团结健康的工作环境。5、架构决定性能大家似乎理解，事实并未如此，有些架构师认为简单的更换底层架构就足以解决应用的性能问题，他们很可能轻信了“经测试产品性能超出竞争对手25%”，比如从4ms到3ms，这1ms放在一个性能极低的架构里几乎可以忽略不计。归根结底，所有产品和架构必须遵循分布式计算和物理学的基本原理：运行应用和产品的计算机性能有限，通过物理连接和逻辑协议实现的通信必然有延时。因此，应该承认架构才是影响应用性能和可伸缩性的决定因素。性能参数是无法简单的通过更换软件，或者“调优”底层软件架构来改善的，我们必须在架构的设计和重新设计上投入更多的精力。6、分析客户需求背后的意义顾客和最终用户通常提出的所谓需求，只是他们心目中可行的解决方案，并不是问题唯一的解决途径，当了解顾客的需求背后的意义，我们可以为顾客解决真正的问题并可能降低难度。7、起立发言许多架构师都是从技术岗位上成长起来的，他们擅长和机器打交道，然而架构师更需要与人打交道，无论劝说开发人员接受具体的设计模式，还是向管理层解释购买中间件的利弊，沟通都是达成目标的核心技能。有经验的架构师会很重视推销自己的想法也明白有效沟通的重要性，其中一个简单又实用的技巧是在2人以上的场合发表意见时请“站起来”，起立发言非常重要尤其是当其他人坐着的时候。当你站起来的时候无形中添加一种权威和自信，自然就控制住了场面，听众不会随意打断你的发言，这些都会让你的发言效果大为改观，你会发现站立可以更好的用双手和肢体语言。在10人以上的场合，起立发言方便你与每位听众保持视线接触。眼神交流、肢体语言等表达方式在沟通中的作用不可小觑。起立发言还可以让你更好的控制语气、语调、语速和嗓门，让你的声音传的更远。当你讲到重点内容时，注意放慢语速。发声技巧也能显著改善沟通效果。比沟通事半功倍，起立发言是最简单、有效的方法。8、故障终究会发生硬件会出错，于是我们增加冗余资源来提升系统的可靠性，同时也增加了至少有一台设备出错的概率。软件会出错，增加额外的监控程序也会出错。于是我们又为自动化增加监控，结果是更多的软件，导致更高的故障率。类似的如：三里岛核电站泄漏事故既然必然会出错就需要事先设计好防范故障的模型，以应对威胁系统安全的意外情况。9、我们常常忽略自己在谈判我们都面临过削减预算的要求，如果资金运转促襟见肘，技术方案只能委屈求全。比如如下情景：“我们真的需要这东西吗？”项目投资人发难道。尽管真的需要，我们通常也不能这么回答，因为此时我们是在谈判，此时我们需要认清自己的角色，不能把自己当成工程师，而且投资人明白他在和你谈判，我们应该这样回答"真的需要吗"这类问题：“单台服务器每天至少崩溃3次，没有第二台我们甚至无法跟董事会演示，事实上我们需要4台服务器，构成2组，这样在需要时断开一组而不必被迫关闭系统。即使有一台出现意外，也不影响系统正常运行”10、量化需求速度快不能算作需求，响应灵敏和可扩展也不能算需求，因为我们无法客观地判断是否满足了这样的条件。正确的描述需求应该像这样：“必须在1500ms内响应用户的输入。在正常负载下，平均响应时间控制在750ms-1250ms之间。由于用户无法识别500ms以内的响应，所以我们没必要将响应时间降到这个范围一下。”11、一行代码比500行架构说明更有价值架构说明书（specifications）很重要，因为它描述了构建系统的模式，但是静下心来全面彻底地理解架构——即从宏观上把握组件之间的交互，又着眼于组件内部的代码细节——也很重要。架构师往往容易被抽象的架构所吸引，沉迷于设计过程。事实上仅有架构说明书是远远不够的。软件项目的最终目标是建立生产体系，架构师必须时刻关注这个目标，牢记设计只是达到目标的手段，而不是目标。如果亲自开发，应该珍视自己花在写代码上的时间，千万别听信这会分散架构师精力的说法。这样既能拓展你的宏观视野，也能丰富你的微观世界。12、放之四海皆准的解决方案架构师应该坚持培养和训练“情景意识”——因为我们遇到的问题千差万别，不存在放之四海皆准的解决方案。“情景模式”：调查有经验的架构师处理复杂问题的方式。有经验的架构师和设计师的答案如出一辙：只须使用常识....【一个】比“常识”更贴切的说法是“情景意识”——在给定情景下对合理性的把握。架构师通过学习和实践，不断积累的案例和经验，建立足够的情景意识。他们通常需要十年的磨练，才能解决系统层次的问题。13、提前关注性能问题商业用户的需求主要表现卫队功能的要求。系统的非功能特性则由架构师负责，包括：性能表现、灵活性、持续正常工作时间、技术支持资源等。但是对非功能特性的初始测试往往被拖到开发周期的最后阶段，有时还由开发团队来操刀，这样的错误屡见不鲜。在项目周期的最后阶段才关注性能问题，会导致我们错失大量历史信息，这些信息包含性能变化的细节。如果性能是架构设计的重要指标，就应该尽早展开性能测试。在采用敏捷方法开发的项目中，如果有2周为一个迭代周期，我认为性能测试的开始时间最迟不能晚于第三次迭代。坚持技术测试是需要耐心和毅力的，无论是搭建合适的测试环境，采集适当的数据集，还是编写必要的测试用例，都需要投入大量的时间。14、架构设计要平衡兼顾多方需求平衡兼顾各方的要求和项目的技术需求CEO需要控制成本运营部门要求软件易于管理二次开发人员要求软件代码容易学习方便维护业务部门：旅行合同义务、创造收益、树立客户口碑、控制成本，创造有价值的技术资产技术部门：确保软件的功能15、草率提交任务是不负责任的行为傍晚时候，团队正在完成本次迭代的收尾工作，一切按部就班、有条不紊。只有约翰赶着赴约有些急躁，他仓促写完自己的代码，编译、检入，然后匆匆离开。几分钟后红灯亮起（许多采用敏捷开发方法的软件公司（例如ThouthtWorks）在每个团队成员的桌上放置一盏3色灯，用来表示当前的集成状态，黄色正在集成，绿色集成成功，红色集成失败），构建失败。约翰没来得及执行自动测试就草率地提交了任务，连累大家无法继续工作。正常的工作秩序全被打乱了。这个时候架构师就该发挥作用了，营造一种团队文化，以维护流程通畅为重，以浪费他人时间为耻。要做到这一点，务必在系统内实现完善的自动测试功能，纠正开发人员的行为。沉下心来改变系统的生产效率，缩短流程避免各行其是，才能缩短开发时间。总之一定要杜绝一切草率提交任务的念头。16、不要在一棵树上吊死负责构建系统的人似乎无法接受这样的事实：没有哪种数据类型、消息格式、消息传送机制，甚至主流的架构组件、策略、观点用来能够用来解决所有的业务问题，毕竟当大家都希望摆脱业务需求不断滋生的意外和烦恼。才用多钟表现方式、多钟传输方式不是为了消遣。应当认识到，通过分解系统的非功能参数，可以为客户提供多样化的解决方案。17、业务目标至上在商业化的背景下开发企业应用，架构师必须成为业务部门和技术部门沟通的桥梁，周旋调解，兼顾双方利益，同时业务目标来驱动项目 开发。业务目标和实际的开发条件应该成为架构师主持制定决策的参照系统。在启动一个软件项目之前，应当制定计划，明确投资回报的预期。架构师必须把握这个预期，并预估该项目的商业价值，避免做出错误的技术决策，造成经费超支。用业务目标驱动项目开发，才能保证软件开发团队的长远利益。18、先确保解决方案简单可用，再考虑通用性和复用性许多用来实现基础设施的代码，包括组建、框架、类库、基础服务，普遍存在一个问题，它们设计一向强调通用性而不考虑具体应用。如果存在多个可实施方案难以取舍，“先简单后通用”原则可以成为最终的评判标准。虽然很多架构师重视通用性，但这样做是有前提条件的。并非所有人都需要通用性，愿意为它掏钱。19、架构师应该亲力亲为称职的架构师应该通过示范领导团队，架构师通常都取得过不错的业绩，有份出彩的简历，容易获得业务人员和技术人员的青睐。但除非他能展示自己的实践能力，否则很难赢得团队的尊重，团队成员将无法从他身上学到东西，大家甚至难以在他的领导下做好本职工作。20、持续集成架构师（无论是应用架构师还是企业架构师）都应该在项目中鼓励推广持续集成的方法和工具。现在持续集成已经取代了“尽早构建，经常构建”（build early and often）的提法，它确保当前的开发不会出现意外，是一种降低风险的技巧。构建应用程序是持续集成最主要的内容，它通常是自动执行的，可以设置在夜里执行，或者当源代码改变时自动触发。当然你也可以选择手动构建。21、避免进度调整失误导致项目失败的原因很多，最常见的是中途临时调整进度。改变计划回答带来以下问题：仓促的进度会导致拙略的设计、蹩脚的文档，可能引发质量问题，导致用户拒绝签收仓促完成代码导致bug增多，测试不充分增加测试中可能出现的问题以上问题均能引发产品质量问题，而解决产品质量的问题代价更高。最后的结果是成本不降反升，通常项目就是这样失败的。22、取舍的艺术架构师应该明白鱼和熊掌不可兼得的道理。如果2个性能本身就是冲突的，满足一项就会导致另一项失败或者整体失败。23、打造数据库堡垒创建牢固的数据模型要从第一天开始牢固的数据模型既可以保障当前的数据的安全，又为今后提供可扩展性。要保障数据安全就必须隔离来自应用层的bug（在不断变化的应用层中这些bug无处不在，不会因为你的勤奋而消失），必须严格遵守引用完整性规则，尽量使用域约束规则，还要选择恰当的键，即保证数据的完整性，又遵守约束规则。要实现可扩展性，就必须正确地将数据标准化。以便今后在数据模型上添加架构层：千万不要偷懒走捷径。为了妥善保护数据库必须拒绝无效数据，阻止无意义的关系。在定义键、外键、域约束时，应该采取简洁的容易被理解和验证的名称，使他们含义不言自明。数据模型中的域规则也要做到物理化和持久化，避免他们在应用逻辑发生改变时被删除。为了充分发挥关系型数据库的作用——让它真正的成为应用的一部分，而不仅仅是存放数据的库房——必须从开始构建数据库时，就深刻理解业务需求。随着产品的演变，数据层也会发生变化。24、重视不确定性当你面临2中选择的时候应该仔细考虑设计中的不确定性。迫于压力，人们常常为了决策而决策。这时可以借鉴期权思想（指在期货交易中，权利的受让可以在将来的某个约定的时间，根据当时的情况决定是否行使权利，即推迟做决定时间），当你在不同的系统开发路线之间举棋不定时，不要急于做出决策。推迟决策，直到掌握更详实的信息，以便做出更可靠的决策。但也别太迟，要赶在这些信息失效前利用他们。25、不要轻易放过不起眼的问题问题出现时，虽然个别团队成员会发现一些端倪，但往往由于大多数人认识不到其严重性，这些问题不是被忽略就是被搁置，知道变得难以解决。注意造成的原因和哪些方法克服这些消极因素。26、让大家学会复用有这样一种观点，认为设计优良的框架、细致考虑并精巧实现的架构自然会被人们重复利用。但也是在满足下列条件下擦可能被复用：大家都知道它的存在大家知道如何使用它们大家认识到利用已有资源好过自己动手27、架构里面没有大写“I"英文单词架构（architecture）里面有字母”i"但不是大写的“I”。它代表的不是那个喜欢唤起别人关注，喜欢凌驾于众人之上的“I"(自我）。自我可能是我们这最大的敌人。如何避免犯错误？需求不会撒谎。重视团队合作。检查你的工作。自我反省。28、使用”一千英尺高“的视图用来了解正在开发的软件质量如何在架构图中，系统是由若干个小方框组成的，方框之间的连线代表着各种含义：依赖关系、数据流、共享资源等。这种图好比从飞机上俯瞰地面上的风景，我们称之为“三万英尺高”的视图。另一种典型的视图是源代码，好比占在地面上看大地。两种视图都无法冲分钟展现软件的质量：前者太抽象，而后者细节太多，以至于我们看不清整个架构。很显然我们需要一个介于2着之间的视图——“一千英尺高”的视图。"一千英尺高“的视图提供的信息来自恰当的层次，囊括大量数据和多钟度量标准，例如方法数，类扇出数和圈复杂度。具体的视图与特定的质量属性密切相关。一旦我们绘制出合适的视图，判断软件质量就更客观了。29、先尝试后决策创建一个应用需要作出很多决策。有些决策设计挑选框架和函数，而另一些则需要选定特定的设计模式。架构师应该持续关注那些马上要制定的决策，架构师可以在决策之前，要求几个开发人员商量解决方案，比较不同解决方案的优点和弊端。对同一个问题尝试2种或者2种以上的解决方案，可能是代价最低的选择。事后发现方案不合适或者是没人发现方案不合适都是糟糕的情况。30、掌握业务领域知识高水平的软件架构师不仅要懂技术，还要掌握问题空间对应的业务领域的知识。缺乏业务领域知识的架构师不能顺利地解决问题，无法把握业务目标和业务需求，也就难以设计有效的架构来满足需求。31、程序设计师一种设计程序设计属于设计范畴而不是生产范畴。软件的生产则是自动化的，由编译器、构建工具和测试代码共同完成。如果把编写代码看成设计行为，而不是生产行为，我们就能采用一些已经被证明有效的管理方式。这些方法过去用于管理不可预测性的创新工作，比如研发新车、新药、新的电脑游戏。我们指的是敏捷的产品管理方法和精益生产方法，比如SCRUM。32、让开发人员自己做主多数架构师都是从开发人员干起的。以前作为开发人员你很少有机会仔细观察整个系统是怎样组合在一起的，而作为架构师这是你工作的重点。如果想出色的完成工作，是不可能有空闲去干预开发人员的。33、时间改变一切选择值得投入精力的工作简单原则，回顾以前或者更早的项目时，几乎都会惊诧自己当初的做法，如果有机会再做一次，我们一定会以更简单点的方法来完成。这就是时间的作用。别跟以前的工作过不去，你现在看重的设计思路，可能2-3年后就会被自己否定。34、设立软件架构专业为时尚早设计软件架构师一门手艺，从业者无意要通过实践和训练才能在这个领域获得成功。35、控制项目规模估算与准确的科学计算相差甚远，所以产品特性实现起来常常比预期要困难。缩小和控制项目规模策略：抓住真正需求。分而治之，设置优先级，尽快交付。敏捷方法的倡导者提倡开发”最简单有用的东西“，越复杂的架构越难以实现。缩小项目规模通常会降低架构的复杂性，这是架构师提高成功几率最有效的途径。36、架构师不是演员，是管家架构师接受新项目，都渴望证明自己的价值，这是人之常情。炫耀和作秀与指挥开发项目背道而驰。架构师的职责和管家类似，承担着管理他人资产的责任。架构师要满足不同领域的客户需求，而这些领域的专业知识通常是架构师所不具备的。37、软件架构的道德责任软件世界的道德范畴边界并不清晰，尽管有些行为无疑是不道德的，比如侵犯他人的公民权利等，但还有些行为的道德意义不被察觉，比如浪费别人的时间。架构师的每项决策（例如设置必填项和规定流程），都限制了用户可以做什么不能做什么。这比法律容易的多，并且还找不到法院受理他们的诉讼。我们可以从倍增效应的角度来看待软件的影响。软件问题所造成的损失将以成不可估量的倍数出现，尤其是给人心理上的。假设架构师要实现一个新功能，简单的设计要1天完成复杂的设计要1周的时间，但简单的设计要强迫用户输入大量的数据，这个过程常常会丢失数据，耽搁工作，让人非常沮丧。从长远看浪费别人的时间将远远超过你省下的时间。损人利己是不道德的行为哪怕程度很轻。38、摩天大厦不可伸缩土木工程不只是设计建筑这么简单，真正的难题在于规划整个施工过程，确保建筑物拔地而起，包括从奠基到竣工的所有工作。其中有很多经验值得我们借鉴，尤其是对于部署大型集成化软件系统（包括所有企业应用和web应用）。如果把软件比喻成土木工程，那么传统的大爆炸式软件部署方式就好比把备齐的建筑材料一股脑仍上天，指望他们瞬间拼成一座大厦一样那么可笑。相反，无论是开发新项目，还是替换已有的系统，都应该逐个部署系统组件。2个优点：首先，隐藏在代码中的技术风险是部署软件时无法回避的问题，其次这种方法迫使我们设计清晰的组件间接口。有些是不能借鉴的，尤其是在建筑工程中屡试不爽的”瀑布式“施工方法。毕竟摩天大厦不需要可伸缩性。应用软件只要具备了用户要求的功能便可发布，不用等到十全十美。事实上，产品越早发布公司的净收益就越高。这样既可增加商业利润又可以改变架构品质，这样实用的技巧实在不多。39、混合开发的时代已经来临混合编程：在一套软件系统中同时采用多种核心编程语言现在可以采用基于文本协议（text-based protocols）了。这些新技术以特定格式的文本作为载体，便于所有人编写和理解，为混合开发提供了前所未有的可能性。架构师把若干个强大的开发工具组合起来使用，以往的标准是挑选合适的编程语言，现在则演变成挑选合适的编程范式。选择多了并不总是好事，但至少好过以往软件架构非此即彼的窘境。40、性能至上性能指标和其他指标一样重要。有些设计师把性能放到最后考虑。我们通常把系统响应用户输入的时间作为衡量性能的标准。生产率通常用来描述构架系统的效率，也属于性能范畴，其重要性在于直接影响项目的成本和进度。系统的人机交互性能直接关系到用户是否愿意掏钱。包括：响应时间，是否直观，操作步骤是否简单。合格的说明书除了注明系统每秒钟的响应次数，还要测量典型的任务时间。非交互性组件的性能同样影响着系统的表现。在考虑系统的实现方法和运维策略时，架构师和设计师应该密切的关注系统的性能表现。41、留意架构图里面的空白区域软件系统由相互依赖的程序组成，我们把装配这些程序的方法及程序之间的关系成为架构。假设某个箭头表示”使用HTTP协议，发送SOAP-XML格式的同步请求/响应消息“，由于架构图里面的空间有限，写不了这么多内容，所以通常用简单的注释表示。从技术角度出发可以简写成”XML over HTTP",如果从业务角度出发，有可能写成“查询库存单元”。不同的程序看似通过箭头直接联系，其实不然，矩形之间的空白区域充满 着各种软件和硬件。应该理解每个箭头包含的静态信息和动态信息。42、学习软件专业的行话每个专业都有行话，同行之间讲行话方便交流，清晰、简洁、高效的方式与同行进行沟通，是软件架构师应具备的能力。架构师必须掌握基本的架构模式和设计模式，学会辨别不同模式，并借助他们和同行及开发人员进行交流。架构和设计模式可以分为四大类：企业架构模式、应用架构模式、集成模式、设计模式。企业架构模式定义架构的全局框架结构。应用架构模式指出了全局架构下的子系统及局部应用的设计方法。设计模式研究架构中各个组件的构造方法。除以上4种外，架构师还应该了解和提防各种反模式。反模式：影响软件开发中的常见错误：需求分析麻痹症、委员会设计、蘑菇管理、死亡征途。43、具体情境决定一切”分享设计架构的理念让我觉得很滑稽，因为我认为压根就不存在设计理念““毕竟，没有理念本身也是一种理念”最重要的设计经验是具体情境决定一切，根据它设计尽量简单的解决方案。换句话说，架构决策只有在情境需要时，才能牺牲尽量简单的原则。脱离了具体的应用场景，孤立地比较技术的优劣是毫无意义的事。44、侏儒、精灵、巫师和国王架构师好比国王，应该熟悉各种人的性格特点，招聘不同性格的人加入自己的团队。安排任务时应该时刻考虑所有开发人员的性格特点。为不同性格的团队成员安排合适的任务，如果大家有机会磨合、相互适应，就能轻松化解决各种难题。45、向建筑师学习建筑师名言建筑师社会性的表演，是上演人类历史的剧院。要想成为伟大的建筑师，优雅丰富的心灵远比聪明才智重要。建筑师自诩上帝的助手，甚至觊觎上帝的宝座。（上帝：客户）天底下没有完美的建筑。建筑师首先应该是伟大的雕塑家，或者伟大的画家，否则他不过是个建筑工人。46、避免重复你的开发人员在重复无需思考的工作吗？代码里面反复出现某些相似的片段？某些代码是复制粘贴后稍加修改而成的，如果出现这些情况，说明团队工作效率不高。软件开发的真理：复制时魔鬼重复性的工作拖累开发的进度。消灭重复的内容是你的责任，为此，应该重新研究框架，创造更完善的抽象机制，请专门制作工具的程序员（toolsmith）帮你完成切面框架（aspect framework），使用代码生成器。要想消灭重复内容必须有人采取行动。47、欢迎来到现实世界工程师偏爱精确，整天和0和1打交道的工程师更是如此。现实世界不是二进制的。顾客有可能撤销确认过的订单，支票有可能跳票，信件可能丢失，付款时间可能延迟，许下承诺还可能失信。这些已经够糟了，可分布式系统又带来了新的不一致性。服务有可能失效，状态有可能在毫无征兆的情况下改变，事务处理可能得不到保证。分布式系统不但是松耦合、异步、并发的，而且不遵守传统的事物语义。48、仔细观察别试图控制一切妄想掌控一切的架构师只能设计出紧耦合的、脆弱的解决方案，这一套已经行不通了。我们必须启动必要的辅助机制。我们已经进入分布式、松耦合系统的时代。构建松耦合的系统多少有些麻烦，我们希望系统足够灵活，别因为一点点小的改动就支离破碎。随着系统的配置越来越灵活，当前的系统配置包含了更多的信息，为了便于理解，必须从中提取模型。比如，搞清楚哪个组件负责向逻辑信道发送消息，哪个组件负责接收消息，就应该把组件间的通信关系用图标模型记录下来。与模型驱动架构不同，你先构建出灵活的架构，然后从实际的系统状态中提取模型。49、架构师好比两面神罗马神话里面，两面神是司守门户和万物始末之神。他有两张面孔，凝视2个不同的方向。两面神兼顾前后，过去与未来。架构师在不同的对象之间架起桥梁，比如梦想和现实、过去的成功和未来的方向、业务目标与开发i限制。我们应该以两面神为榜样，工作上严格把关，综合考虑新情况与老经验，在成熟技术上不断创新，既满足当前的业务需求，又兼顾未来的额发展规划。50、架构师当聚焦于边界和接口“哪些应该在一起，哪些应该分开”51、助力开发团队架构师可以施加约束，也有机会成为推动者。要确保开发人员拥有他们所需的工具。要确保开发人员拥有所需的技能，确保他们能够获得必须的培训。同时，也要尽可能的参与到开发人员的选拔中。只要不违背软件设计的总体目标就让开发人员自己做决策。最后，保护开发人员，不要让他们卷入到不那么重要的工作中。52、记录决策理由在软件开发社区，对于文档尤其是关于软件自身设计的文档的价值，争论颇多。分歧一般集中于两处，一处是“详细的前期设计”的有效价值，另一处则是使设计文档化和不断变化的代码库保持同步的难易程度。记录软件架构决策理由的文档，长期有用，无需为之付出过多维护精力，具有很高的投资回报价值。根据项目的不同灵活选择合适的文档格式来记录架构决策的方方面面，格式可以是文本、维基、或博客形式的速记备忘录，也可以使用较正式的模板。比如这些文档：可以作为和开发人员沟通的工具，说明应遵循的重要架构原则当开发人员对架构背后的逻辑提出质疑时，使团队能够就事论事向经理和利益相关者说明这样构建软件的确切原因把项目移交给下任架构师好处是：它逼着你说出理由时，有助于确保基础是扎实稳固的、如果相关条件发生变化，需要对决策重新评估，它可以作为一个起点53、挑战假设，尤其是你自己的延迟判决法则：“臆断是事情搞砸的根源”软件架构师的最佳实践表明，应该记录下每个决策背后的理由，当这一决策包含权衡（性能vs.可维护性，成本vs.上市时间等）时尤须如此。有些小道消息：开源软件不可靠位图索引带来的麻烦比好处多....确保这些假设清楚明确，对后继者和未来的重新评估来说非常重要。更重要的是拿出证据。不要忽略相关这个词语。事实和假设是构建软件的两大支柱。务必确保软件的基石坚实可靠。54、分享知识经验从所有的失败的经验中，我们可以学到很多东西。在像软件开发这般年轻的行业中。为了持续发展传播经验和知识至关重要。每个团队在自己的小世界小角落里所学到的东西，可能会在全球产生影响力。55、模式病人们记录和发现模式，避免后来人重新发明车轮。对于软件架构师而言，设计模式是极有价值的可用工具之一。使用模式，能够创造更易沟通更易理解的通用解决方案。模式与良好设计息息相关，如果发现自己试图把最喜欢的模式硬套在不适用的问题空间上，那么你也许是”模式病“患者。不要让一展模式功底的欲望遮掩了务实真知。56、不要滥用架构隐喻架构师喜欢使用隐喻（metaphor）。对那些通常比较抽象、复杂和变化的移动的目标，隐喻提供了良好的具体媒介。找到实物作为正要构建的东西的隐喻，会更容易沟通和讨论架构全局。滥用架构隐喻经常会出现问题，让架构师不知所措，比如：业务领域的客户开始越来越喜欢系统隐喻，这时，系统还在构想中，在这种情况下所有各方共享的是最乐观的可能解读，但其中并没有包括任何必要的约束。开发团队认为隐喻比实际业务更重要。由于团队耽溺于隐喻，你不得不开始修正那些古怪的决策。所交付的系统包含了许多遗留名称，从早已老旧过时，有待重新鉴定隐喻，到多次重构和重复挖掘的概念。57、关注应用程序的支持和维护应用程序的支持和维护永远不是事后才考虑的事情。由于应用程序80%的声明周期都在维护上。开发人员和支持人员拥有的技能不同，就像开发/测试环境和生产环境有截然不同的目的一样。系统管理员会遇到的问题：*系统管理员不能重新提交请求消息来重现问题。*一旦投入使用，就没有调试器可以用了。....就会出现以下症状：*大多数问题都需要开发人员参与。*支持团队讨厌新的应用程序。....为了确保应用程序脱离开发人员之手后能成功运行，应该做到：*理解开发人员和支持人员确实具有不同的技能*在项目中尽早的引入支持负责人。...当系统管理员很开心的时候大家都会很开的。58、有舍才有得有时，接受某种约束或放弃某个特性，可带来更好的架构，这种架构在构建和运维上都会更加简单，而且成本更低，往往能产生富有创造性和创新性的结果。59、先考虑原则、公理和类比，再考虑个人意见和口味如果是单凭个人经验、意见和口味创建的架构是没有考虑原则、公理、和类比所带来的好处的。这样做，架构文档化会更容易，从描述架构所遵循的原则开始即可。原则清晰的架构能够把架构师解放出来，使其免于全面复审而忙得不可开交。原则和公理确保了架构的一致性。60、从“可行走骨架”开始开发应用为了实现、验证和不断发展应用架构，一个非常有用的策略，便是从Alistair Cockburn所谓的“可行走骨架”开始。“可行走骨架”是对系统的最简单实现（a minimal implementation),它贯穿头尾，将所有的主要构件组件连接起来。从可工作的最小系统开始训练全部的通信路径，可以带来“正朝着正确的方向前进”的信心。对于大型系统通常是由多名开发人员共同构成，对于大型系统而言更多的协调工作是必不可少的。从“可行走骨架“开始，保持系统一直运行可用，递增式地进行培育，使其逐步增长。61、数据是核心软件开发人员最初将软件理解为命令、函数和算法构成的系统。如果稍稍后退站远一点，计算机只不过是能访问与操作一堆数据的时髦工具。代码在计算机中运行时，底层数据的状态不断发生变化。举例而言，如果想了解Unix操作系统，通过源码逐行挖掘是不大可能奏效的，但是如果你读过一本unix内部数据结构的书，便可更好的了解unix底层是如何运行的。从概念上开看，数据比代码更加精炼，也更好理解。即使对于最复杂的系统，通过这种面向数据的视角，即通过底层信息的结构整体开看待系统，也可以将之缩减为细节的有形集合。然后降低其复杂性。数据在大多数问题中处于核心地位，业务领域问题由数据蔓延到代码中。诚然，软件架构中的许多问题确实和数据相关。从设计角度来看，大多数系统的关键问题，就是要在正确的时间从系统获取正确的数据。62、确保简单的问题有简单的解软件架构师解决了许多非常困难的问题，但也会解决一些相对容易的问题，对于简单的问题，不要使用复杂的解决方案。为复杂问题付出的直接成本可能看上去很小，但是其潜在成本要大得多。为问题的解决方案付出的代价不仅仅只是在实现和维护上。架构师会从主观的判断或潜在不确定性需求出发，产生调整解决方案的强烈冲动。但记住一点：试图猜测未来的需求时，错的概率是50%，错的非常离谱的概率是49%。63、架构师首先是开发人员不管解决方案多么优秀，决定实现能否成功的最重要因素之一是让开发人员愿意接下任务。虽然不是工作的一部分，架构师还是会经常去处理一些比较复杂的任务。这样做的目的有两个：第一，这是一种乐趣，而且还能帮我们做到宝刀不老；第二，这有助于向开发人员表明，我不是碰到麻烦时会干吹烟卷却束手无策的架构师。64、根据投资回报率进行决策（ROI）我们对项目所做的每一个决策——无论是技术、过程，还是与人相关——都可以看做一种投资形式。回报率（rate of return），也成投资回报率（Return On Investment,ROI)，是衡量投资是否成功的标准之一。将架构决策视为投资，并将相关的回报率也一并考虑在内。在判断每个决策选项是否务实或恰当时，这种方法很有用。65、一切软件系统都是遗留系统即使系统十分前沿，采用了最新的技术开发而成，但对接手它的下一个人而言，它也会是遗留系统（legacy）。必须面对这种情况！在今天，软件很快便会过时，这已经成为软件的天然属性。如果软件能够存活下来哪怕只有数月的时间，都必须承认一点：负责维护工作的开发人员肯定要对软件进行缺陷修复，这是不可避免的。这引出如下几个问题。*清晰性：各个组件和类的角色一定要清楚*可测行：系统易于验证吗？*正确性：结果和设计或期望的一致吗？*跟踪性：可容易修复紧急缺陷66、起码要有2个可选的解决方案对于某一个问题，如果只考虑了一个解决方案，那你就有麻烦了，在给定的约束条件下，寻找问题的最佳方案，期望第一个解决方案即满足全部的需求和约束，几乎是不可能的。这种问题即使有——也绝少是真地由于缺乏可选方案而造成的，它更可能是架构师缺乏特定问题域的经验所致。67、理解变化的影响好的架构师能够将复杂性降到最低程度，他在解决方案中给出的抽象，应该能够为更高的层次提供坚实基础，同时，还应该能足够务实地应付未来的变化。优秀的架构师能够深刻理解变化带来的影响，这种影响不仅限于彼此隔离的软件模块之间，而且包括人与人之间，以及系统与系统之间。变化有多种不同的表现形式：*功能需求的变化*可扩展性需求的变化*系统接口被修改。。。。幸运的是许多工具和技术可以用以减轻变化的影响：*进行小规模的增量渐变*构建可重复运行的测试用例*跟踪好依赖关系*降低复杂性*自动化重复任务68、你不能不了解硬件对于许多软件架构师，硬件容量规划问题是一个超出其舒适区的主题，但它的确是架构师工作的重要组成部分。如果没有硬件方面的专业知识，预估待开发系统的硬件配置是非常容易出错的。比起采购超出实际所需的硬件，为容量规划留出预算是更为经济的。69、现在走捷径，将来付利息长远看来，系统维护将比项目初期的开发消耗更多的资源。测试：使用测试先行的设计，进行单元测试碰到架构问题或设计缺陷，作为架构师，一定要坚持成本还很低廉时就动手。搁置越久，为之付出的利息也就越高。70、不要追求完美，足够好就行软件设计师，尤其是架构师，在评估针对某个问题的解决方案时，会倾向于考虑它是否优雅完美。有些瑕疵只须经由一些调整或迭代重构便可消除。建议：不要屈服于企图使设计或实现达到完美的诱惑！把目的设定在“足够好”就行，当已经达成目标时就停下来。71、小心“好主意”“好主意”会杀死项目。有时候杀伤力会很快见效，但更常见的症状是：因屡屡错过的里程碑和不断攀升的缺陷数量，项目苟延残喘，最终不治身亡。“好主意”：那种诱人2的、不用想都知道的、外表无辜、以为不可能会产生伤害的那种“好”注意。“好主意”真正的邪恶之处在于它的“好”。如果出现下列关键词，要小心了：*如果....会更酷。*“嘿，他们刚刚发布了YYY框架的XXX版本。我们应该马上升级”。72、内容为王我见过无数这样的设计，它们大都永无止境地强调需求、设计、开发、安全及可维护性，但从未关注系统的真正要点——数据。73、对商业方，架构师要避免愤世嫉俗雇主希望偶们能够解决问题，倾听和了解雇主的业务，是我们必须掌握的最为关键的技能。成为优秀架构师的秘诀之中有一个关键要素，那便是:要对工作满怀激情，但不要是那种带着愤怒和火气的“激情”。74、拉伸关键维度，发现设计中的不足应用程序的设计轮廓，最初是基于特定的业务需求、所选择的技术或现有的技术、性能要求、预期的数据量，以及构建、部署和运营上可用的财务资源。无论采用什么样的解决方案，都要求能满足或超越当前环境下的要求，成功运行起来，否则这就不称其为解决方案了。拉伸解决方案的关键维度，看看哪些方面会遭到破坏。75、架构师要以自己的编程能力为依托在架构上，架构师都期望能够创建出精巧的设计和完美的抽象，来优雅的解决手头的问题。如果能再项目中多安插些技术那就更让人有成就感了。但是最终要实现设计的不是架构师。如果开发人员需要去实现那些架构上的“杂技”，那将会对整个项目造成巨大影响为项目设计架构时，对实现的每个设计元素所需要的工作量，要做到心中有数；如果以前曾开发过其中某种设计元素，那么估算所需的工作量将会容易得多。不要在设计里面使用自己没有亲自实现过的模式，不要使用自己没有用之写过代码的框架，不要使用自己没有亲自配置过的服务器。76、命名要恰如其分如果都不知道一个东西应该叫什么，那你肯定不知道它究竟是什么。如果你不知道它究竟是什么，那么你肯定不能坐下来为它编写代码。77、稳定的问题才能产生高质量的解决方案最好的架构师不是要去解决难题，而是围绕难题开展工作。架构师要能够将四处弥漫的软件问题圈起来，并画出其中的各种边界，确保对问题由稳定的、完整的认识。这些问题应该具有以下特性：*内聚性：问题块在概念上市统一的，其中所有的任务、数据和特征都是相关的。*能够很好地和其他块分隔开：这些块在概念上进行了规范化处理；他们很少重叠或者根本不重叠。78、天道酬勤架构师常常被描述为一种注重创造力与问题解决能力的职业。除了创造力外架构师还应当具备另一项同样重要的特质——勤奋，勤奋指很多方面，但归根结底是指具备坚强的毅力，并且对系统的每项任务和每个架构的目标都能投入足够精力。勤奋经常和平凡携手同行。勤奋还意味着要求架构师必须真正做好那些看似简单的任务，坚守承诺。79、对决策负责由于软件架构师比组织中的其他人更有影响力，所以他们必须对自己做出的决策负责。研究表明有超过三分之二的软件项目要么彻底失败了，要么未能成功交付（项目延期、预算超支、客户不满意）。究其根本原因，有许多事由于架构师做出了不当的决策，或者无法最终执行正确的架构决策。如何做出有效的架构决策：首先,对决策的过程有充分认识第二，定期对架构决策进行复审第三，要贯彻架构决策最后，可以将一些决策委托给响应问题域的专家，不必出自其自身。80、弃聪明，求质朴智力超群、足智多谋对任何人来说都是值得称道的品质。对架构师来说，这些素质尤其被看重。然而，聪明也包含某些额外的隐含意义。它也暗指能快速想出脱身之计的能力，但这种本领最终要依靠一些小伎俩，骗局或掉包计。聪明的设计僵硬难改，其细节会对全局产生太多牵扯，往往会一触即毁。81、精心选择有效的技术，绝不轻易放弃作为软件设计开发的老手，每个架构师通常都有一些让自己屡屡取胜的武器用来武装自己。这些技术由于种种原因深受架构师青睐，排在其首选解决方案的前几位。这并不是说某种技术一旦入围就可以永久罔替。选择新技术虽然有风险，但其价值能为你带来质的飞跃。考虑技术未来的前景。软件架构师工作很大一部分，是要选择用以攻克难题的合适技术。82、客户的客户才是你的客户在软件会议需求会议上，要这样想象：你的客户并不是你的客户。实际上真的不难做到，因为，事实便是如此。如果你的客户的客户赢了，那么你也赢了。如果你在编写一个电子商务应用程序，那么应该考虑的应当是那些会在那个网站上购物的人的需求。如果你的客户有意无意的忽视他们的客户所看重的重要事项——那么请放弃这个项目。需求收集会议不是项目实现讨论会议。83、事物发展总会出人意料事物的发展总会出人意料。在设计时，人们很容易陷入误区，投入太多的时间在设计上。设计中的这些微小变化累积起来，很快就需要对设计进行一次较大的变更。设计是一个不断发现的过程。84、选择彼此间可协调工作的框架软件框架是系统的基础，在选择时，不仅要考虑每个框架自身的质量和特性，也要关注共同构成系统的各个框架之间是否能和谐相处。如果框架间有重叠，则要确保了解候选框架在逻辑域或关注层面上的重叠程度。为了尽量减少框架间互有重叠的概率，要根据系统需求的应用场合，选择精专强大的框架。系统应该由多个相互独立的框架构成，其中每个框架都精专于各自的领域，但同时又非常简洁、包容、灵活。85、着重强调项目的商业价值对于非软件业从业人员，软件架构显得虚无缥缈，架构项目在争取资金时会遭遇到困难。大众心理学表明，大部分人会相信亲眼所见的东西。而拥有预算决定权的人，几乎都是受商业价值驱使的。下列五部，会成功将架构提案打造成经典的商业项目：1、形成价值描述（提高 生产力，改进效率的能力）2、建立量化度量标准3、回过头来关联传统商业的衡量方式4、知道该在哪里停止5、寻找恰当的时机86、不仅仅只控制代码，也要控制数据源代码的控制和持续集成，是管理应用程序构建过程和部署过程的优秀工具。数据方案和数据内容常常会根据源代码的变化而变化，他们也是这一过程的重要组成部分，因此也要对之进行类似的控制。数据库的变化不应该影响构建活动的连续性。要把数据库也作为一个构建单元包含在内，做到一次性构建整个应用程序。数据迁移不应该作为一种补救措施。87、偿还技术债务对任何已投入实用的项目（也就是说，有客户在实用产品），无论是要修复缺陷，还是要添加新功能，总有必须修改产品的时候。在那点上，会面临2个可能选择：花合适时间“一次做对”，或者取巧走“捷径”，争取尽快推出修改过的产品。作为架构师必须决定怎么做才有意义。88、不要急于求解架构师多半是开发人员出身。开发人员的主要职责是解决编程问题。相比架构问题编程问题的范围更狭窄。很多编程问题是很小但比较棘手的算法问题。架构师和开发人员因此学会了迅速进入问题解决模式，但有时候没有解决方案才是最好的而解决方案。许多问题根本不需要解决，看似问题是因为我们只关注表面症状。学会审视问题本身。看看能否改变问题。我们必须戒除“问题解决迷恋症”。89、打造上手的系统我们十工具的制造者。我们制造的系统，一定要能够帮助人们——通常是其他人——做事，否则就是去了存在的意义，我们也将无法从中获取报酬。用户体验应该是“上手的"。90、找到并留住富有激情的问题解决者组建一支汇聚优秀开发人员的团队，是确保软件项目成功非常重要的事情之一。一旦建成便竭力维护。提放批评过度。批评过度，可能会扼杀开发人员的创造力，降低其生产力。更糟糕的是，可能会在团队内部造成纷争。以正确的方式经营开发团队，其重要性不言而喻。91、软件并非真实存在软件工程经常被拿去和完善的传统学科——如土木工程——进行对比。这些类比有个问题，和这些传统实践制造的有形产品不同，软件并非真实的存在。业务和软件都是活生生、会变化的实体。业务需求可能会因新近收购的业务伙伴和营销战略而迅速变化。业务需求很可能会发生变化，因为我们构建的产品是柔韧的。记住，需求文档不是蓝图，软件并非真实存在。我们创造的虚拟物比实体物更易于改变。92、学习新语言架构师必须让别人能理解你。业务人员专业用语和程序员专业用语是有差别的。架构师需要掌握各个沟通团队的语言。93、没有永不过时的解决方案今天的解决方案会成为明天的问题。今天做出的选择，在未来很大程度上是错误的。“分析瘫痪”是今天架构师们碰到的问题之一，此问题最大的归因，是试图去猜测对未来而言最好的技术。94、用户接受度问题人们并不总是满心欢喜地接受新系统或系统的重大升级。这种情势，可能会对项目的成功构成威胁。架构师的目标，是要去了解和衡量用户的接受度问题带来的威胁，并朝着能减轻这些威胁的方向开展工作。“项目拥戴者”可以帮助消除用户接受度问题。这个职位的最佳人选，是能代表用户或利益相关方的人。95、清汤的重要提示清汤是一种非常清澈的肉汤，上品清汤非常清澈，需要不断重复的精炼浓缩才能烹出。设计架构也应当不断精炼浓缩。软件中许多漏洞的需求和缺陷，可最终追溯到含糊笼统的语言描述上。拒绝模凌两可的废话。概念需要在加上“总是、永远、不管任何情况下”仍然成立。96、对最终用户而言，界面就是系统糟糕的用户界面埋没了太多的好产品，最终用户通过界面访问系统。架构师应该确保，随着架构变化而变的用户界面也要能够反应用户的期望。不仅要让最常用的交互易用，而且要使最终用户能够从中获得回报。97、优秀的软件不是构建出来的，而是培育出来的在一开始就要设计庞大的系统几乎毫无好处可言。设计尽可能小的系统，帮助成功交付，并推动它向宏伟的远景目标不断演化。粗略的从后面的十几个里面提取出以下几个方面：数据：程序的核心就是数据，数据的结构表现出数据的形态，数据可能会随着架构更新，数据库也要更新。文档：文档是为了避免反复思考而存在的，类似于代码注释，文档是对工程的注释。尤其是对架构师的每一个有可能产生分歧的决策，必须用文档标明决策原因。推迟决定（也有其他翻译）：是软件开发模型的策略，这样有助于收集更多有关决定的信息。团队：团队需要的不是单一的一类人，但需要的一起能合理分配工作并完成工作的一类人。找到好的团队成员一定尽心维护。用户：客户至上，客户体验是架构师最好的简历，标志着软件的成功与否。沟通：和业务部门沟通，需要学习业务部门的语言，其中涉及到一些专业词汇，避免沟通障碍。和客户沟通明白需求，和程序员沟通....选择技术：如何选择使用的技术，要考虑的事项（如：架构师本人的技术，对于软件的性能，不同架构一起融合等）性能：相对于功能而言，性能经常被忽略。——————作者：H100来源：CSDN原文：https://blog.csdn.net/u014449046/article/details/49390571版权声明：本文为博主原创文章，转载请附上博文链接！
微服务变得越来越理所当然，似乎我们一直生活在微服务的世界中。很多时候，我们常常讨论微服务采用与否、如何选型等问题。但本文作者 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 大型（64vCPU、512GB RAM）服务器。你曾经部署过单体应用吗？当然，我们可以将其复杂化，但在常规情况下，如果将应用程序部署到云上，单体应用就是你所需要的形式。让我们以一个简单的在线商店应用程序为例：应用程序的一个负载均衡器运行应用程序的一个计算实例应用程序的一个（关系型）数据库用于日志聚合的 Kibana 如果你用的是微服务：一个 Kubernetes 集群一个负载均衡器运行应用程序和托管 K8S 集群的多个计算实例一个或多个（关系型）数据库，取决于你是否每个服务用一个数据库一个用于服务间通信的消息系统，例如 Kafka用于持续集成（持续部署）的 Jenkins用于日志聚合的 Kibana用于监控的 Prometheus用于分布式跟踪的 Jaeger/Zipkin 而且这只是一个高层级的概览。微服务确实可以产生价值，但问题是：代价是什么？尽管这些承诺听起来很好，但你的架构中有更多活动的部件，这自然会导致更多的失败。如果你的消息系统挂了怎么办？如果你的 K8S 集群出现问题怎么办？如果 Jaeger 宕机，而你无法跟踪错误怎么办？如果指标没有进入 Prometheus 怎么办？显然，你将花费更多时间（和金钱）来构建和运转这个复杂的系统。更快的部署?我将讲讲优势列表中的第一点：更快的部署。当你想到 Netflix、Facebook、Twitter，并且观看他们的会议演讲，他们描述他们正在运行的微服务数量，以及他们如何向 Git 提交内容，并在数小时内将其投入生产。这是不是好得难以置信？在我看来，这绝对是可以实现的，但我承认我从未参与过这样的微服务项目。我并不是说这是不可能的，只是从稳定性、基础设施和团队文化角度来看，这真的很难实现。让我分享一下我是如何从我的经历中得出这个结论的。在对一个全新的项目进行编码之前，你通常会先研究如何将产品转变成技术方案。你会设计系统，设计微服务，会有多少个微服务，每个微服务的职责等等。有一个真正的教学项目，我们在这个项目中练手，我们最终做了 80+微服务，用了多长时间呢，4 个月？这 80+微服务的现实意义是，与其将这 80+微服务一起组合成一个单体应用并部署这个单体应用，部署单个微服务绝对会更快，但是.......这 80+微服务太小了，以至于一个开发单元——敏捷领域的叙事——永远不可能只涉及一个服务。系统从根本上被破坏了，更快的部署的承诺立即消失了。我们不再拥有更快的部署，而是相反，更慢的部署。而且慢得多。另外，我会反复思考这个问题。部署过程中活动的部件越多，意味着潜在故障越多。很多时候，基础实施不够稳定，部署会随机失败，因为：在下载/上传软件包时，Artifactory/Nexus/Docker 仓库短时间内不可用；Jenkins 构建器随机卡住。这只是其中的一部分。产品必须分解为微服务。每个服务都必须对其自己的事情负责。例如，Netflix 中的一个推荐服务应该负责向用户提供推荐。不是谁都是 Netflix，也不是所有东西都容易分解成合适的大小和职责。这是领域驱动设计（Domain Driven Design，DDD）和有界上下文可以提供帮助的地方，但这实践起来并不容易，有时甚至没有足够的时间/开发性来试验这些方法。配套文化无论如何，在我看来，微服务的第二个困难是组织/项目文化。如果产品（部门）根本不关心底层系统架构会怎么样？我是说，他们会关心吗？举个例子：如果你有一个拥有大量微服务的复杂架构会怎么样。产品负责人进来对团队说，让我们开发整个功能。在团队分析完功能请求后，发现它涉及 10-15 个微服务，因为它与许多其它的已有功能有关联。那你会怎么办？你试图将它分解成更小的部分，但是这么做到底对不对，这里存在着疑问，因为每个小部分的功能没有意义，而且逐个服务发布它会增加大量开销。你当然不能对产品负责人说，仅仅因为我们用的是微服务，所以我们需要 3-4 倍时间，对吧？这个对话会是什么样子？产品经理：嗨，伙计们，我想到了一个非常棒的功能。我们的竞争对手也准备做这个功能，所以我们要快点实现它。2 周做完，可以吗？团队：好吧，初步看来，我们可以实现这个功能。而且这个功能看起来也是一个好主意，可以带来更多的客户。我们会重新组织，好好谈谈。团队：好吧，2 周有一点儿问题。因为我们用微服务是为了更快，我们需要更多时间来实现这个功能，由于我们需要涉及 15 个服务，因此我们需要 6 周的时间来完成初步实现。产品经理：初步实现？团队：是的。这 15 个服务之间的通信非常重要，因此初步实现不会包括异常处理、弹性通信模式、调试跟踪等其它东西。如果做这些的话，我们还额外需要 4 周时间。产品经理跳窗了更好的故障隔离这一点自然是正确的。如果一个服务挂了，只有那个服务会受影响，对吧？虽然确实如此，但这并不是绝对的。让我给你展示 Netflix 的一个虚拟架构图——我对其进行了简化：假设用户想要看推荐。请求转到推荐服务，它查询用户数据来了解用户详情，并将推荐存储在其数据库中（不在图片上），而且由于这是用户相关的数据，所以它们可能需要将其加密。现在，如果数据加密服务挂了会发生什么？我们还能做推荐吗？肯定不能，因为我们不能加密用户数据，所以我们自然会说，嘿，伙计，我们现在不能给你推荐，请 5 分钟后再试。这个故障影响到系统中的推荐服务，系统会以无法立即提供推荐的事实来优雅地做出回应。但是你知道要优雅地处理这类情况需要做多少工作吗？非常多。让我们再举一个例子。用户尝试使用登录服务来登入系统。数据加密服务仍在故障，登录服务调用分析服务来获取在一个时间区间内有多少用户正在尝试登入的指标，以及其它一些虚构的指标。不过，分析服务也在与数据加密服务通信，因为这些数据也需要加密。现在，编写分析服务的团队正忙着，没有时间来实现适当的异常处理，因此数据加密服务的问题会转而影响到登录服务。显然，登录服务是在几个月前完成的，这个服务没有准备好处理来自分析服务的底层错误，因此即使不关键的分析服务失败也会导致用户登录被拒绝。而且我知道你是怎么想的。是的，实现登录服务的团队不负责为处理这种情况做准备，但是如果他们认为分析服务会优雅地处理这个异常呢？这已经写在分析服务的 API 合约中，但它没有那样生效。那么，当你在一个单体应用程序中，会发生什么呢？一个服务崩溃在这个上下文中并没有真正的意义，但假定由于某种原因，连接到数据加密的数据库表不可访问了。在这种情况下，异常处理非常简单，因为你只需要准备一个 exception 就可以了。但是在过分赞扬单体应用前，需要说的是，单体应用也有缺点，如果单体应用挂了，什么东西都不可用了。因此，这是一个平衡问题，需要问问你自己。是实现一个 try-catch 代码块更容易，还是处理一个同步 HTTP 调用异常或异步消息异常更容易？我记得，对于 80+微服务，标准化异常处理是非常了不起的事情，它需要一个团队花费数月来完成。这甚至不意味着在每个地方都引入异常处理，而只是将现有的异常用我们使用的一个自定义库重写，这样我们就可以减少未来异常处理场景所需的繁琐工作。关于作者Arnold Galovics 六年级就开始学习 Flash 编程，之后开始接触 HTML、CSS、JavaScript，在高中时期学了几年 Pascal，然后在大学开始学习 C、C++和 Java。Java 是其职业垫脚石，他为 Java 投入了大量时间。2012 年开始作为全职软件开发者，参与金融行业、OAuth2、与 OpenID 兼容的身份验证平台、物联网等应用程序的开发，主要专长是 Java 及相关框架，熟悉 Spring、JUnit、TestNG、Mockito、JPA、Hibernate，以及 Kubernetes、Kibana、Ansible、Jaeger、Zipkin、Kafka、MQTT 等。只要是跟 Java 相关的开发技术、基础设施、云、架构都比较熟悉。在过去几年中，他过渡到了团队管理的位置，团队规模从 5 人增长到 35 人，试图使用 Scrum 和 Kanban 来实践敏捷方法，希望在团队成员个人创造力与公司目标之间取得平衡。原文链接：https://arnoldgalovics.com/microservices-in-production/
作者和授权信息本文由 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个小时的工作时间均摊到各种要做的事情上边，就会发现其实每一件事都分不了太多时间，这会造成整体业务进展慢。同时，因为就一个人，所以必须在多种业务之间来回切换，这会带来一些额外成本。比如说我们正在编程、正在做架构设计的时候，是在进行深度思考，如果这时候有一些紧急但不重要的事情插入进来，就会把我们从深度思考中拉出来，之后需要再花很多时间才能重新进入到这个状态里边去，甚至可能再也回不到当时的状态，从而丢失掉一些很好的想法。尤其是对一些创造性高的工作来讲，这是非常可惜的。一个人需要做全部事第二个缺点就是，一人公司往往要求我们一个人把整个链条上的所有事情都做了。原因很简单，因为整个公司就你一个人，你不做就没有人做。这样带来的一个非常明显的问题，就是工作量的大额增加。即使很多没有难度的事情，处理细节也会消耗大量的时间。另外还有一个更严重的问题，「麻雀虽小、五脏俱全」。它不但要求工作量，还对技能有要求。如果你缺乏特定的技能，就需要投入上百个小时的学习时间，而且还不一定能学得好。更有一些大型公司具有的资源，一人公司可能是不具备的，比如像做运营和销售时候的人脉资源。如果持续解决不了，就只能调整策略去绕开。矛盾和解决这里就出现了一个非常明显的矛盾：一方面是我们个人的时间精力非常有限（一周就50~60个小时）；另外一方面，我们又有非常大量的事情要做，因为公司就我们一个人，所有的事情都是要有人来做的。这个矛盾不解决，一人公司就运转不好。怎么解决呢？还是从矛盾的双方分别入手。提升效率第一个方向，一个人的时间和精力是有限的，那我们能不能提升效率。这个对于其他的行业来讲，可能会比较难，但是对于程序员来讲，可以考虑自动化和人工智能。如果在这两个方向上有突破的话，我们就可以把个人的时间和精力从重复劳动里面解放出来，让机器高效率的去处理重复的事情，把我们仅有的精力放到创造性的、开创性的业务上面来。对于通用业务而言，这个难度可能很大，但如果针对某些特定的业务，还是有可能构造出一人+机器人的效率放大结构的。这个结构一旦完成，就可以极大的提升效率。选择要做的市场另一个方面，我们还可以从选择要做的市场入手。虽然每个公司都有各种业务，但对于不同的市场，每一种业务的工作量是完全不同的。如果我们对进入的市场进行取舍，就可以把精力集中到那些工作量小的细分市场或者小众市场。比如我们只针对一个小众人群去做一个功能简单的软件，产品和开发的工作量就会小很多。但小众市场往往伴随获客问题。通用渠道首先是通用渠道的相对获客成本变高。比如同样是花一百万买开屏广告，面向大众的快消类产品，100 万人看，其中有 80 万都是潜在目标用户，最后点击可能是 20 万。但小众产品如果以同样价格去投放，100 万人中很可能只有 10 万人是目标用户，这样点击和转化就非常低了。相对而已，小众人群的获客成本反而高很多。定向投放除了通用渠道，我们还可以考虑做定向投放。所谓定向投放是说，对这个小众市场的行业网站和社区投放广告，或者向这个小众市场相关的意见领袖（KOL）做营销推广，再或者购买搜索关键字来导流。这部分的效果会好一些，但成本就要看这个行业竞争如何了，竞争激烈的比通用渠道投放还要贵。自制内容以上两种方式都是需要相当的市场预算的，对于一个刚刚启动还没有盈利的产品，更多的是没有什么预算的情况。这时候我们更多的会考虑自己来做内容、自媒体、成为 KOL。但做内容是需要持续不断投入的事情，在精力上的投入比较大。如果我们是一个人的公司，那一周50个小时的时间，花在视频录制剪辑加字幕发布上的时间，很可能高达20个小时。40%的时间花在做视频上，而这个视频它还不是立竿见影的，需要很长的时间去积累用户。这也是为什么你会看到很多的程序员，不是靠写软件挣钱，而是靠公众号卖广告挣钱。因为做内容就很费时间了，如果还要去开发一个软件，精力上很难支持住。自传播除了做内容，我们还可以在产品设计上发力。如果我们能让产品做到自传播 —— 就是让用户能不断地邀请来新用户，我们就不用花自己的精力在上边了。有网络效应类的产品比较适合做自传播相关功能，因为用户的收益和用户数量成正比的。有的产品不一定适合传播，比如定位是一个非常私密的个人数据类产品，就不一定适合通过分享内容来拉新。当然除了直接整合在产品中，我们也可以通过积分、物质回报来激励。比如现在已经很常用的分销返利或者邀请用户送付费会员等。小结对比以上方案，自传播应该是最好的渠道。需要付出的成本低，效果相对的也好。但它的问题在于如何优化产品，实现持续不断的自传播。这个是非常考验产品能力的。选择成为平台或生态的一部分除了选择市场以外，我们也可以选择成为平台或者生态的一部分。因为有平台在，我们就可以少做很多事情，甚至只需要关心业务逻辑。对于早年的苹果市场来讲，只要会开发应用可能就OK了。苹果商店会帮你进行销售，其他的事情都不用管。但这其实是理想状态，随着市场慢慢的从蓝海变成一个红海，我们会发现即使应用写完了，在市场里已经有很多同样的应用。我们又只能想办法去做营销相关的优化，在其他渠道去做一些推广。最后之前要做的事情，又回来了。因为对于每一个产品来讲，平台能提供的入口大家都能拿到，只能在这个基础上再竞争。用现在的词就是「内卷」，市场「卷」起来以后，我们就必须去做更多的事情。当然我们也可以不做海，选择去做一个小池塘 —— 就是说这个市场非常小，不太可能变成红海，因为没有那么多的人看得上它。但相应的，这种市场一是很难发现，二是往往随着趋势的发展，它可能会消失掉。可能短期内还能挣点钱，但最后这个市场可能就没了，你又不得不从头来重新寻找新市场，这也是非常痛苦的。苹果商店已经很成熟，所以比较卷。我们也可以去找一些新的平台和生态。比如 toB 的 SaaS 的话，国内可以看看企业微信和钉钉，国外的话可以看看 Airtable 这种新兴生态。如果进入的时间点合适，就能分到很多流量。当然，还是想之前说的，一旦市场竞争变激烈后，红利就会消失，剩下的就是大家真刀真枪的竞争，要做的事情又会变多，如此往复。分离非核心业务确定了市场以后，我们还可以对自己的业务进行取舍。比如，我们把非核心业务给分离出来。这些业务，我们可以外包、可以兼职。对于一些基础设施，我们可以「以租代建」。所谓「以租代建」，就是说以前我们需要什么系统都要自己开发，但是现在有各种各样的云平台、行业SaaS、以及不少按量付费的商业服务。比如商品代发，就已经有平台可以帮你来做。只要付一点钱，就可以让他们帮发货，自己就不用再搞个仓库或者店面来做中转。基础设施和制造业也正在逐渐的成熟和开放，比如3d打印、周边印制。最后它们都会抽象成一些API接口，我们在网上去调用它，付费，剩下的事情就自动完成了。这样的话，很多非核心的业务都可以被分离出来。当然这个是一个过程。不同国家和地区的市场、不同的行业成熟度都不同，需要自己去考察。强调「以租代建」对于程序员有特殊意义，因为对我们来讲写程序是很容易的事情，自己建一套系统也很方便的，而租用别人的还要花钱。以租代建的核心是节省时间和精力，如果我们只是通过不断开发各种系统来省钱，那这样跟我们去接外包挣钱不会有太大的区别。（这也是我自己经常犯的错误，需要时刻提醒自己）这里还有一个概念要明确，前面我们有提到说要分离非核心业务，那什么样的业务是核心业务呢。这里有一个简单的判断标准。在我们做的这个业务中，最稀缺的资源应该成为我们的核心业务。比如对网课平台来讲，能持续不断生产优势课程的讲师就是稀缺资源，如何聚集和维护这个群体就是核心业务。只要保证这点，其他资源都会慢慢聚集过来。而其他的部分，比如课程平台的开发，就是非核心业务，可以通过租用或者购买的方式来解决。增强优势除了降低工作量，我们更需要想办法来增强优势。因为降低工作量只是保证我们能把产品完成，但如果产品和其他竞品一样的话，并不会具有优势。从用户的角度来讲，大部分的用户并不关心产品背后的开发者是个人还是大企业，更看重付出的成本和得到的收益。所以我们最终还是要回到产品价值上来，为用户提供不可或缺的价值。从标准品到独立品类我们可以给一些标准化的产品去添加独有的特色功能，从而把它变成一个独立的品类。比如我之前做过一个软件叫做福利单词，它是一个背单词的软件。在任何一个市场上，这类软件都是一大堆。但福利单词有一个额外的功能，就是在输入单词正确时，会给你显示一张高清的萌妹子福利图。这就带来了完全不同的体验，在它和那些千篇一律的背单词软件中划出了界限，成为了一个同时融合叫教育和娱乐功能的独立品类。如果你觉得这点小功能还不足使其以成为一个独立品类的话，可能我之前做的学前端 RPG 游戏 更明显一些。副产品优势另外一点就是，我之前在「从精益开发到精益副业」的视频 中提到的「副产品优势」。虽然是在运营一人公司，但不一定非要全职来做这件事情。也可以一边上班，一边把一人公司作为副业来做。在这种情况下，我们就会多出来一个优势，我叫它「副产品优势」。核心是说，因为有主业，所以可以保证基本收入和生活品质；在主业工作里边产生的副产品，可以进一步加工为商品，作为副业来销售。这样既没有生活压力，又降低了副业的制作成本。虽然刚开始可能收益的绝对值不大，但可以慢慢把它做大，直到有了充足的现金流，再把它当成主业来做。营销优先还是开发优先除了上边提到的这些，在实际运营中，我们还经常会遇到很多其他需要选择的地方。比如，在优先度上，到底是应该营销优先还是开发优先。对于大一点的公司，有足够的人力，营销和开发都是不同的部门去做，所以可能不存在这个问题。但是对于一人公司来讲，其实很难一边做营销，一边不停的去给产品开发新功能。因为营销和运营不是一个短时间的事情，需要持续不断的进行。如果你不去做，很可能流量就没有了，没有流量就没有转化、也就没有收益。另一方面，如果我们不断的开发新功能，时间长了就会有一堆项目需要维护，维护成本累加起来会很大。假设有 50 个项目，平均每个项目一年升级维护一次，每次两天，那么就会花掉我们工作时间的 40%。如果这些项目是免费的还好，可以随时关闭。但如果每个项目都有那么几十个付费用户，既不挣钱就要不断的提供维护和客服，是非常麻烦的。这之间的取舍，会对我们的一人公司的运营产生很大的影响。营销优先营销优先模式是说，我们只开发一个很简单的产品，维持一个很小的功能集。然后不断的去为这个产品寻找新用户。这个模式的优点是，我们开发的功能很少，维护成本比较低，不用不停地开发。而它的缺点就在于，我们需要持续不断的进行营销，不断的获取新的用户。最后可能会发现，越来越多的精力都用到了营销上，用到了拉新上。最后完全变成了做内容或者做业务的竞争。即使这样，如果能做好营销，那其实也不错。但大部分程序员并不喜欢和擅长做营销，而且在没有市场预算的情况下，要成为影响力不错的营销号是需要花很多的时间和精力，甚至还有运气的。关于营销的难度，很多同学没有基本的概念。我这里有一个自己常用的参考转化率，是在以微博为主要流量入口的环境下测试得到的。从信息流展示次数到有效付费购买之间，转化率略为 1~5‰ 。当然，具体的数据会因为营销材料、产品需求有很大的不同（这其实是优化得不错的数据了），当你自己测试过后，可以得到自己的转化率数据。如果你没有自己的数据，那么不妨以 1‰ 为基础简单评估营销难度。也就是说，如果想要获得 100 个购买，大概需要十万次的有效阅读，那么首先以 10 万的触达为基础思考如何达到。开发优先另一种模式叫做开发优先。是说我的营销能力可能不够，那我就面向同一群用户，不做营销了；改为针对已有的这些用户，不断的为他们开发付费产品。这其实就是凯文·凯利那篇《1000个铁杆粉丝》的文章中的逻辑。文章中说，如果你有1000个铁杆粉丝，无论你卖什么东西他们都会买的那种，那你只需要面向他们不断推出产品，就可以维持不错的生活。这种模式的优点是，我们不用到处去做营销，不用过多的去做我们（可能）不擅长的领域。而缺点就是，开发很累，维护也很累。如果不能形成规模效应，就要不断的开发付费应用，每一个产品可能就会做得很浅。你可能要问，为啥我要不断的开发应用，我只开发一个应用，然后不断的收钱不行么？答案当然是可以，但难度有点高。为什么要这么说呢，我们来计算下。假设我们期望每个月的毛收入在 5 万（除去成本和税以后大概在 3 万），如果以 1000 个铁杆粉丝来算，那每一个用户，就需要每个月消费50块钱。这其实是一个很高的费用。从开发者的角度来讲，你可能觉得这个费用不高，但从用户的角度来讲，是很高的。如果你收集下自己和周围的人在软件和互联网服务上的实际开销，就会明白。我之前在微博上发过一个提问，从评论来看，即使一年花销达到200左右的产品和服务都不太多，而且基本是资源导向的，比如视频音乐会员、电商外卖会员。很少有工具类软件能达到这个数的。所以，to C 的工具软件和 SaaS 里边，要找到每年能持续挣600块钱的需求，难度相当高。to B 的服务在价格上相对容易上去，但是在获客成本和开发工作量上又相对较高。如果能在其中找到一个好的需求，倒是很不错。总之，如果我们找不到这样的需求，就只能退而求其次，用多个付费服务来提升客单价。实际操作前面说了这么多的分析，但离落地还有一点点距离。在最后一部分里，我们就来思考下怎么落地。发现一个趋势寻找一个小市场针对这个市场面向 1000 个用户，提供一个每月 50 元定价的产品或者面向 10000 个用户，提供一个每月 5 元的产品开发产品并持续运营发现趋势首先，我们应该集中精力在发现趋势上。以前创业的时候，我经常思考一个问题。凭什么一个创业公司可以以很小的团队，在很短的时间，用很少的资源崛起。以前的人都没这些人聪明吗？显然不是。后来在阅读一些创业方法论的时候才明白，这是因为创业公司发现了趋势，找到了变化。因为这些变化是新出来的，所以以前的商业虽然有能力，有资源，但难以未卜先知。新的趋势就像山脉的崛起，将原来严丝合缝的商业逻辑撑开，出现了新的商业路径。发现趋势，就是要看到变化。个人的努力虽然重要，但也要考虑时代的进程。尤其对于一人公司来讲，跟上大趋势，才能放大自己有限的精力投入。关于趋势发现，简单粗暴的方式是读研究报告。比如艾瑞网会定期更新一些简版报告，从里边的数据可以发现很多有意思的趋势。不过这些报告更多的是面向创业投资领域，未必适合一人公司。像我经常在微博上提到的 Trends.vc 这种专门为独立开发者和一人公司准备的分析报告，就更有针对性一些。寻找一个小市场正在高速增长的赛道里往往有大量的巨头和创业公司，从资源上来讲，一人公司在这些领域很难占据优势。但在这些赛道周边，通常都存在一些年收入最高几千万人民币的小市场，这些市场大厂和资本是看不上的，反而是一人公司很好的切入点。如果能结合趋势，选择到一个现在看起来很小，但是会随着趋势慢慢变大的市场，就能进一步保证将来的收益。早期进入，持续深耕，当这个市场成长起来时，即使是一人公司，也会具备很强的竞争力。设计产品然后就是针对这个市场设计产品了。根据自己的能力，可以有两个选择：面向 1000 个用户，提供一个每月 50 元定价的产品或者面向 10000 个用户，提供一个每月 5 元的产品当然，其实你还可以进一步调节用户数和月定价，只要乘起来是 5 万就可以。而且 5 万也只是一个参考值，做不到还可以调低。如果一个产品做不到，可以把一个改成两个。这里量化数据的意义在于，给出一个清晰的模式，用来做前期的参考。参考依据在设计的过程中，我们可以准备很多备选方向和产品，通过比较选出最适合自己的。以下是我觉得有用的参考依据：市场安全性：发展趋势（是否快要没了）、竞争情况（是否红海）客户价值：MRR（每月经常收入预期）、LTV（客户生命期价值）获客渠道和成本：是否能够自传播，传播系数工作量：MVP（最简可行产品）所需工时、迭代和升级维护成本资源匹配度：是否有自己难以掌控的资源开发和持续运营接下来就是 MVP（最简可行产品） 的开发，PMF（产品市场契合） 的寻找以及后续的持续运营（或者转型）了。这一部分的内容可以参考精益创业系列方法论。一人公司的基础设施无公司运营虽然写的是「一人公司」，但其实我们并不需要一开始就注册一家公司。因为会带来办公地址和记账的固定成本。一般来讲，最理想的方式是以个人身份运营业务，在有了稳定的现金流以后，再注册公司。在国内，很多平台对个人主体并不友好，需要自行寻找替代方案。以 Web 业务为例，我们需要和平台对接的部分通常包括：第三方用户登入（比如微信登入）支付（没有这个就没法收钱）消息触达（群发通知）其中，① 和 ③ 算是加分项，② 则是付费业务不可绕过的。个人支付解决方案就我了解，在目前个人主题可用的支付方案中，唯一安全而且稳定的是「小微商户」及类似方案。这种方案其实是支付平台（比如微信、支付宝）在提供底层能力，只是通常为了防止被滥用，不开放直接申请，而改用服务商代理的形式。正因如此，它可以做到资金完全走支付平台（而不是你的支付服务商），保证了资金的安全而且没有二次清算问题。国内提供基于小微商户支付方案的有好几家，通过搜索可以发现有 xorpay 、payjs 等服务商。但不少服务商不太厚道的自己搞了一个审核流程来收取审核费或者叫开通费。我自己使用的是面包多推出的支付平台：面包多Pay。官网注明的特点如下：没有开通费，交易时才付费，非常适合启动期的项目，费率为每笔交易 0.1 + 2%支付完成以后可以显示文字、图片或者跳转到网址，一些简单场景就不用写代码来接入了不过对我而言，最主要的考量还是平台稳定性，现在面包多每月结算数百万，这个支付平台其实就是其业务核心「闪电结算」平台的扩展，属于主业副产品，因此不挣钱应该也会维护下去。一个 Tips：面包多Pay（其他平台我并未交费试用，因此不做评价）的支付接口里边，有一个获取 openid 的接口。它其实可以用来做微信体系下的用户登入。换句话说，无需认证公众号就可以实现微信用户的登入和支付。这就非常适合个人。消息触达常规操作是，在登入时要求用户补全邮箱、手机号并将其作为消息触达主通道。但邮箱时效性差、短信被拦截可能性高，且费钱。因此微信成为了发送通知实时性和到达率最高的通道。但是未认证公众号只能被动回复消息，均不能主动发送消息。即使认证公众号，模板消息权限正在收回。经过比较，我认为目前适合个人的消息触达方式是微信机器人/QQ机器人。通过关注机器人，发送 token 实现账号关联，之后就可以通过机器人推送消息给用户了。我知道的方案如下：微信机器人方案： wechaty (网页版协议免费，其他协议收费)QQ机器人方案：mirai （未亲测）机器人方案除了可以用作消息推送，还可以用作登入。比起通过支付接口的 openid api 登入而言，没有因 openid 改变导致用户无法登入的风险。公司注册如果你不能找到满意的个人主体解决方案，那么就只能考虑注册公司了。需要留意的是，即使注册公司资质，其实也有个体工商户和公司两个选项。个体工商户的申请流程虽然简单，但其背后是无限责任。而有限责任公司则以注册资金作为上限，更容易规避风险。公司注册不是本文的内容范围，在此就不做展开了。
交付物软件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、以上内容建议附加进商务合同，成为其中一部分。
软件外包存在风险，外包人员技术、态度、交付能力，如果想通过合同或者诉讼降低风险，由于太多的未知因素和太多的主观性，不现实。因此唯一的外包原则应该是：如果外包人员做得不好，有能力随时终止合作且可控费用损失和项目交付。可以尝试渐进式方法，首先废除传统开发外包大瀑布方式（例如签订需求URS、项目总金额、进度款支付）（不过目前大部分外包会坚持使用瀑布法，并签订大额的预付合同），尝试新方案，项目按照功能或者阶段划分为多个子合同，做小项分包，或者改为签订人力外包合同。针对我们想要构建的功能，拟定一个顺序列表。找几名开发人员，最好是独立的自由职业者，但如果同意以下流程，开发工作室也没问题。对于每名开发人员，挑选列表中最重要的功能，与他们讨论功能需求、预算和成本。让他们实现那个特性并测试。让一名内部人员审核他们的 PR，测试升级后的 App，并标出有问题的地方。符合要求后，合并并部署该特性，这样，所有创始人/用户就可以继续审核该 App，并提供反馈或者根据需要调整。如果我们对他们所做的工作感到满意，就挑选下一个我们希望他们实现的功能，然后再次重复这个过程。如果我们对他们的工作不满意，就解雇他们，并寻找替代者。当前需要做的工作，整理敏捷开发平台或者公共开发平台，并且参照以下原则：客户合作胜于合同谈判个体和互动胜于流程可运行的软件胜于详细的文档响应变化胜于遵循计划参考文章：Experiences working with an Outsourced Dev Shop
亲测推荐 2021 年 SaaS 技术栈：Docker、Django、Traefik 和 IntercoolerJS
我最近发布了个人对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 用于 Web 的容器化 DjangoDjango 很好地支持发布到容器中，我多年以来一直这么用。我反复强调开发环境和生产环境匹配的重要性，Docker 为我实现了一切。我在 2021 年新推出了一个 Django 项目，用做新项目的模板，参见https://github.com/simplecto/django-reference-implementation。实现异步任务的 Django 命令我使用做为标准框架组成的自定义Django命令实现异步任务。该模式采用具有 sleep()的 while 循环，轮询数据库相关操作，并采取相应的动作。截止 2021 年，我已使用这一模式运行一个网站截屏项目一年多，回报丰厚。该项目每日对 1500 个网站做截屏，所有操作由 Django 命令计划和管理。项目地址：https://github.com/simplecto/screenshots。IntercoolerJS 降低了复杂性这里如果展开说，需推出多个帖子，恐怕内容太长，以至于不会有人愿意读。我结合 JQuery 和这个小型 JavaScript 库，实现部分类似单页应用的效果，尽管事实上并非单页应用。IntercoolerJS 保留了 Ajax 的传统优点，从后端 HTML 更新 DOM，无缝且平滑，非常便于实现用户登录和更新小型表单等元素。强力推荐访问IntercoolerJS官网。其创立者在 2021 年继承发展了 IntercoolerJS，推出了HTMX。Sentry 捕获生产中错误任何应用都会出错，但不应向用户展示。Sentry 提供了一种捕获生产中软件缺陷的易用便捷方式，其特性包括：开源许可，可在生产中任意部署。只需在 Django 项目的 settings.py 中添加几行配置，即可生效。与 Git 代码库和问题追踪系统紧密集成，提供全生产环境的缺陷可追踪能力。另一个优点是，随时能在生产环境中禁用。更多信息，可访问Sentry官网。Bitbucket Pipelines 替代 CI/CD2021 年，我不在个人项目的部署中使用 CI/CD。其中存在太多工具，复杂性高。我只是使用 PyCharm 运行测试，然后从开发设备直接交付生产环境。当前存在多种 CI/CD 解决方案，但是我推荐 Bitbucket 提供的 Pipelines 的服务。该服务每月提供数百分钟的免费使用，只需很少费用就能提供自上而下的功能。我自己在使用中很少碰到问题，很喜欢它们的 YAML 配置文件。我使用 bitbucket-pipelines.yml 文件，实现跨多个 Docker 容器的完全端到端测试，加载数据库，并在几分钟内执行数以百计的测试。该服务是我们团队高效的关键，支持生产环境中每日五次以上 Push。更多信息，访问Bitbucket官网。ZeroTier 实现 VPN最后，推荐一种在很大程度上是可选的、但是最好应具备的技术。Zerotier 是一种独树一帜的网络/VPN 服务，我用其连接所有的个人计算机。它可穿透防火墙联通家庭和办公场所，一分钟即可配置好。如果所有设备使用 ZeroTier，就可以避免 SSH 中令人头疼的密钥管理，单机上共享带宽。Zerotier 可运行在 Linux、Mac、Windows、Android 和 iPhone 上，覆盖大部分设备。ZeroTier 的一个问题在于，我并不完全了解它的工作机制。和 MacOS 和 iPhone 类似，它们会按用户期望工作，并不出问题，只是从用户体验角度看有些不爽。但对于一名 CTO，谁又会去关心具体的细节呢？总结希望上面的深入介绍能激发读者对 Docker、Django、Traefik，尤其是 IntercoolerJS 的兴趣。它们简单、易于使用，能在适当时大展身手。原文链接： Docker, Django, Traefik, and IntercoolerJS is My Go-To Stack for Building a SaaS in 2021https://www.infoq.cn/article/W4leI4XZ32eSTqFJ8qPl
我成功开发了一个 SaaS 项目，技术栈是这样的
作为一名忠于内心的工程师，每当我看到一家公司发布有关它们技术栈的文章时，我都会泡一杯咖啡，坐下来耐心阅读，看看有没有新的发现。了解其他公司业务背后隐藏的一些技术十分有趣。就像娱乐八卦一样，只不过这是技术层面的探索。几个月前，我开始开发另一个 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 服务中。这在灾难恢复时也会对我有所帮助。我只需要运行一些命令，几分钟后，我的应用服务就可以重建并能正常运行了。当我将应用从 DigitalOcean 迁移到 Linode，以及最近往 AWS 迁移时非常有用。所有的操作都通过代码描述和执行。因此，即使在几年后，我也很容易的跟踪项目的相关部署和运行情况。现在所有的公司都拥有 AWS IAM 策略或者 VPC 子网，这些都是通过一些 UI 界面点击操作完成的，现在所有人都离不开这一功能，因为确实给用户带来了很多便利。Terraform：我使用 Terraform 来管理大部分云基础架构。在我的 Terraform 清单中声明了诸如 EKS 集群、S3 存储、角色和 RDS 实例之类的一些配置。这些数据会同步到另外的加密 S3 存储，以避免我开发用的笔记本电脑发生故障而无力回天。Docker：我会将所有服务构建为 Docker 映像。甚至有状态的组件（比如 Clickhouse 或 Redis）也作为 Docker 容器打包并运行在我的集群中。这也让我的应用服务可移植性非常高，因为我可以在能够运行 Docker 的任何地方运行它。Kubernetes：它极大地解放了我繁琐的工作。我并不是盲目地向所有人进行推荐，因为在工作的这些年里，我使用它解决了好几次大型的生产故障。为公司及时解决生产问题，让我感觉十分自豪。我还用它进行容器化应用的管理，这也帮我减轻了工作负担。GitHub Actions：过去，我常常使用的是CircleCI（这个用起来也不错），但是对于这个项目，我更喜欢使用 GitHub Actions，因为它删除了需要访问代码库以及部署密码的一个不必要的服务。但是，CircleCI 同样具有很多不错的功能，我仍然向大家推荐它。基础设施服务我从最开始使用月费 5 美元的 DigitalOcean 单实例服务器开始，逐步转向使用 Kubernetes 来管理服务，因为我正在彻底改变 Kubernetes 提供的一些开箱即用的功能（比如：服务发现、TLS 认证、负载均衡、日志滚动管理、滚动发布、容量管理等）。但是，即使在较大的服务器实例上，使用 Kubernetes 管理的 DigitalOcean 也同样存在可靠性问题。集群 API 服务经常会随机地停止工作并且无法恢复，这会破坏包括负载均衡在内的许多集群服务，也就意味着服务停机无法对外提供正常服务。每当发生这种情况时，我会重新创建一个新的集群，尽管使用 Terraform 可以很轻松的实现，但是这并不会增加大家对其托管服务可靠性的信心。我怀疑是他们的资源不是特别充足导致的，考虑到他们的服务收费较低，因此这是可以理解的。不幸的是，几周后，我就无法解决上面提到的问题了。这就是为什么我决定迁移到Linode的原因，在接下来的一个半月的时间里，系统再也没有出现过任何问题。但是，AWS 向我抛来了更加诱人的优惠，所以我最近又做了一次迁移。AWS 还支持使用托管服务比如 RDS 来减轻 PostgreSQL 的压力，这对我来讲是个很大的优势。我的迁移工作没有那么复杂，因为我的所有基础架构都是通过 Terraform 和 Kubernetes 配置清单进行描述的。系统迁移可能会花费或长或短的时间，所以一定要有耐心。这一方面的话题可以在其他文章中找到。AWS：提供可预测服务以及大量的托管服务。我主要在全职工作的时候使用过它，所以我没有花费很多时间来处理问题。我使用过的 AWS 服务主要有 EKS、ELB、S3、RDS、IAM 以及专用 VPC，未来我可能会使用 Cloudfront 和 Kinesis 服务。Cloudflare：我主要将其用于 DDoS 保护、DNS 服务以及负载各种静态资源的边缘缓存（目前减少了 AWS 的 80％网络出口带宽费用——它们的带宽定价是在是太贵了！）。Let’s Encrypt：免费的 SSL 证书授权服务。我在 Kubernetes 集群中使用了 cert-manager，它根据我的入口规则自动颁发和更新证书。Namecheap：我常常使用的域名注册服务商。它允许 MFA 登录，这是一个十分重要的安全功能。与其他域名服务商不同，它们不会每隔几年就会突然增加域名的高昂续费费用，十分的良心。Kubernetes 组件以下组件可以自动完成大部分开发运维工作。我也使用其他的一些组件，但是我最想推荐给大家的是下面几个：ingress-nginx：一个性能稳定的使用 NGINX 作为反向代理和负载均衡的网络入口控制器，控制入口流量到集群节点的网络流量负载均衡。cert-manager：该组件可以按照入口规则中的定义自动颁发和更新 TLS 证书。external-dns：借助 DNS 服务（例如 Cloudflare）同步公开 Kubernetes 服务和网络入口。prometheus-operator：可以自动监控大部分的服务，并可以通过 Grafana 对数据进行展示。flux：可以实现在 Kubernetes 中进行连续交付。当我要发布新的 Docker 映像时，可以通过拉取镜像进行部署。命令行工具我使用的命令行工具有很多，但经常使用且值得推荐的就下面这几个：kubectl：与 Kubernetes 集群进行交互的工具，可以对日志、pod 和服务进行监控，并且可以 SSH 登陆到运行中的容器。stern：Kubernetes 的 pod 日志查看工具，方便易用。htop：交互式系统进程查看工具，真的比系统自带的 top 工具好用。cURL：网络请求工具，可以对请求头进行检查。HTTPie：与 cURL 工具类似，但是对于 JSON API 而言更简单易用。hey：网络负载测试工具，可以提供详细的延迟分布报告。监控工具Prometheus：可以高效地存储时间序列数据并进行监控。可以追踪所有群集和应用程序的性能指标。比使用 Cloudwatch 进行应用程序监控要便宜得多。Grafana：可以对 Prometheus 监控数据进行展示。所有的展示数据以 JSON 文件进行描述，并在 git 仓库中进行版本控制。Sentry：对应用程序异常情况进行监控。该工具在发现带有其他元数据的未处理错误时进行告警通知。Loki：受 Prometheus 启发而发展出来的一款日志聚合系统。它附带了 prometheus-operator 功能，可以帮助我在整个群集中对海量日志进行搜索。邮件工具Fastmail：我优先选用的商务电子邮箱，功能齐全且稳定性高。Postmark：我主要将其用于交易电子邮件（电子邮件验证、每周报告、登录安全警报、密码重置等）的收发。他们的电子邮件传输速度非常快，邮件移动应用程序在业界也是一流的。开发工具GitHub：源代码托管及版本控制工具。PyCharm：可能是 Python 最好的 IDE 工具。使用它可以轻松地重构和导航整个项目代码，而不仅仅是单个代码文件。 即使使用大型动态代码库，该工具的使用表现也很好。VS Code：非常适合 Typescript / React 编程，并且可以用作通用代码编辑器。Poetry：Python 打包及有锁文件的依赖管理工具。Yarn：具有本地缓存的快速 JS 依赖项管理工具。Invoked：我使用它将所有代码库任务包装在可调用的命令中。例如，使用inv build可以准备静态资源，打包前端/后端环境依赖，并生成 docker 映像。这样，就可以在本地执行与 CI 运行的相同的命令。其他工具Panelbear：当然，除了 Panelbear，还有什么能比 Panelbear 更好的工具来跟踪 Panelbear 的网站分析呢？内部测试是有很大收益的，因为我就是我自己的客户。Healthchecks.io：当计划作业未能正常运行时，就会通过电子邮件或者 whatsapp 通知到我。它也是基于 SaaS 的辅助程序，这个工具我使用了好几年了，非常高兴可以推荐给大家。Trello：我使用它来记录和跟踪一些问题、需求及想法等等。Figma：用于为目标页面快速制作模型、横幅和插图，它取代了Sketch作为我的入门工具。原文链接https://panelbear.com/blog/tech-stack/
写代码有这16个好习惯，可以减少80%非业务的bug
每一个好习惯都是一笔财富，本文整理了写代码的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) } 写完代码，脑洞一下多线程执行会怎样，注意并发一致性问题我们经常见的一些业务场景，就是先查下有没有记录，再进行对应的操作（比如修改）。但是呢，(查询+修改)合在一起不是原子操作哦，脑洞下多线程，就会发现有问题了，反例如下：if(isAvailable(ticketId){ 1、给现金增加操作 2、deleteTicketById(ticketId) }else{ return "没有可用现金券"; } 为了更容易理解它，看这个流程图吧：1.线程A加现金2.线程B加现金3.线程A删除票标志4.线程B删除票标志显然这样存在「并发问题」，正例应该「利用数据库删除操作的原子性」，如下：if(deleteAvailableTicketById(ticketId) == 1){ 1、给现金增加操作 }else{ return “没有可用现金券” } 因此，这个习惯也是要有的，「写完代码，自己想下多线程执行，是否会存在并发一致性问题」。获取对象的属性，先判断对象是否为空这个点本来也属于「采取措施规避运行时异常」的，但是我还是把它拿出来，当做一个重点来写，因为平时空指针异常太常见了，一个手抖不注意，就导致空指针报到生产环境去了。所以，你要获取对象的属性时，尽量不要相信「理论上不为空」，我们顺手养成习惯判断一下是否为空，再获取对象的属性。正例：if(object!=null){ String name = object.getName(); } 多线程异步优先考虑恰当的线程池，而不是new thread,同时考虑线程池是否隔离为什么优先使用线程池？使用线程池有这几点好处呀它帮我们管理线程，避免增加创建线程和销毁线程的资源损耗。提高响应速度。重复利用。同时呢，尽量不要所有业务都共用一个线程池，需要考虑「线程池隔离」。就是不同的关键业务，分配不同的线程池，然后线程池参数也要考虑恰当哈。之前写过几篇线程池的，觉得还不错，有兴趣的朋友可以看一下哈一文读懂线程池的工作原理（故事白话文）面试必备:线程池解析源码分析-使用newFixedThreadPool线程池导致的内存飙升问题手动写完代码业务的SQL，先拿去数据库跑一下，同时也explain看下执行计划。手动写完业务代码的SQL，可以先把它拿到数据库跑一下，看看有没有语法错误嘛。有些小伙伴不好的习惯就是，写完就把代码打包上去测试服务器，其实把SQL放到数据库执行一下，可以规避很多错误的。同时呢，也用「explain看下你Sql的执行计划」，尤其走不走索引这一块。explain select * from user where userid =10086 or age =18; 调用第三方接口，需要考虑异常处理，安全性，超时重试这几个点。调用第三方服务，或者分布式远程服务的的话，需要考虑异常处理（比如，你调别人的接口，如果异常了，怎么处理，是重试还是当做失败）超时（没法预估对方接口一般多久返回，一般设置个超时断开时间，以保护你的接口）重试次数（你的接口调失败，需不需要重试，需要站在业务上角度思考这个问题）? 简单一个例子，你一个http请求别人的服务，需要考虑设置connect-time，和retry次数。 ?如果是转账等重要的第三方服务，还需要考虑「签名验签」，「加密」等。之前写过一篇加签验签的，有兴趣的朋友可以看一下哈程序员必备基础：加签验签接口需要考虑幂等性接口是需要考虑幂等性的，尤其抢红包、转账这些重要接口。最直观的业务场景，就是「用户连着点击两次」，你的接口有没有hold住。? 幂等（idempotent、idempotence）是一个数学与计算机学概念，常见于抽象代数中。在编程中.一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数，或幂等方法，是指可以使用相同参数重复执行，并能获得相同结果的函数。?一般「幂等技术方案」有这几种:查询操作唯一索引token机制，防止重复提交数据库的delete删除操作乐观锁悲观锁Redis、zookeeper 分布式锁（以前抢红包需求，用了Redis分布式锁）状态机幂等多线程情况下，考虑线性安全问题在「高并发」情况下，HashMap可能会出现死循环。因为它是非线性安全的，可以考虑使用ConcurrentHashMap。所以这个也尽量养成习惯，不要上来反手就是一个new HashMap();? Hashmap、Arraylist、LinkedList、TreeMap等都是线性不安全的；Vector、Hashtable、ConcurrentHashMap等都是线性安全的 ?主从延迟问题考虑先插入，接着就去查询,这类代码逻辑比较常见，这「可能」会有问题的。一般数据库都是有主库，从库的。写入的话是写主库，读一般是读从库。如果发生主从延迟，很可能出现你插入成功了，但是却查询不到的情况。如果是重要业务，需要考虑是否强制读主库，还是再修改设计方案。但是呢，有些业务场景是可以接受主从稍微延迟一点的，但是这个习惯还是要有吧。写完操作数据库的代码，想下是否存在主从延迟问题。使用缓存的时候，考虑缓存跟DB的一致性，还有（缓存穿透、缓存雪崩和缓存击穿）通俗点说，我们使用缓存就是为了「查得快，接口耗时小」。但是呢，用到缓存，就需要「注意缓存与数据库的一致性」问题。同时，还需要规避缓存穿透、缓存雪崩和缓存击穿三大问题。? 缓存雪崩：指缓存中数据大批量到过期时间，而查询数据量巨大，引起数据库压力过大甚至down机。缓存穿透：指查询一个一定不存在的数据，由于缓存是不命中时需要从数据库查询，查不到数据则不写入缓存，这将导致这个不存在的数据每次请求都要到数据库去查询，进而给数据库带来压力。缓存击穿：指热点key在某个时间点过期的时候，而恰好在这个时间点对这个Key有大量的并发请求过来，从而大量的请求打到db。