我目前正在开发一个 Rails 3 项目,该项目分为四个部分:
- 面向公众的网站
- 管理网站/后端
- 模型
- 用于第三方数据访问的 API
由于模型在三个关键组件之间共享,我想保留它们远离一个主要项目,但是每个部分都需要访问模型,但我不想重复代码并且到处都有不同的版本。
目前,我在 gem 中拥有模型代码,并且在每个项目的 Gemfile 中,我使用以下行引用它们:
gem "my_models", :path => "../my_models/"
但是,当我部署到测试服务器以供同事评估系统时,我需要从外部存储库,因此我将上面的行替换为以下内容:
gem "my_models", :git => "[email protected]:username/my_models.git"
这本身运行良好,但在“版本”方面相当笨重(即,每次我希望将更改部署到测试时,我都需要更改版本)服务器),切换线路使用 git 而不是 local,并确保我正确推送文件。
以前我使用共享 git 子模块,但这同样尴尬。
我宁愿不将所有内容都构建到一个大型项目中,因为这些项目往往会变得巨大且难以维护,并且如果可能的话,我也希望将关注点分开,因此我对管理站点所做的任何更改都没有太大的影响有机会影响其他组件 - 显然这些模型有可能导致问题,但这是我已经考虑和理解的风险。
当谈到这样的事情时,人们会提出什么建议?或者,我的处理方式完全错误吗?
一些额外的背景:
这个应用程序是对现有网站的重写,该网站遵循“将所有内容集中到一个项目中”的模型 - 不幸的是这里有两个问题:
- 该应用程序开发得很糟糕 - 我继承了这个项目,当我第一次拿起它时,单个用户每页的加载时间约为 2 分钟 - 此后该时间已减少,但整个过程中仍然存在问题
- 我们目前已达到当前站点的容量限制,我们预计我们将需要在接下来的 6 个月内承担更多负载 - 但是扩展使用“一体化”应用程序意味着我们将浪费资源来扩展不需要它的网站后端。
本质上有两件事我想分开 - 前端(公共网站和 API)和后端 - 我对软件开发的了解告诉我,将所有这些结合在一起并不是一个理想的解决方案(过去的历史表明我认为将这两者分开对于确保前端性能来说是一个很好的举措)。
也许我需要从另一个角度来看待这个问题 - 将模型保留在每个项目中,而不是在项目之间共享它们,而是为每个功能区域提供一个缩减的功能子集(即后端需要知道谁创建了帖子,但是前端并不真正关心这一点,因此在读取模型时忽略该逻辑)。
I am currently working on a Rails 3 project that is divided up into four parts:
- The public facing website
- The administration website/backend
- The models
- The API for third party data access
As the models are shared between the three key components I want to keep them away from being in one main project, however each part needs access to the models, but I don't want to repeat the code and have different versions everywhere.
Currently I have the model code in a gem, and in each project's Gemfile I am referencing them with the following line:
gem "my_models", :path => "../my_models/"
However when I deploy to our test servers for my co-workers to evaluate the system on I need to pull the models from an external repository, so I swap out the above line with the following:
gem "my_models", :git => "[email protected]:username/my_models.git"
This in its self works well, but its quite clunky in terms of 'versions' (i.e. I need to bump the version every time I wish to deploy the changes to the test servers), switch the line over to use git instead of local, and make sure that I'm pushing the files properly.
Previously I was using a shared git submodule, but this was just as awkward.
I would rather not build everything into one mega-project, as these tend to become monstrous and difficult to maintain, and I would also like to separate concerns if possible, so any changes I make to the administration site doesn't have much of a chance to impact the other components - obviously the models have the potential to cause issues, but that is a risk I have considered and understand.
What would people out there suggest when it comes to something like this? Or, am I going about it completely the wrong way?
Some additional background:
This app is a rewrite of an existing website which followed the model of 'lump everything into the one project' - unfortunately there are two issues here:
- The app was badly developed - I inherited this project and when I first picked it up the load times were ~2 minutes per page with a single user - this has since been reduced but still has issues throughout
- We are currently at our capacity limit of the current site and we anticipate that we will need to take on more load in the next 6 months - however scaling out with an 'all in one' app means we'll be wasting resources on scaling out the back end of the site which doesn't need it.
Essentially there are two things I want to separate - the Front end (being the public website and the API) and the back end - everything I know about software development tells me that combining all this together is not an ideal solution (and past history shows me that splitting these two is a good move in terms of ensuring front end performance).
Perhaps I need to look at this from another angle - keep the models in each project, and instead of sharing them between projects have a cut-down subset of functionality for each functional area (i.e. the backend needs to know who created a post, but the front end doesn't really care about that, so omit that logic when reading in the model).
发布评论
评论(6)
删除模型项目(将模型放入其他部分之一,我建议您认为“更重要”的任何内容),将所有项目放入单个存储库(单独的项目文件夹)并创建指向 models/libs/apis/无论
您的代码的 符号链接高度耦合在一起,您经常需要同时对几个项目进行更改(例如更新模型和更新使用它们的 API 等)
单存储库符号链接设置的一个好处是您的提交将减少碎片化并且通常会代表完整的功能实现 - 更容易跟踪错误,读取历史记录和维护代码库,
而且当您部署时,您不需要从许多存储库中读取 - 那里的故障点更少,
使用分支这样的模型发布过程也更简单现在涵盖了所有项目的范围,
有一些缺点,比如符号链接在 Windows 上不能很好地工作,但对我来说它工作得很好
drop the models project(put models into one of other parts, i'd suggest whatever you consider "more important"), put all projects into single repository(separate project folders) and make symlinks to models/libs/apis/whatever
your code is highly coupled together and you often need to make changes to few projects at once(like updating models and updating APIs that use them, etc)
one nice thing about single-repo-symlink setup is that your commits will be less fragmented and will usually represent full feature implementation - easier to track bugs, read history and maintain codebase
also when you deploy you don't need to read from many repositories - one less point of failure right there
release process is also simpler with such model as branch will now hold the scope of all projects
there are some drawbacks like symlinks dont work that well on windows and whatnot but for me it works perfectly
您可以创建一个包含共享模型的可安装引擎,并用它创建一个 gem。这将优雅地处理名称间距问题。这里的另一个好处是您也可以分享您的资产。
观看railscast 了解更多详情。
You can create a mountable engine that contains the shared models and create a gem out of it. This will handle the name spacing issues elegantly. Other nice aspect here is you get to share your assets also.
Watch this railscast for more details.
您仍然需要通过将需要测试的更改推送到远程存储库来管理“版本”,但您可以使用 Bundler 1.2
http://gembundler.com/man/bundle-config.1.html#LOCAL-GIT-REPOS
这样它将获取您的本地提交,而您不必保留部署时更改 Gemfile。
You'll still have to manage the 'versions' by pushing changes that need to be tested to a remote repo, but you can use the new
local
config of Bundler 1.2http://gembundler.com/man/bundle-config.1.html#LOCAL-GIT-REPOS
This way it will pick up your local commits and you won't have to keep change your Gemfile upon deployment.
我知道这不能解决您的特定问题。但我真的建议你将所有项目合并为一个。将所有这些部分包含在一个应用程序中是很常见的,并且没有任何开销。我认为这个问题没有不尴尬的解决方案。
I know that this is not an solution for your particular problem. But I really suggest you to merge all projects into one. It is very usual to have all this parts in one application and there is no overhead. I think there is no not-awkward solution for this problem.
看一下 Git 子树。
这可能对你有用..
http://igor-alexandrov.github.io/blog/2013/03/28/using-git-subtree-to-share-code- Between-rails-applications/
或者
你可以编写 Rake 任务..
示例:-
请参阅下面的链接。
http://hiltmon.com/blog/2013/ 10/14/rails-tricks-sharing-the-model/
Take look at Git subtree.
This may work for you..
http://igor-alexandrov.github.io/blog/2013/03/28/using-git-subtree-to-share-code-between-rails-applications/
OR
You can write Rake task..
Example:-
See the below link.
http://hiltmon.com/blog/2013/10/14/rails-tricks-sharing-the-model/
您的项目有足够的代码覆盖率吗?如果确实如此,我会尝试将有意义的逻辑分开,如果一个模型用于不同的项目,只需选择一个最适合的模型并在其之上编写一个 API。
然后,您可以使用该 API 访问其他项目上的这些模型(最好使用 ActiveModel 之类的东西)。您仍然会有一个简单的 CRUD,但所有核心模型逻辑都将在外部处理。
不过,在分开它们之前一定要三思而后行。您希望在您想要拆分的庞然大物中创建的每个应用程序上保持严格的域。
关于引擎:
我已经使用 Engines 来解决同样的问题,它确实有帮助,但我还必须将 Gemfile 更改为在开发时指向本地路径,推送 gem,然后将其拉到当前项目上,这就是行为你不喜欢。
Does your project have enough code coverage? If it does, I would try to separate the logic where it makes sense, and if a model is used in different projects, just pick one that fits best and write an API on top of that.
Then you could use that API to access those models (preferably using something like ActiveModel) on the other project. You would still have a simple CRUD, but all the core model logic would be handled externally.
Be sure to think well before splitting them up, though. You want to keep your domain tight on each app you create out of the Behemoth you want to torn apart.
Regarding engines:
I have used Engines for the same issue and it does help, but I also had to change my Gemfile to either point to a local path when developing, pushing the gem, then pulling it on the current project, which is the behavior you're not fond of.