草庐IT

2021年,我们 CSDN App做了什么?

张迁 2023-11-29 原文

各位 CSDNer,我是CSDN App的产品负责人张迁,2021年我们做了什么?

在这一年其实我们做了很多,也舍弃了很多。所以想和你来聊一聊这个产品。

我想如果不是这篇文章你可能都不知道 CSDN还有个 App 吧?很惭愧,我们做的还不够好,没有让我们的 App尽可能满足所有人的需求,这是我们需要继续努力的。从四年前我们正式上线第一个版本,到现在我们迭代到了 v4.20.0,按计划今年还会有一个版本的更新,所以我们在 2021年度累计迭代 21个版本。看吧,这就是产品人的浪漫,连迭代的版本数都透露着“爱你”(谐音梗不扣钱)。

这篇文章我会从 产品功能、性能优化、UI升级几个方面来说说我们这 21个版本都做了什么。同时我希望你可以带着下面三个小问题看完这篇内容,并将你的想法回复在评论区。对于合理的反馈,我想我们可以来单独聊聊……

1、App内设计最烂的功能模块是哪一个?

2、你觉得 App内哪一个模块相对还不错?

3、如果你是我,你最想在 App上实现一个什么功能?

在这之前,先说一个客观存在的现状。市面上大多数App为了能够快速的迭代产品以及适应公司各业务的发展,都是使用 Native+H5+小程序 这种混合开发的模式,CSDN 也不例外。所以有的时候会发现提出的一个需求或 bug能够快速的调整,那基本都是一些后端服务或基于H5/小程序的功能模块;更新版本之后才有调整那就是原生开发需要发版解决,这种相对来说时间就会久一点。当然,作为程序员,相信你们也是能够看出App内哪些是原生、哪些是H5和小程序。

OK 下面我们正式来聊一聊 App的 2021年做了什么?举几个例子来说一说:

每个人对美的认知都不太一样,不能说孰好孰坏。但产品设计总归要遵循一个简单原则,无论是视觉体验还是交互使用,简单的才是好的。如果一个功能需要通过引导说明来向用户解释,那这个功能的设计一定不是最优的。并且一定是 UI围绕着功能的,而不应该是苦思冥想一些功能去满足一个炫酷的UI。

首页

可能你们都有发现,首页的内容会被经常调整。尤其是推荐流,在这个页面我们要解决的是让用户快速浏览到自己感兴趣的内容,并且能够一直浏览到自己感兴趣的内容。单说视觉层面,首页导航条我们优化了样式及选中状态;对于信息流逐步的优化了每条内容展示信息元素、主次区分、封面尺寸、字体、字号、间距等信息。我们希望信息流是简洁的,在浏览的时候不会觉得视觉疲劳。

我们坚持每次的功能调整一定是为了在某个场景解决了用户的某个问题。功能上我们取消了首页的自定义内容导航,这也是基于我们的推荐算法逐步迭代让我们可以在推荐流就可以满足绝大部分用户的需求。自定义是为了满足用户的个性化,当我们可以在一个面满足的时候,就可以去除更多的冗余分类。新增的【热榜】同样是基于对我们现阶段算法的自信,让更多用户可以快速筛选出全站一个时间段内较为热门的内容,降低用户的筛选成本。

在【关注流】我们没有粗暴的把关注人的所有内容直接罗列,而是进行过多次的分析和测试,最终选定展示近7日的内容,并且对于关注的单个用户也可以独立展示内容。当你关注的用户有内容更新时,关注流会有相应更新内容数量的提示。我们真的希望你关注的是对你有帮助的并且是你需要的。

首页的所有改变呈现在版本更新里可能就是一句“首页优化”,但背后却是我们对算法的上百次改进,对App性能的无数次调优。这才保证了我们每次推荐数据的准确性、稳定性、有效性,以及保证我们无论是视频、直播、文章、动态等内容都可以做到点击即可秒开详情。

个人主页

我们定义个人主页是“人与人”之间的隔空对话,我们希望能够更多的展示出被访问者的“成就”和“能力”。所以我们在视觉上让一些更为重要的信息占据更多的区域,对简介内容做了折叠并突出了你的成就信息,我们相信相比简单的自我介绍,数据更能说明一切。你所创作的内容也会被更有条理的分类展示,让访客可以对你不同的面都有所了解。

既然我们定义这个页面是“人与人”的对话,那么我们也希望访客和被访问者之间产生一点共鸣。所以我们展示出了你的行业和所在地区(隐私信息可关闭)以及你的兴趣标签,访客视角可以看到与你有共同相关的点。我们希望通过这个“点”能让更多的用户之间可以连成线、铺成面,希望在 CSDN你除了可以得到知识还能够认识很多伙伴。

文章详情页

这个页面可能是App内被用户浏览次数最多的页面。对于这个页面的调整我们秉承着以阅读体验为最高优先级,去除了大量的冗余信息,多次对文章排版布局进行样式调整。并在详情页增加了快捷搜索、摘要分享、长按复制、稍后再看等实用小功能,尽可能的让用户可以在当前页完成一些操作需求,并且加强了读者对于内容互动的操作。对于文章本身,我们增加了来源标记、分享卡片;多次调整了相关推荐策略。对于作者,我们开放了移动端的文章打赏,让你的内容有一些额外的认可。性能上我们对详情页进行过多次优化,即便是超长文章也能够快速完成全文加载。作为技术社区“代码”无处不在,我们在移动端也做了对代码的兼容展示,让你可以全屏阅代码一键即复制。

每日一练

相信你在学习的路上也会产生迷茫,这个迷茫源于自我怀疑,怀疑对知识汲取的有效性,怀疑自己是否有真正的能力提升。系统性的提升可以通过实际项目来完成验证,那日常学习的碎片化内容该如何来检验?这就是【每日一练】存在的意义,我们针对不同语言将一些高频使用的知识点转化成代码练习,通过每日定量的任务来完成知识点的二次掌握。不积跬步,无以至千里;不积小流,无以成江海。相信即便每日仅用5~10分钟来刷刷题,长时间的积累也会给你带来很大的价值。

当然,我们也知道再有趣的学习都会是痛苦的,努力学习的人值得被奖励,所以设立了每月排行榜并对榜单的Top用户进行福利奖励。目前已经有一大批用户收到了来自【每日一练】的学习奖励。

 签到

当我们说道签到,你可能就想到“钱”。是的,我们要发钱,很干脆直接的发钱。当然,之前CSDN也做过一些类似的活动。可能大部分还是没有很直接的给到一些可见的收益。尤其是签到,一直被诟病,很多用户都反馈签到抽奖从未中过。不可否认我们在之前在一个功能上考虑太多的因素,成本、ROI、占用资源等等。在各种原因的影响下往往一个很好的功能就会变得很功利,这不是我们想要的,至少不是我们最初想要的。我们一直在探索怎样更好的让用户用的爽,用的不反感。无论是今年开始的原力计划在流量和金钱上的奖励,还是码住夏天的翻卡活动,亦或是增加的现金打赏等等,我们一直在尝试。

原本的签到,想必各位也都很清楚了,一直被你们吐槽。那么我们调整之后,从原来的连签多天获得抽奖机会,且不一定抽中什么,变成了每日签到都会给到一定的现金收益。并且原力分提升还能够得到10倍的签到奖励。虽然每日的奖励额度不是很多,但绝对是市场上众多产品中针对签到发放奖励较高的一个。现阶段每日进入App-我的-签到,点击即可领取每日的现金奖励。透露一下一年的签到收益与CSDN年卡会员的费用相当。

当然对签到的改动只是第一步,我们希望通过这一小小的尝试来与你建立更多的连接。人生从来不像意想的那么好,也不像意想的那么坏。就像我们的一样,虽然在你们眼中有很多槽点,但总还是会有一些可爱的地方,不是么~

小彩蛋:哪位同学发现了这个每日奖励的规则么?

Blink

这是一个我们调整过很多次的模块,很长一段时间内都没有对Ta有一个明确的定位,所以在某个时期你们会发现这个模块几乎处于“放养”的状态。我们也是希望在用户自主的使用中发现这个模块对于用户的意义。现在我们发现了,我们从来不认为技术人需要的只有干货,除了知识和工作我们还需要生活。这里就是所有用户的动态,有学习、有生活,只要你愿意你可以在这里分享一切你想分享的内容(请遵守社区规范)。有很多用户跟我说只想看到技术干货,不想在这里看到其他的内容。我们尊重用户的使用习惯,你可以有选择的浏览内容,但请不要用你的规则要求所有用户。

有一段时间在Blink有很多用户开始分享自己的生活,这其实让我们受宠若惊。我们做的不够好,但仍有用户很认可的在这里分享,我们很感激。不过也有一些小遗憾,这些用户往往会收到一些不友好的言论回复,对此我们深感抱歉,是我们没有摸索并明确社区的方向,让你们受到一些不好的体验。对此,我们增加了对回复/评论的【举报】功能,我们希望社区的氛围是友善的、和谐的、平等的,一切分享都应该得到友善的互动。

功能上我们逐步完善了可以发布的内容类型,包含了文本、图片、视频、投票、PK等等,并且在功能逻辑上多次优化。本年度的最后一个版本,Blink会升级为【微社区】并新增同城模块。我们希望在微社区你看到的是你关心的人的内容以及推荐的用户动态,同时可以浏览不同城市下用户的动态内容,世界那么大、城市那么多,不要偏爱于此。我们希望这里发生的事情可以和你有一点点的关联,并且可以留下你发生的事情 ,毕竟大大的城市小小的我们,你的程序人生总归需要留下一点点的足迹。

我们实现的功能远不止这些,今年 App进入研发的需求200+,有一些被陆续舍弃,有一些会被继续迭代。当然,我们的初心没有变,继续为用户提供更好的、更有价值的服务。我们希望不仅仅只是在做一个功能,而是在满足更多用户的合理诉求。大厦从来不是一天建成的,但坍塌往往就在一瞬间,所以我们会很珍惜你们给到的信任与支持。接下来的一年中,我们希望可以慢一点,认真打磨好每一个有价值的服务,做一个有灵魂的产品。

在此也感谢我们移动端团队的每一位成员:

运营-丁焕朗;

App研发-孟瑞瑞、邓建东、兰伟欣、马占文、杨旭东、丁豪、郭武鑫、匡罡、王林彭、张震;

小程序研发-许章正、靳俊召、刘营、王天雷;

测试-李秀秀、张凌宇、刘静;

以及UED团队的曹宏、孙维国、刘亚强。

感谢每位同学的负责和努力,让我们的用户都被善良以待。

以上……

另:欢迎各位点击下载体验 CSDN App/或扫码下载

有关2021年,我们 CSDN App做了什么?的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  3. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  4. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  5. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  6. ruby - ruby 中的 TOPLEVEL_BINDING 是什么? - 2

    它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput

  7. ruby - Infinity 和 NaN 的类型是什么? - 2

    我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串

  8. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  9. ruby - 为什么 SecureRandom.uuid 创建一个唯一的字符串? - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?

  10. ruby - 当使用::指定模块时,为什么 Ruby 不在更高范围内查找类? - 2

    我刚刚被困在这个问题上一段时间了。以这个基地为例:moduleTopclassTestendmoduleFooendend稍后,我可以通过这样做在Foo中定义扩展Test的类:moduleTopmoduleFooclassSomeTest但是,如果我尝试通过使用::指定模块来最小化缩进:moduleTop::FooclassFailure这失败了:NameError:uninitializedconstantTop::Foo::Test这是一个错误,还是仅仅是Ruby解析变量名的方式的逻辑结果? 最佳答案 Isthisabug,or

随机推荐