• Why Sometimes I Write WET Code at 2018年09月16日

    解决过分 DRY 或不够 DRY 问题,可简单定 2 个原则:

    1. 不过早“优化” - 先不要假想着将来会有人“重用”这个方法,将来太多不确定性。
    2. “事不过三”原则 - 出现 2 处重复不过份,当第 3 次出现重复时就要考虑 DRY 一下了。(Tips:可以利用工具如 rubycritic、flay 或 flay 等来帮忙找出重复的地方)
  • 最短且最好理解的版本:

    arr.inject({}) {|r, (k,v)| r.merge({k => v.to_i + r[k].to_i}) }
    or 
    arr.inject(Hash.new(0)) {|r, (k,v)| r[k] += v.to_i; r }
    
  • 使用本地存储时如果是单机应用还要考虑文件过多问题,carrierwave 提供了 hook 可以实现 partitioning 以及文件删除后的文件夹清扫,Disk Service 不知道提供了接口没

  • 我吐槽的是 rails 的代码组织和命名:)

  • 要想模仿 ActiveRecord 的要慎重,这是个“PhotoShop”级别的库,包含各种想得到或者你觉得现在没用将来很需要的特性。

    看下 rails 5.1.4 中 ActiveRecord 定义的 module 有 150 多个(不包含 Class 及子 module)

    ActiveRecord::Attributes,
    ActiveRecord::Migration,
    ActiveRecord::ExplainRegistry,
    ActiveRecord::Migrator,
    ActiveRecord::Fixture,
    ActiveRecord::NoDatabaseError,
    ActiveRecord::ConnectionTimeoutError,
    ActiveRecord::ExclusiveConnectionTimeoutError,
    ActiveRecord::QueryCache,
    ActiveRecord::Core,
    ActiveRecord::ConnectionHandling,
    ActiveRecord::CounterCache,
    ActiveRecord::DynamicMatchers,
    ActiveRecord::Enum,
    ActiveRecord::InternalMetadata,
    ActiveRecord::Explain,
    ActiveRecord::Inheritance,
    ActiveRecord::ModelSchema,
    ActiveRecord::NestedAttributes,
    ActiveRecord::NoTouching,
    ActiveRecord::TouchLater,
    ActiveRecord::Persistence,
    ActiveRecord::Querying,
    ActiveRecord::CollectionCacheKey,
    ActiveRecord::ReadonlyAttributes,
    ActiveRecord::RecordInvalid,
    ActiveRecord::Reflection,
    ActiveRecord::RuntimeRegistry,
    ActiveRecord::Sanitization,
    ActiveRecord::Schema,
    ActiveRecord::SchemaDumper,
    ActiveRecord::SchemaMigration,
    ActiveRecord::Scoping,
    ActiveRecord::Serialization,
    ActiveRecord::StatementCache,
    ActiveRecord::Suppressor,
    ActiveRecord::Timestamp,
    ActiveRecord::Transactions,
    ActiveRecord::Translation,
    ActiveRecord::Validations,
    ActiveRecord::SecureToken,
    ActiveRecord::ActiveRecordError,
    ActiveRecord::ConnectionNotEstablished,
    ActiveRecord::ConnectionAdapters,
    ActiveRecord::Aggregations,
    ActiveRecord::Associations,
    ActiveRecord::AttributeAssignment,
    ActiveRecord::AttributeMethods,
    ActiveRecord::AutosaveAssociation,
    ActiveRecord::Attribute,
    ActiveRecord::LegacyYamlAdapter,
    ActiveRecord::AssociationRelation,
    ActiveRecord::NullRelation,
    ActiveRecord::Relation,
    ActiveRecord::QueryMethods,
    ActiveRecord::PredicateBuilder,
    ActiveRecord::SpawnMethods,
    ActiveRecord::FinderMethods,
    ActiveRecord::Batches,
    ActiveRecord::Result,
    ActiveRecord::TableMetadata,
    ActiveRecord::Delegation,
    ActiveRecord::VERSION,
    ActiveRecord::SerializationTypeMismatch,
    ActiveRecord::Coders,
    ActiveRecord::RecordNotFound,
    ActiveRecord::AdapterNotSpecified,
    ActiveRecord::AssociationTypeMismatch,
    ActiveRecord::AssociationNotFoundError,
    ActiveRecord::RecordNotSaved,
    ActiveRecord::Locking,
    ActiveRecord::RecordNotDestroyed,
    ActiveRecord::RecordNotUnique,
    ActiveRecord::InvalidForeignKey,
    ActiveRecord::AdapterNotFound,
    ActiveRecord::SubclassNotFound,
    ActiveRecord::HasManyThroughOrderError,
    ActiveRecord::WrappedDatabaseException,
    ActiveRecord::NotNullViolation,
    ActiveRecord::ValueTooLong,
    ActiveRecord::MismatchedForeignKey,
    ActiveRecord::PreparedStatementCacheExpired,
    ActiveRecord::PreparedStatementInvalid,
    ActiveRecord::HasManyThroughAssociationNotFoundError,
    ActiveRecord::StaleObjectError,
    ActiveRecord::ReadOnlyRecord,
    ActiveRecord::AttributeAssignmentError,
    ActiveRecord::MultiparameterAssignmentErrors,
    ActiveRecord::UnknownPrimaryKey,
    ActiveRecord::AttributeSet,
    ActiveRecord::ImmutableRelation,
    ActiveRecord::TransactionRollbackError,
    ActiveModel::UnknownAttributeError,
    ActiveRecord::Deadlocked,
    ActiveRecord::SerializationFailure,
    ActiveRecord::HasManyThroughCantDissociateNewRecords,
    ActiveRecord::IrreversibleOrderError,
    ActiveRecord::HasManyThroughNestedAssociationsAreReadonly,
    ActiveRecord::HasManyThroughAssociationPolymorphicSourceError,
    ActiveRecord::TestFixtures,
    ActiveRecord::HasManyThroughAssociationPolymorphicThroughError,
    ActiveRecord::DeleteRestrictionError,
    ActiveRecord::HasManyThroughAssociationPointlessSourceTypeError,
    ActiveRecord::HasOneThroughCantAssociateThroughCollection,
    ActiveRecord::HasOneAssociationPolymorphicThroughError,
    ActiveRecord::InverseOfAssociationNotFoundError,
    ActiveRecord::Store,
    ActiveRecord::AttributeDecorators,
    ActiveRecord::LazyAttributeHash,
    ActiveRecord::ThroughCantAssociateThroughHasOneOrManyReflection,
    ActiveRecord::ReadOnlyAssociation,
    ActiveRecord::AmbiguousSourceReflectionForThroughAssociation,
    ActiveRecord::FixtureSet,
    ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection,
    ActiveRecord::HasOneThroughCantAssociateThroughHasOneOrManyReflection,
    ActiveRecord::HasManyThroughCantAssociateNewRecords,
    ActiveRecord::HasManyThroughSourceAssociationNotFoundError,
    ActiveRecord::ThroughNestedAssociationsAreReadonly,
    ActiveRecord::Integration,
    ActiveRecord::Base,
    ActiveRecord::EagerLoadPolymorphicError,
    ActiveRecord::StatementInvalid,
    ActiveRecord::AttributeMutationTracker,
    ActiveRecord::ExplainSubscriber,
    ActiveRecord::Calculations,
    ActiveRecord::MigrationError,
    ActiveRecord::IrreversibleMigration,
    ActiveRecord::DuplicateMigrationVersionError,
    ActiveRecord::DuplicateMigrationNameError,
    ActiveRecord::UnknownMigrationVersionError,
    ActiveRecord::IllegalMigrationNameError,
    ActiveRecord::PendingMigrationError,
    ActiveRecord::ConcurrentMigrationError,
    ActiveRecord::NoEnvironmentInSchemaError,
    ActiveRecord::ProtectedEnvironmentError,
    ActiveRecord::Type,
    ActiveRecord::EnvironmentMismatchError,
    ActiveRecord::DefineCallbacks,
    ActiveRecord::LogSubscriber,
    ActiveRecord::SuppressorRegistry,
    ActiveRecord::TypeCaster,
    ActiveRecord::Callbacks,
    ActiveRecord::Railties,
    ActiveRecord::NullMutationTracker,
    ActiveRecord::DangerousAttributeError,
    ActiveRecord::HasOneThroughNestedAssociationsAreReadonly,
    ActiveRecord::ConfigurationError,
    ActiveRecord::Railtie,
    ActiveRecord::FixtureClassNotFound,
    ActiveRecord::MigrationProxy,
    ActiveRecord::NullMigration,
    ActiveRecord::TypeConflictError,
    ActiveRecord::RangeError,
    ActiveRecord::TransactionIsolationError,
    ActiveRecord::Rollback,
    ActiveRecord::Tasks
    

    一般人用得最多的是 Migration、Validations、Scoping、Attributes、AttributeMethods、Callbacks、FinderMethods、QueryMethods、CounterCache、Associations 等 module 提供的 DSL。

    有些高级点如 Locking、Store、SpawnMethods(提供 merge 合并其他 model 的 scoping)、QueryCache(不少人不知道可在 rake task 中显式使用)、TouchLater、SecureToken(提供 generate_unique_secure_token)、PredicateBuilder(定制 query 的 predicate)、Aggregations(提供 composed_of macro)、Suppressor(临时跳过 save 操作)在所适应的场景中很便利却容易被忽略。

    另外想吐槽一点是各种 Error module 没有放到一个 Error namespace 下,或者放到与 feature 同名的 module 下也能接受。

  • JSON 中时间对象的输出格式是怎么定义的?

    最后的参考是 rails 的实现:ActiveSupport/TimeWithZone.html#method-i-as_json

  • 如果没有复杂业务逻辑和需要一些第三方 gem 的,只是对 redis 的操作,这个业务场景没必要用 rails,单纯用 grape 这个框架都会性能倍升,并还是在 ruby 这个语言 scope 内。而 rails 的光是启动一个实例就加载上百个 Initializer 策略(实测 130 个),楼主描述的场景(完全实时查询)rails 提供的很多缓存策略都用不上,有力使不上劲的感觉,一开始框架选型就不妥了。

  • Rails 5.1 add delegate_missing_to at 2017年07月21日

    这个就是 draper 的 delegate_all 实现,而 draper 就是装饰器模式的典型使用场景

  • DHH、林志颖、韩寒三大跨界开赛车的男神

  • before_create do
      article.increment!(:likes_count)
    end
    

    这个已经改变了业务逻辑:先累加赞,再添加赞记录。

    一个思路是把这类计数器累加操作可以放入队列里异步、顺序执行。

    另外我的使用 counter_culture+pg 经验中发在多线程高并发时,累加值容易互相覆盖,最好还是定时或在某些 callback 再 call 一个 update_counter_by_counts

  • Rails 与 Django 性能的疑问 at 2017年05月19日

    有意义的,意思就是如果你打算做很 care 性能的产品,就选 py 驱动的框架;如果很 care 能否快速实现、需求变化频繁、组件丰富拿来就用、care 开发人员情绪的,就顺便考虑下 rails

  • 说起 CI 时间的话,想起 4 年前的一个 rails 项目,CI 上跑一次完整回归大概 5 个多小时

  • 楼主也叫 Rain?缘分

  • Rails 最佳实践 - 定时任务 at 2017年01月19日

    赞同楼主,crontab 在多实例部署就有容易有问题,另外无重试、统计,精度到分钟级别,顶多算个触发器,是比较粗糙的解决方案,不过也能解决 80% 的早期项目需求。跟 sidekiq 结合是不错的实践,可充分利用 slidekiq 的重试、统计。

  • #6 楼 @kgen 分析帝跪了 ORZ。实际情况是为了赶在元旦前发布,数据收集是在假期最后一天的下班前收集的(第一条提交数据时间:2016-12-30 17:41:54,而我们 6 点下班),实际数据收集不是全的,不过作为抽样可以用来参考一些问题了。

  • #5 楼 @freefishz 那个是163的数据,没有错

  • #3 楼 @gihnius #2 楼 具体实践总结 中 blog 的部分都是发表到了公司官网 blog 上的了:http://www.beansmile.com/blog

  • #2 楼 @lgn21st 发布匆忙忘了说明,具体实践总结 中 blog 的部分都是发表到了公司官网 blog 上的了:http://www.beansmile.com/blog ,其他一些是内部资料不方便公开望见谅,欢迎面交 😄

  • 恭喜 @fredwu 加入新公司,开始新事业,结尾不应该是The End应该是 To be continued

  • 统一账户管理平台 at 2016年11月15日

    楼主不知道有个 openid 标准?曾经有时间各大 IT 服务商都支持了,包括 AOL, Blogger, Flickr, Google, Amazon.com, Microsoft, Facebook

  • 非常能理解楼主需求,一套可重用的 CMS 框架,可以满足很多无需太多定制要求的项目,极大减少开发量,例如:

    • refinerycms,可满足 只需要简单页面内容定制的,例如建站类型的
    • activeadmin-cms,适合原型级别、不管后端、验证概念级别的项目
    • rails-admin,可满足不太 care 管理后台,前台有定制需要的项目
  • The compiler is written in Crystal 每当看到这种能自举的编程语言就有种“通透”的感觉,上次是看到有印象的是 coffeescript The CoffeeScript compiler is itself written in CoffeeScript,非常有意思

  • @楼主 最好的 cucumber 代码 example 是 rspec 内核的测试代码:https://github.com/rspec/rspec-core/tree/master/features

    而最好的 rspec 代码 example,自然是由 cucmber 提供:https://github.com/cucumber/cucumber-ruby/tree/master/spec/cucumber

  • #16 楼 @tony612 model 里使用establish_connection configurations['your_db_config_in_database.yml'] 即可,不能再简单

  • 从 web 项目的角度,很少会只测试 controller action 而不测试 view 或路由(除非是做功能扩展型的 gem 开发),而集成测试会覆盖到路由、action 及 view,更符合 web 项目的实现思路,更多的边界测试可以由单元测试来保证,这样既保证了开发效率也有质量,我们团队从 rails3 时代开始就只做集成测试和单元测试,也正是如此考虑,我想 DHH 这个决策也是顺势而为。

    如果留意 rails 的变更历史,不难发现 Rails 一直在根据流行的 best practice 来进行内构调整,从最早的功能全包,如包含树形结构、分页,然后又剥离出去;从内置 prototype.js 到改为可选 js 框架。这些改动都是先有之(便利),再改进为可配置(灵活),无一不是为了方便开发者着想。

  • 以前这个场景是用一个 gem grouped_validations 实现,DSL 如下:

    validation_group :name, :if => :ready? do
      validates_presence_of :first_name
      validates_presence_of :last_name
    end
    

    不过好久没更新了,想不到这个 feature 变成刚需特性给 rails5 内置了,rails 开发真心爽快

  • 从零开始 Ruby on PHP at 2016年06月14日

    @楼主 在 erb 中 concat buffer 有 2 种做法:一种是用原生的模板语法<%= var %> ,类似 php 5.4 里的 short tag <?=; 另一种就像你这样操作 output buffer,但在 sinatra 里有比较简单/标准的做法:

    # app.rb
    helpers do
      def echo(str) @_out_buf << str.to_s end
    end
    
    # index.erb
    <% echo 'hi' %>
    

    anyway,楼主探索 ActionView 的技巧分享值得点赞

  • 唐凤 绝对是传奇之最没有之一,「她」之前可不是女程序员

  • 有个 toy 级别的用 ruby 来写 react-native app: https://github.com/zetachang/opal-native

  • 11 点刚发现这个问题,huacnlee 同学就解决了,赞