代码字体mono
by Chetan Sharma
由Chetan Sharma
如何构建代码存储库:Multi,Mono或Organic? (How to Structure Code Repositories: Multi, Mono, or Organic?)
The newest debate in town is whether you should keep your services in a single repository or multiple small repositories.
城里最新的争论是您应该将服务保存在单个存储库还是多个小型存储库中。
The idea of multiple small repositories is that code for each of your app’s micro service is kept in a repository of its own. With a mono-repo, you keep the all the code in a single repository and deploy the code as microservices.
多个小型存储库的想法是,每个应用程序微服务的代码都保存在自己的存储库中。 使用mono-repo,您可以将所有代码保存在单个存储库中,并将代码部署为微服务。
So which should you use? Being too rigid about any one approach — without considering the purpose and uses of each approach — can lead to negative outcomes in the long run. If you’re aware of when to use each, it can increase your productivity and improve your project.
那么您应该使用哪个呢? 从长远来看,对任何一种方法过于僵化(不考虑每种方法的目的和用途)都可能导致负面结果。 如果您知道何时使用它们,则可以提高生产率并改善项目。
要改变规则,我们首先需要了解它们为什么存在。 (To bend the rules, we need to first understand why they exist.)
A common recommendation is to have an independent repository for every app/service. But why? Because, by having one repository for each micro-service, we gain:
常见的建议是为每个应用程序/服务都有一个独立的存储库。 但为什么? 因为,通过为每个微服务拥有一个存储库,我们可以获得:
Freedom to write code differently and independently of all other services.
自由编写代码不同,独立于其他所有服务。
Velocity in making code changes while fixing bugs, making updates, testing and deploying. Since changes only have to be tested in a single repository, deployment of the code is faster and more reliable.
在速度修改代码,而修正错误,进行更新,测试和部署。 由于更改只需在单个存储库中进行测试,因此代码的部署更加快捷,可靠。
Separation of code as independent units, which prevents bug leakages and performance bottlenecks between services.
将代码分隔为独立的单元,从而防止错误泄漏和服务之间的性能瓶颈。
Clear ownership of each repository and service, which is especially helpful for large teams.
明确每个存储库和服务的所有权 ,这对于大型团队尤其有用。
但是,为什么会出现单一回购协议的需求? (But why did the need for mono-repos arise?)
Clearly, the multi-repo approach has its benefits. But it also comes with its own challenges, especially in projects with a large number of microservices that use the same frameworks, language, tech stacks etc.
显然,多重回购方法有其好处。 但这也带来了自己的挑战,特别是在使用相同框架,语言,技术堆栈等具有大量微服务的项目中。
A few of these challenges are:
这些挑战包括:
Enforcing standards and best practices across all repositories. With a multi-repo, changes in code standards and best practices need to be replicated across repositories. With a mono-repo, all the changes can be done in one place.
在所有存储库中执行标准和最佳实践 。 对于多仓库,需要在存储库之间复制代码标准和最佳实践的更改。 使用单仓库,所有更改都可以在一个地方完成。
The effort of maintaining shared or common components. Security patches, version upgrades and bug fixes involve making sure that these changes are made across all repositories and that they work seamlessly everywhere. (On a side note, the repeated code in each service also bloats its size.) In a mono-repo, we can make updates in one place, saving both time and headaches.
维护共享或通用组件的努力。 安全补丁,版本升级和错误修复涉及确保在所有存储库中进行这些更改,并且确保它们在任何地方都可以无缝运行。 (顺便说一句,每个服务中重复的代码也增加了它的大小。)在单一仓库中,我们可以在一个地方进行更新,既省时又省力。
End-to-end testing in tandem with closely related or dependent services right from the developer’s machine. By having all the code in one place, we ease the process of starting up all the related services and running end-to-end tests.
直接从开发人员的机器进行与紧密相关或依存服务的端到端测试 。 通过将所有代码放在一个位置,我们简化了启动所有相关服务和运行端到端测试的过程。
On-premise deployments of code for other businesses. By deploying a mono-repo as microservices, we save time and reduce the redundant effort of bootstrapping each repository.
用于其他业务的本地代码部署 。 通过将单存储库部署为微服务,我们可以节省时间并减少引导每个存储库的冗余工作。
Clearly, there are advantages and disadvantages to both approaches, and each approach will have its own benefits under different circumstances.
显然,这两种方法都有优点和缺点,并且每种方法在不同的情况下都会有自己的优点。
Therefore, we have adopted the approach of remaining flexible and using both multi-repos and mono-repos, but only after completely understanding why we have chosen to use each for each service. This has led us to have multiple repos containing several microservices, segregated in a way that has made:
因此,我们采取了保持灵活性的方法,并同时使用了多仓库和单仓库,但要完全理解为什么我们选择为每种服务使用每种仓库。 这导致我们有多个包含多个微服务的存储库,这些存储库以如下方式隔离:
- Maintenance and updates both easy and fast. 维护和更新既简便又快速。
- Locating the code to debug or change much more structured. 查找要调试或更改的代码要结构化得多。
- Onboarding new teammates easier. 新队友的入职更加轻松。
我们如何决定使用哪种类型的存储库 (How we decide what type of repository to use)
The following considerations have helped us decide when to use mono-repos vs. multi-repos.
以下考虑因素帮助我们决定了何时使用单存储库和多存储库。
1.考虑将用作服务基础的代码。 (1. Think about the code that will serve as the foundation of the service.)
Begin by identifying any similarities in code, maintenance, and updates. If multiple repositories have identical code, it would be better to club them in a single repository.
首先确定代码,维护和更新中的任何相似之处。 如果多个存储库具有相同的代码,最好将它们合并在一个存储库中。
The freedom to write code differently and independently in a service is one of the benefits of multiple small repositories. But often services will have a lot of identical scaffolds if they use the same language, framework, logging, bootstrap scripts, middle-wares, etc. Reusing these shared scaffolds saves time.
在服务中以不同方式独立地编写代码的自由是多个小型存储库的好处之一。 但是,如果服务使用相同的语言,框架,日志记录,引导脚本,中间件等,则它们通常会有很多相同的支架。重用这些共享的支架可以节省时间。
For example, Collect — our primary data collection tool — has multiple micro-services built on an identical framework. These services are built on Node.js, Express and Parse Server. They share a lot of libraries like Winston, Mongoose and other third-party integrations. Earlier, when each of these services had a repository of its own, updating or fixing a bug in any of these shared modules meant updating and testing each repository separately. This was slow and cumbersome.
例如, 收集 (我们的主要数据收集工具)具有在相同框架上构建的多个微服务。 这些服务基于Node.js , Express和Parse Server构建。 他们共享许多库,例如Winston , Mongoose和其他第三方集成。 早先,当这些服务中的每一个都有自己的存储库时,更新或修复这些共享模块中的任何一个中的错误就意味着分别更新和测试每个存储库。 这既缓慢又麻烦。
However, when we clubbed them together in a mono-repo, testing and updating the shared modules became easier and faster. Applying security patches and enforcing standards became easier since developers can do all the changes in once place.
但是,当我们将它们组合成一个单体仓库时,测试和更新共享模块变得更加容易和快捷。 由于开发人员可以一次完成所有更改,因此应用安全补丁和执行标准变得更加容易。
The potential risk of a mono-repo is that a developer can reuse code originally written for an unrelated module. When the two modules share code, then change in this common code can lead to bugs. If these bugs go unchecked, they can affect the CI/CD (Continuous Integration and Delivery) pipelines of unrelated micro-services. To avoid such issues, it is important to have a strong testing suite in place.
单一仓库的潜在风险是开发人员可以重用最初为无关模块编写的代码。 当两个模块共享代码时,更改此公共代码可能会导致错误。 如果不检查这些错误,它们可能会影响不相关的微服务的CI / CD(连续集成和交付)管道。 为避免此类问题,重要的是要有一个强大的测试套件。
2.检查是否有与其余模块完全不同的模块。 (2. Check whether you have any modules that are very distinct from the rest.)
Are you developing a module that demands a very different technology, language, framework or persistence? Then separating it out into a separate repository will be better.
您是否正在开发一个需要非常不同的技术,语言,框架或持久性的模块? 然后将其分离到一个单独的存储库中会更好。
In Collect, there are services that handle processing of events in bulk. They maintain queues, execute custom scripts and have a completely different error-handling mechanism. These services are written in Python, and quite often they need to do CPU-intensive tasks.
在“收集”中,有一些服务可以批量处理事件。 它们维护队列,执行自定义脚本,并具有完全不同的错误处理机制。 这些服务是用Python编写的,并且经常需要执行CPU密集型任务。
So when we were thinking about restructuring the code for Collect, keeping these services in a separate repo came across as self evident. These services were very different from Collect’s main repository (described above). While the main repository was for user-facing requests, this repo was all about background tasks and executions. Also, the change management in these services was going to be different and isolated from the main repository.
因此,当我们考虑重组Collect的代码时,很明显地将这些服务保存在单独的存储库中。 这些服务与Collect的主要存储库(如上所述)非常不同。 虽然主要存储库是用于面向用户的请求,但此回购全是关于后台任务和执行的。 而且,这些服务中的变更管理将有所不同,并且与主存储库隔离。
Thinking about the code maintenance and how it is going to evolve over time led us to club these services in a separate repository. By doing that, we were able to put up a completely different change management system, which turned out to be very helpful and more productive.
考虑到代码维护及其随着时间的发展,我们将这些服务合并到一个单独的存储库中。 通过这样做,我们能够建立一个完全不同的变更管理系统,事实证明该系统非常有用,而且效率更高。
3.考虑不确定性,因此要考虑服务可能经历的更改频率。 (3. Consider the uncertainty and therefore the frequency of changes a service might go through.)
When you start working on something that is highly uncertain (either in terms of the scope of the problem or the implementation itself), then having a different repository can give you with the velocity and freedom you need to test things.
当您开始进行高度不确定的事情(无论是问题的范围还是实现本身)时,拥有不同的存储库可以为您提供测试事物的速度和自由度。
For example, say that you want to test a new way of processing images to identify objects. You want to dabble with machine learning, but you are still unsure how it will evolve or if the problem statement will change dramatically. In this case, it would be clearly better to have a separate repository and then get to a point of certainty. Conversely, if you think that the API has reached stability and will remain unchanged for a large amount of time, you can take a call to merge it with one of your main repositories.
例如,假设您要测试一种处理图像以识别对象的新方法。 您想涉足机器学习,但仍不确定它会如何发展或问题陈述是否会发生巨大变化。 在这种情况下,最好有一个单独的存储库,然后再确定一点。 相反,如果您认为该API已达到稳定性,并且会在相当长的时间内保持不变,则可以调用将其与您的主要存储库之一合并。
The blog was originally published on blog.socialcops.com. The above is how we handle our repository decisions. I hope it can help you in thinking from first principles if you approach this problem. Do subscribe to our newsletter for more updates from SocialCops Engineering and Data Science Team.
该博客最初发布在blog.socialcops.com上。 以上是我们处理存储库决策的方式。 我希望,如果您解决此问题,它可以帮助您从首要原则出发进行思考。 请订阅我们的新闻通讯,以获取SocialCops工程和数据科学团队的更多更新。
代码字体mono