普通视图

发现新文章,点击刷新页面。
昨天以前首页

基于P站(Poloniex)的广度优先搜索算法来获得任意两种币的兑换价格


币圈的P站是Poloniex,前几年被孙宇晨收购了,它是一个交易所。我很久之前用过Poloniex,当时对其印象并不是很好。

不过,现在我对其好感增加,因为币安买下的coinmarketcap免费的接口就很多限制。

官方文档),这个接口的频率限制是一秒200次,很慷慨了。

https://api.poloniex.com/markets/price

能返回所有交易配对,比如这样的:

[
    {
        "symbol": "BTS_BTC",
        "price": "0.0000000186",
        "time": 1731852313035,
        "dailyChange": "-0.0462",
        "ts": 1731852313054
    },
    {
        "symbol": "DASH_BTC",
        "price": "0.000317",
        "time": 1731848096481,
        "dailyChange": "0.0063",
        "ts": 1731848096489
    },
    ... ...
]

这个JSON返回的结构是一个数组,每个元素是个结构体,也就是一个币价的具体配对信息,我们可以看成是一条边Edge两个顶点Vertice,这样就是一个图结构(带权图 Weighted Graph,权值就是兑换价格),虽然给的是单边,但其实是个双向的,比如USD_BTC得值可以反过来推得BTC到USD的价格。我们可以设计一个算法,从币价A到币价B,可以通过BFS广度优先搜索算法来获取价格。比如有配对A_B、B_C、C_D我们就可以获得A_D的值。

深度优先搜索算法DFS也可以,不过这个算法会返回找到的第一条路径,并不能保证是最短的,最短的确实是最准确的,因为链也长,转换精度就会下降。

当然,可能存在多条路径,最理想的状态是把这些路径都求出来,取个平均啥的,不过这样就得暴力搜索所有的路径了,算法时间复杂度就会比较高。

以下是BFS广度优先算法的代码,Javascript的,可以用于网页前端或者NodeJs后端,甚至是CloudFlare Serverless Worker或者是其它无服务框架:Azure Function、AWS Lambda等。

const fetch = require('node-fetch');

async function getTicker(a, b) {
  try {
    const response = await fetch('https://api.poloniex.com/markets/price');
    const data = await response.json();

    // 创建一个哈希表来存储代币对及其价格
    const pairMap = new Map();

    // 使用直接对及其反向对填充哈希表
    for (const { symbol, price } of data) {
      const [base, quote] = symbol.split('_').map(token => token.toLowerCase());
      if (!pairMap.has(base)) pairMap.set(base, new Map());
      if (!pairMap.has(quote)) pairMap.set(quote, new Map());
      
      pairMap.get(base).set(quote, parseFloat(price));
      pairMap.get(quote).set(base, 1 / parseFloat(price)); // 添加反向边
    }

    // 将 token 转换为小写
    a = a.toLowerCase();
    b = b.toLowerCase();

    // BFS 查找从 a 到 b 的转换率
    const queue = [[a, 1]]; // 从初始代币和兑换率 1 开始
    const visited = new Set([a]);

    while (queue.length > 0) {
      const [currentToken, currentRate] = queue.shift();

      if (currentToken === b) return currentRate;

      // Check connected tokens
      for (const [nextToken, rate] of (pairMap.get(currentToken) || new Map())) {
        if (!visited.has(nextToken)) {
          visited.add(nextToken);
          queue.push([nextToken, currentRate * rate]);
        }
      }
    }

    // 如果未找到路径,则返回 null
    return null;
  } catch (error) {
    console.error("获取或处理数据时出错:", error);
    return null;
  }
}

// Example usage:
(async () => {
  const rate = await getTicker('btc', 'trx');
  console.log('BTC 到 TRX 的兑换率:', rate);
})();

代码的一些简单说明:

  • API 数据提取:从 P站 API 提取数据并将响应解析为 JSON。
  • 映射对:以每个代币作为键创建一个映射,其中值是它可以直接转换为的另一个代币映射,以及兑换率。
  • 双向映射:通过反转反向转换的价格来存储直接对和反向对。
  • 广度优先搜索:使用队列遍历从 a 到 b 的路径。对于每个代币,都会检查其邻居(可转换代币)。如果找到 b,该函数将返回累积率;如果没有,则继续,直到所有选项都用尽。
  • 处理无路径:如果未找到转换路径,则函数返回 null。

如果有多组兑换,我们可以改成传入一个数组,这样就不用多次调用P站的API了。

const fetch = require('node-fetch');

async function getToken(pairs) {
  try {
    const response = await fetch('https://api.poloniex.com/markets/price');
    const data = await response.json();

    // 创建一个哈希表来存储代币对及其价格
    const pairMap = new Map();

    // 使用直接对及其反向对填充哈希表
    for (const { symbol, price } of data) {
      const [base, quote] = symbol.split('_').map(token => token.toLowerCase());
      if (!pairMap.has(base)) pairMap.set(base, new Map());
      if (!pairMap.has(quote)) pairMap.set(quote, new Map());
      
      pairMap.get(base).set(quote, parseFloat(price));
      pairMap.get(quote).set(base, 1 / parseFloat(price)); // 添加一条反向边
    }

    // 使用 BFS 查找单个对的转换率的辅助函数
    const findConversionRate = (a, b) => {
      a = a.toLowerCase();
      b = b.toLowerCase();
      
      if (a === b) return 1; // 直接转换

      const queue = [[a, 1]];
      const visited = new Set([a]);

      while (queue.length > 0) {
        const [currentToken, currentRate] = queue.shift(); // 出队列

        if (currentToken === b) return currentRate;

        for (const [nextToken, rate] of (pairMap.get(currentToken) || new Map())) {
          if (!visited.has(nextToken)) {
            visited.add(nextToken);
            queue.push([nextToken, currentRate * rate]);
          }
        }
      }

      return null; // 路径没找到
    };

    // 迭代列表并查找转换率
    const results = pairs.map(([a, b]) => findConversionRate(a, b));
    return results;
  } catch (error) {
    console.error("Error fetching or processing data:", error);
    return pairs.map(() => null); // 如果有错误,则返回每对的 null
  }
}

// Example usage:
(async () => {
  const conversionRates = await getToken([['btc', 'trx'], ['usd', 'steem']]);
  console.log('兑换结果:', conversionRates);
})();

简单的代码说明:

  • 参数更新:getToken 现在接受成对的元组数组,其中每个元组代表一对 [a, b]。
  • 辅助函数:findConversionRate 处理每对的转换,实现与以前相同的 BFS 方法。
  • 映射每对:函数迭代数组里的每个配对币,应用 findConversionRate 计算转换率,并将结果存储在数组中。
  • 错误处理:如果出现 API 或处理错误,则返回一个空值数组,与输入数组的长度匹配。

这个修改后的函数现在可以接受一个数组,并在一次Poloniex API调用中返回数组里每个配对的兑换率。

英文:Crypto Token Exchange Rate Computation Based on Breadth First Search Algorithm on Poloniex API

区块链技术

本文一共 1127 个汉字, 你数一下对不对.
基于P站(Poloniex)的广度优先搜索算法来获得任意两种币的兑换价格. (AMP 移动加速版本)

扫描二维码,分享本文到微信朋友圈
75a5a60b9cac61e5c8c71a96e17f2d9c 基于P站(Poloniex)的广度优先搜索算法来获得任意两种币的兑换价格 Javascript Poloniex P站 交易所 Crypto Exchanges 加密货币 区块链 比特币 BTC 程序设计 算法 编程 计算机 计算机 软件工程
The post 基于P站(Poloniex)的广度优先搜索算法来获得任意两种币的兑换价格 first appeared on 小赖子的英国生活和资讯.

相关文章:

  1. HPZ800服务器主板太老不支持超过2TB的大硬盘 我家里一直用的是HPZ800服务器, 很吵, 很老, 虽然这台服务器已经有十年之久(我在EBAY上买来用了五年多了), 但是即使放到今天, 这服务器速度依旧很快, 很稳定. 由于服务器用的是ECC较验内存, 所以基本上不重启关机. HPZ800主机有两个硬核CPU – 因特志强 X5650 – 每个CPU是12核....
  2. 给孩子零花钱培养孩子正确的金钱观价值观 两个娃已经不知不觉7岁8岁了. 媳妇和我商量一下决定给孩子每人每周5英镑的零花钱(Pocket Money). 这样他们慢慢的就有自己的小积蓄备将来不时之需: 比如朋友聚会生日啥的需要准备礼物. 同时, 我们决定不再给孩子买零食(薯片啥的). 孩子一天好几餐, 晚上睡觉前还得吃零食, 我们就多买了很多水果面包, 健康的食物多吃一些总不是啥坏事. 孩子可以用这些零钱买自己想要的东西, 我们也不再过问. 孩子有自己的决定权. 第一周的时候,...
  3. 测测你的幸运 – Linux Fortune-Teller LINUX 下有很好很好玩的命令,之前已经介绍过: figlet, rig, curl. 现在推荐另一个 命令 fortune 是用来随机显示一段(句)话的.fortune 在英文里就是幸运的意思. 这个命令可以不需要 参数 如果没有 可以通过 apt-get...
  4. 负电价活久见: 安装Octopus智能电表省电费甚至赚钱 前几周我的电气公司 Octopus 终于来装智能电表了(Smart Meter),虽然是免费安装的,但是排队排了有两三年了吧。因为之前一直写邮件催的时候就老是说 Not Ready。 收到邮件说可以安装智能电表我还是相当开心和期待的,因为已经听说这玩意好,但是还是得亲身体验一下。工程师来安装大概不到2小时,其中需要停电闸一会儿,重新接下线。装好后,给了个小册子,自动切换到了 Agile 的电价,也就是每半小时的电价都不一样,提前一天可以在手机App和网站上查得。 正好在原来的电价计费合同快要结束前2天换到了智能电表计价 Octopus Agile方式,但是系统还是扣了我75英镑 Exit Fee (提前合同结束得交违约费),不过我一个电话打过去,公司很爽快就给我退了。...
  5. ChatGPT-4 使用 Math Wolfram 插件解决数学脑筋急转弯问题 这篇文章, 我们看一个简单的数学问题(脑筋急转弯), 并用 Python 解决它. 我们看一下LLM(大型语言模型): ChatGPT3.5和ChatGPT4. 通过 ChatGPT-Plus 订阅(目前每月 20 美元 + VAT增值税), 我们可以启用...
  6. 微软面试题: 三角形的面积是多少? 据说是一个印度人杀入微软最后的面试, 面试官给了这么一道小学数学几何题: 这哥门也有疑问 可是最后还是坚持 答案 30 (底 X 高 / 2) 不存在 这是个陷井: 这个直角三角形是不存在的. 两个小直角三角形的勾股定理:...
  7. 给STEEM中文微信群加了个机器人 之前说到我的公众号 justyyuk 可以查询几种虚拟货币的实时价钱, 但是有点不方便, 因为很多朋友在群里聊天得切换到公众号, 这下好了, 今天往STEEM中文微信群(还有编程群)加了个机器人, 在聊天的时候想了解价钱就直接输入货币代号即可, 如: 既方便自己, 又能方便别人(省事, 价格信息会同时显示给其它成员). 注: 这机器人不是我做的, 只是我拉进来的,...
  8. Javascript 中 sleep 函数实现 Javascript 中并没有 built-in 的 sleep 函数支持, 在 async/await/Promise 的支持之前, 我们可以用 busy-waiting 的方式来模拟: 1 2 3...

三次冲击谷歌软件工程师: 我的面试起伏录 (谷歌面试是不是一生只有三次机会?)


Google(谷歌)是全球知名的互联网巨头之一,几年前被认为是养老终级大厂,福利优厚,压力相对较小。在英国伦敦,Google设有一个主要从事开发和研究的办公室。

第一次面试 2016年

我在2016年首次面试Google。第一轮是电话面试,由一位在瑞士的工程师主导,通过电话交流并在Google Doc上同步编写代码。由于当时技术水平有限,我用C++完成了那道消息打印的题目,核心是使用队列和哈希表来解决问题,写得很磕磕巴巴。

当时对软件工程师的级别没有特别概念,推测自己面的是SWE L4/L5的级别,因为当时也就工作了5年多。

我查了一下邮件,2013年11月份的时候谷歌猎头联系我问我要不要试试?我说我当时没拿到英国永居,不想冒险,虽然他说到谷歌可以办工签,我当时还是没有选择去面试,现在想起来实在不可思议,后来2014年/2015年的时候同一个猎头还每隔6个月就check-in一次,最后面是在2016年4月份的时候才开始第一次的。

hello-from-google-email-3-years 三次冲击谷歌软件工程师: 我的面试起伏录 (谷歌面试是不是一生只有三次机会?) 程序员 软件工程 面试

这个谷歌猎头很敬业,2014年联系我,最后跟踪了三年让我参加第一轮面试。

我要是当时聪明一些,努力刷题一些,搞不好当时进谷歌,现在也工作将近十年了,拿着谷歌股票到现在,也不至于现在混个高不成低不就的。

第二次面试 2020年

第二次面试是2020年11月份,第零轮其实应该算是Google的猎头问的一些选择题,比如C++里的哈希表/map如果访问一个不存在的键会发生什么?Google的软件工程师包括SRE站点可靠工程师在面试的时候都可以选两种路径,一个是数据结构和算法(编程),另一个是运维/DevOps偏LINUX知识的。我都选前者,毕竟这个我感觉只要短期刷题就好了,相反后者需要多年工作实战的积累。

通过了猎头的小测试,我进入了第一轮,是道编程题,但是并不是那种力扣上可以见到的,这一轮45分钟,给得是一个比较有意思的游戏,比如迷宫生成算法。面试的时候需要你主导整个过程,包括澄清问题,构思,写代码,分析复杂度等等,每一步都需要你Think Aloud。虽然这一轮我犯了些错误,但是给得反馈总题还不错,面试官说他觉得我应该进入下一轮。

到了终面,安排在了同一天,上午2轮,下午3轮,我记得3轮编程/Coding,一轮系统设计,一轮Culture Fit/Behavior/行为模式。除了系统设计是1小时,其它的4轮都是45分钟,谷歌的Coding面试45分钟都是解决1题即可,题目并不是力扣上的,题目范围/scope较大,偏难。一般来说coding完还会有一些Follow-up的问题,比如怎么优化算法。这个和Meta/Facebook的Coding面试不同,Meta百分百喜欢出力扣上原题,40分钟内需要解决2题力扣原题(留5分钟问问题),这个可以通过力扣按公司归类最近3/6个月的试题准备即可。

系统设计我记得是设计一个类似AWS S3的文件存储,也不知道是不是看我当时在AWS S3工作。很可惜,最后面这一轮不过关,当时我面的是L5(Senior),软件工程师级别越往上走,对系统设计的能力则要求越高(设计可扩展/分布式/高性能的系统 )。

Unfortunately Google doesn’t disclose specific feedback per interview session so in this case I can’t share more context. I wish I had more to share with you! Also, we don’t use the scoring system from 1-4 anymore, each person puts in full context, notes, and recommendations and then HC reviews for an overall consensus decision.

不幸的是,Google 不会披露每个面试环节的具体反馈,因此在这种情况下我无法分享更多背景信息。我希望我能与您分享更多!此外,我们不再使用 1-4 的评分系统,每个人都会提供完整的背景信息、注释和建议,然后由 HC 进行审查以做出总体共识决定。

一般大厂来说,不太会降级别给Offer,也就是说,如果面的是L5职位,但是能力可能只到L4,一般来说是不会给Offer的,但也不排除个别情况下,据说Meta就有面试E5给E4的情况。

级别是在面试过程中根据您的个人背景确定的,包括简历经验、面试表现等多种因素,以及与 SWE/SRE 的契合程度。

Unfortunately we reviewed for overall technical depth slotted against our teams and right now the decision is not to proceed.

不幸的是,我们审查了我们队伍的整体技术深度,现在的决定是不继续。

这次面试的职位是SRE站点可靠工程师

我的面试谷哥GOOGLE伦敦SRE的经验和教训

第三次面试 2024年

其实去年2023年,也申请了谷歌伦敦Google Research的位置,当时和猎头简单聊过之后,就没下文了,猎头说会把我的简历给招聘经理,不过等了好几周,最后面很抱歉的说已经招了别人了。

Apologies for the radio silence on this one, we have had radio silence from the hiring manager on this role. They have unfortunately decided to prioritise other hiring areas in the team so we won’t be able to move forward at this stage.

However, if we have any other roles in the future I will make sure to keep you in mind.

抱歉,我们没有得到任何回复,我们一直没有收到招聘经理关于这个职位的任何回复。不幸的是,他们决定优先考虑团队中的其他招聘领域,因此我们目前无法继续推进。

但是,如果我们将来有其他职位,我一定会记住你的。

2021年/2022年我记得也投过,不过都没有下文(简历被拒),有一年直接申请Google瑞士,因为听说那边的工资高,和美国一样高,所以想试了试,第二天直接收到了拒信,还是谷歌瑞士的工程师直接发的邮件。

今年就随手申请了一下,也不知道是不是招聘市场回暖,简历同时过了Meta和Google的第一轮筛选。上一次2020年也是,同一时间面试Google和Meta,两个公司的面试都进入了最后一轮(Final Onsite)。

今年和Google猎头聊了聊,她并没有给小测试,就是了解了情况,然后让我选是以算法为主还是运维/DevOps为主,我今年面试的是SRE站点可靠工程师,和第二次一样。

第一轮面试也是一轮设计一个简化版的游戏,面试了45分钟,最后面拖了三分钟 Follow-up问题,也就是把这游戏 Scale Up,如果很多很多人玩,单机内存不够怎么办?

google-interview-first-round-coding-ring 三次冲击谷歌软件工程师: 我的面试起伏录 (谷歌面试是不是一生只有三次机会?) 程序员 软件工程 面试

今年第一轮谷歌面试在家里中午午休的时候进行的,45分钟。这个是当时我房间的Ring拍摄记录的。

我最开始的暴力解法写得很6,犯了两个小错误,并不是Bug Free,不过面试官指出后我立马意识到并改正了,后来优化需要用到 二分搜索+前缀和/Prefix Sum,面试官很满意说他没想到这种方法。

再后来的优化用到了线段树,但由于时间限制,并不需要去实现,但需要讲明白算法原理。我脑子里想着另一种实现二叉索引树Binary Index Tree,但是不记得实现原理了,结果在那里纠结浪费了一些时间。

最后面给出的回馈就是最后面的Follow-up回答得不是很好。不过并没有立刻拒我,我猜是我过了Bar,但是并不是表现最好的那一个。一般一个职位一个坑,如果接到100份简历,那么只会邀请6-8个来进行第一轮面试,然后淘汰掉一半,最后面邀请3-4个来进行终面。

当时猎头给我打电话,说了反馈,然后就说暂时把我的申请on-hold了。

又过了两周,猎头给我回复:

I hope you’re keeping well, I just wanted to update you that we have now closed our London role. If we get another one through we will definitely be in touch! Thank you so much for everything you invested in our interviews, I know you put in a lot, on top of everything else and elsewhere too – and I know it takes a lot, so really do appreciate it, and I really hope we can keep in touch and work together again in the not so distant future! Take care and thank you again for everything you invested in our process, I really enjoyed working with you and getting to know you.

I wish you every strength, take care XXX!

希望你一切安好,我只是想告诉你,我们现在已经结束了伦敦的职位。如果我们又有新职位,我们一定会保持联系!非常感谢你为我们的面试所做的一切,我知道你付出了很多,除了其他一切之外,也付出了很多——我知道这需要很多,所以真的很感激,我真的希望我们能保持联系,在不久的将来再次合作!保重,再次感谢你为我们的过程所做的一切,我真的很高兴和你一起工作,认识你。

祝你一切顺利,保重 XXX!

我回了(不知道可不可以再投其它职位):

Could I apply to other roles if there are any suitable in the meantime? Or is it better to just wait?

如果在此期间有其他合适的职位,我可以申请吗?还是最好等待?

更新:Google猎头隔了几天又回了:

I hope you’re keeping well! Thank you for your patience, we should have some roles coming live in London so I’ll catch up with you super soon! Good news!

希望你一切安好!谢谢你的耐心,我们应该会在伦敦有一些HC职位,所以我很快就会再次联系你!好消息!

每年都面试一下,才能知道自己几斤几两。

谷歌面试是不是一生只有三次机会?

谷歌的面试通常没有严格的次数限制,理论上并不是“一生只有三次机会”。不过,谷歌对多次申请有一定的冷却期政策,这意味着在未通过面试后,申请者需要等待一段时间才能再次申请。

通常的冷却期为6到12个月,但这时间会因具体情况和职位类型有所不同。如果之前的面试表现较好,甚至可以更早重新申请。此外,间隔期越长,对候选人的成长和进步的期望也会更高,因此再次面试时需要准备得更充分。

英文:Three Attempts at Google: My Software Engineer Interview Journey (Is There Only Three Chances in a Lifetime?)

面试经历

面试题

面试技巧

面试其它

本文一共 2568 个汉字, 你数一下对不对.
三次冲击谷歌软件工程师: 我的面试起伏录 (谷歌面试是不是一生只有三次机会?). (AMP 移动加速版本)

扫描二维码,分享本文到微信朋友圈
75a5a60b9cac61e5c8c71a96e17f2d9c 三次冲击谷歌软件工程师: 我的面试起伏录 (谷歌面试是不是一生只有三次机会?) 程序员 软件工程 面试
The post 三次冲击谷歌软件工程师: 我的面试起伏录 (谷歌面试是不是一生只有三次机会?) first appeared on 小赖子的英国生活和资讯.

相关文章:

  1. 按揭贷款(房贷,车贷) 每月还贷计算器 去年给银行借了17万英镑 买了20万7500英镑的房子, 25年还清. 前2年是定率 Fix Rate 的合同 (年利率2.49%). 每个月大概是还 700多英镑. 有很多种还贷的计算方式, 定率/每月固定 是比较常用的. 简单来说就是 每个月交的钱是...
  2. 智能手机 HTC One M9 使用测评 虽然我对手机要求不高, 远远没有像追求VPS服务器一样, 但是怎么算来两年内换了四个手机, 先是三星 S4 用了一年多, 然后 Nokia Lumia 635 Windows Phone, 后来又是 BLU, 半年多前换了...
  3. 博士毕业五年多了 无意翻出 FACEBOOK 五年前上传的博士毕业典礼视频, 才发现自己已经工作近六年了. 还记得当时毕业时的兴奋 为了 一个 ‘Doctor’ 的称号奋斗了三年多 不过这几年对头衔看得越来越淡 包括在公司里也一样 什么职位也无所谓了 做着自己喜欢的事情才是最重要的. 这是 2010年...
  4. WP中检查白名单的用户是否登陆? WordPress 提供了一个方法 is_user_logged_in() 用于检查用户是否是登陆状态. 但是很可惜 这个方法在 pluggable.php 中定义. 也就是说如果你需要在插件中使用, 那么这个函数是没有被定义的. 我们来看一下 is_user_logged_in() 的实现: 1 2...
  5. 同一台服务器上多个WORDPRESS站点的一些设置可以移出去 我自从把所有网站都挪到一处VPS服务器上 就发现很多事情省事很多 可以同时管理多个网站 包括 WORDPRESS博客. 比如我有四个WORDPRESS博客 然后我就把通用的一些资料给移出去 移到 HTTP或者HTTPS都不能直接访问的文件夹里这样就更安全许多. 文件 wp-conn.php 存储了 相同的数据库资料. 1 2...
  6. 三分熟的牛排 除了像早餐, Fish and Chip, 英国酒巴也是吃得到一些外来引进的食物,比如牛排.虽然一般的酒巴里的牛排 (Steak) 一般都不是很地道,表现在你要个三分熟的牛排基本上都是 烧熟了的给你.还有就是牛肉本身也有区别,嫩,而且要新鲜. 上周五发现一家巴西烤肉自助,刚上来的牛排就不错, 三分熟,新鲜,嫩.要是能有个红酒就再好不过了. 五分熟的可以说是 medium (cooked), well done...
  7. 免费的 Visual Studio 2013 社区版 程序员应该都知道 Visual Studio, 这个是微软的得意之作.是世界上最好用的程序设计工具 IDE. 现在 2013 社区版是免费的! 个人开发,和开源什么的都不需要费用.统统都是免费的. VS2013社区版本可以在这个URL下载: http://www.visualstudio.com/en-us/visual-studio-community-vs.aspx 之前我机器装了 VS2012 和 VS2010....
  8. 老婆的配偶签证被拒 郁闷死了, 601镑签证费打水漂,一去不回!费钱费力. 去年12月份我请了律师拿到了永居.老婆是T1G签证的陪工签 (DEPENDENT VISA) 2016年4月份到期. 然后我就想说得趁早把她的签证转成配偶签(SPOUSE)这样她就可以尽快走五年永居的路线. 今天收到拒签信,原因是我没有提供 有工资进帐的那份银行帐单,我提供了我和我老婆的联名帐户, 但是工资并不是直接打到这个帐单上的.所以就这一点被拒了.完全不给解释,不给补材料的机会.601镑就这样再见了. 英国的签证寄出之后是先由另一个部门先收费, 收完费才正式审理,而且不管结果如何是不退钱的.后悔没让律师弄,也不至于到现在浪费这么多时间和金钱,签证还没过.由于原签证还没到期,所以还不能上述.估计只能等搬完家后年底请律师搞定这事. 真是郁闷, 600镑, 我可以再买一个IPHONE6,或者给我的新买的车换四个轮胎....

站点可靠性工程师(SRE) vs 软件开发工程师(SE/SDE)


许多大公司都有站点可靠性工程师(SRE = Site Reliability Engineer)的职位空缺。例如,谷歌、Facebook/Meta 或字节跳动的抖音。软件工程师(Software Engineer)与亚马逊/Amazon所称的软件开发工程师相同(Software Development Engineer)。

站点可靠性工程师(SRE)是一个专注于确保生产环境中软件系统的可靠性、可扩展性和性能的角色。SRE 负责服务的健康状况和正常运行时间,平衡软件开发与运维任务。软件工程师(SE)主要专注于编写和维护代码以创建软件产品,而 SRE 则融合了开发技能、系统管理、故障排除和事件管理,以确保这些产品在实际环境中顺利运行。

以下是两者之间关键区别的比较:

站点可靠性工程师 (SRE)

专注于可靠性与运维:

  • 确保系统高度可用、可扩展且具有弹性。
  • 监控系统健康状况,管理事件并处理故障。

运维自动化:

  • 使用代码自动化手动任务(例如基础设施部署、监控和补救措施)。
  • 通过创建自动恢复或仅需最少人工干预的系统来减少重复性工作。

随叫随到的职责/也就是On-call:我在亚马逊AWS云On Call的体验

  • 通常参与随叫随到的轮值,处理操作问题和紧急情况。

性能和容量规划:

  • 分析系统性能,确保系统能够应对增长和流量高峰。

SLA、SLO 和 SLI:

  • 定义和管理服务级别协议(SLA)、目标(SLO)和指标(SLI),以测量并确保正常运行时间和性能指标。

事件管理:

  • 调查事件,领导事后分析,并实施修复措施以防止未来发生类似问题。

软件工程师 (SE)

专注于开发:

  • 主要参与设计、开发和维护软件应用程序或服务。
  • 通常致力于构建新功能或改进现有软件。

产品开发:

  • 在开发阶段关注软件的功能性、可扩展性和可维护性。

与其他团队合作:

  • 与产品经理、设计师和其他工程师合作,定义功能并实现软件解决方案。

代码质量和测试:

  • 编写测试代码,并通过代码审查、单元测试和自动化测试等实践确保代码质量。

较少参与生产操作:

  • 通常不负责系统正常运行时间或紧急响应(除非在专注于 DevOps 的团队中工作)。

重叠点:

  • 编码技能:SRE 和 SE 都编写代码,但 SRE 可能更侧重于自动化和支持生产系统的工具。
  • DevOps 实践:两种角色可能都遵循 DevOps 原则,以确保持续集成和部署,SRE 强调可靠性,而 SE 则注重开发速度和功能交付。

总而言之,SRE 是一个强调确保生产系统可靠性和运维效率的专门角色,而软件工程师则更多地专注于构建和增强软件。

SE 和 SRE 入职门槛要求的比较

关键区别:SRE 角色通常需要更深的系统操作和基础设施管理知识,而 SE 角色则更强调软件开发和计算机科学理论。

站点可靠性工程师 (SRE)

教育/背景:

  • 通常需要计算机科学、系统工程或相关领域的背景,类似于软件工程
  • SRE 往往具备软件开发和系统管理(Linux、网络等)技能的组合。
  • 通常需要 DevOps 工具、云基础设施(AWS、GCP、Azure)和自动化工具(如 Ansible、Terraform 或 Kubernetes)的经验。

运维经验:

  • SRE 需要管理生产环境、理解 SLA、监控和事件管理的实际经验。

所需技能:

  • 系统工程(Linux、网络等)方面的强大知识。
  • 熟练掌握脚本编写/编程(Python、Go、Ruby 等),用于自动化任务。
  • 具备监控工具(如 Prometheus、Grafana)、CI/CD 管道和基础设施自动化的经验。

软件工程师 (SE)

教育/背景:

  • 通常需要计算机科学或相关领域的学位,尽管有些人通过编程训练营或自学进入该领域。
  • 专注于数据结构、算法和构建软件解决方案。
  • 为应届毕业生或那些具有较少专业经验的人(实习、项目)提供入门级职位。

所需技能:

  • 熟练掌握一种或多种编程语言(Java、Python、C++ 等)。
  • 对计算机科学基础(算法、数据结构、面向对象设计)有深入了解。
  • 具备编写干净、可维护、可扩展代码的能力。

SE 和 SRE 面试难度的比较

关键区别:SE 面试更侧重于算法,而 SRE 面试更多关注系统、操作和可靠性工程,编码要求较低但仍然重要。

站点可靠性工程师 (SRE)

难度:中等到高

  • SRE 面试通常涵盖广泛的主题,包括系统设计、故障排除、生产级故障和监控。
  • 面临与系统可靠性、基础设施扩展和事件响应相关的解决问题的挑战。
  • 面试通常测试您的网络、Linux 基础、云架构和基础设施自动化知识。
  • 部分面试可能会专注于编码,但复杂性因公司而异(通常为中等难度,以脚本为主的任务)。

涉及主题:

  • 系统设计(重点是可靠性、弹性)。
  • 与自动化相关的编程/编码挑战。
  • 故障排除和事件处理。
  • 监控和性能优化。
  • 网络基础和基于 Linux 的系统知识。

软件工程师 (SE)

难度:高

  • SE 面试通常更多关注算法、数据结构和编码挑战。
  • 高级职位的系统设计面试可能会非常复杂,涉及可扩展架构、分布式系统和性能优化。
  • SE 面试往往更注重算法密集度,测试您在时间限制下解决问题的能力。

涉及主题:

  • 数据结构和算法(例如排序、图遍历、动态规划)。
  • 系统设计(针对高级角色)。
  • 以编码风格、团队合作和问题解决为重点的行为面试。
  • 在 LeetCode、HackerRank 或公司自定义平台上的编码练习。

SE 和 SRE 薪酬待遇的比较

关键区别:两种角色的总薪酬非常相似,尤其是在顶级科技公司中的高级职位。然而,在某些技术性极高的职位上(例如高级工程师/首席工程师),SE 可能会因为更大的股票和奖金包裹而超越 SRE。

站点可靠性工程师 (SRE)

基础薪资/Base:

  • 在顶级科技公司(如谷歌、Meta、亚马逊),SRE 的基础薪资通常较高,类似于软件工程师。
  • 在美国,入门级 SRE 的年薪约为 12 万 – 16 万美元。
  • 高级 SRE 的年薪可能在 18 万 – 22 万美元或更高,具体取决于公司和地点(特别是在硅谷等科技中心)。

总薪酬/Total Package:

  • 包括奖金、股票期权和其他福利后,顶级科技公司中的 SRE 的总薪酬可能达到 20 万-35 万美元或更高,特别是高级职位。
  • SRE 经常获得与系统正常运行时间、可用性或事件管理相关的丰厚奖金。

软件工程师 (SE)

基础薪资/Base:

  • SE 的基础薪资通常与 SRE 类似,尤其是在大型科技公司中。
  • 入门级软件工程师的起薪通常在 11 万 – 15 万美元之间。
  • 高级软件工程师的年薪可能在 18 万 – 25 万美元或更高,具体取决于经验、地点和公司。

总薪酬/Total Package:

  • 包括股票期权、奖金和绩效奖励后,SE 在大型科技公司中的总薪酬可能达到 20 万 – 35 万美元或更高,尤其是在股票重的薪酬结构(例如谷歌、Meta、亚马逊)中。
  • 在某些公司,软件工程师的薪酬可能会因为更大的股票包裹而偏高,特别是在较高级别上。

SRE 和 SE 的总结

方面 站点可靠性工程师 (SRE) 软件工程师 (SE)
入职要求 系统/运维经验,基础设施,自动化知识 强大的编码技能,计算机科学基础,专注于开发
面试 系统设计,运维,自动化,事件管理 算法密集,数据结构,编码和系统设计
薪酬 与 SE 相似,基础薪资 $120K–$220K;顶级科技公司总薪酬 $200K+ 与 SRE 相似,但在高级职位上 SE 可能比 SRE 赚得更多

两种工作都非常有价值,尽管 SRE 职位需要更多的系统和运维专业知识,而 SE 职位则更强调开发和算法问题解决。

英文:Site Reliability Engineer (SRE) vs Software Engineer

软件工程师

本文一共 2207 个汉字, 你数一下对不对.
站点可靠性工程师(SRE) vs 软件开发工程师(SE/SDE). (AMP 移动加速版本)

扫描二维码,分享本文到微信朋友圈
75a5a60b9cac61e5c8c71a96e17f2d9c 站点可靠性工程师(SRE) vs 软件开发工程师(SE/SDE) 工作 程序员 资讯 软件工程
The post 站点可靠性工程师(SRE) vs 软件开发工程师(SE/SDE) first appeared on 小赖子的英国生活和资讯.

相关文章:

  1. 避免选择低质量没保障的 VPS 公司 现在程序员基本都会有VPS服务器, 价钱也不贵, 一个月几美元, 随随便便就能申请个玩. 我自己这几年也玩了不少VPS, 现在手上大概有10台VPS, 用于不同的服务: 博客, 区块链, API等用途. 上两周, 其中一台服务器商 supremevps 突然发邮件 给两天时间,...
  2. 按揭贷款(房贷,车贷) 每月还贷计算器 去年给银行借了17万英镑 买了20万7500英镑的房子, 25年还清. 前2年是定率 Fix Rate 的合同 (年利率2.49%). 每个月大概是还 700多英镑. 有很多种还贷的计算方式, 定率/每月固定 是比较常用的. 简单来说就是 每个月交的钱是...
  3. C/C++ 中的内存管理器(堆与栈) 最近面试的时候遇到这个问题。这个问题考你计算机的基本功。 在 C/C++ 中,内存管理是控制程序如何分配和管理其资源的关键方面。C/C++ 程序中的内存通常分为不同的区域:堆栈和堆是最主要的动态和自动内存分配区域。 ACM题解系列之 – 最小堆栈 (Min Stack) 堆栈内存 定义:堆栈内存用于静态(自动)内存分配。它是存储函数参数、本地变量和返回地址的地方。当调用一个函数时,一个新的内存块(称为堆栈帧)会被添加到堆栈的顶部。当函数返回时,该内存会被自动释放。 分配:内存由系统自动管理——在变量超出作用域时自动分配和释放。无需人工干预。 生命周期:受限于函数或代码块的作用域。一旦函数退出,内存将被释放。 大小限制:堆栈的大小通常较小并由系统预定义,意味着大的分配可能导致堆栈溢出。...
  4. 智能手机 HTC One M9 使用测评 虽然我对手机要求不高, 远远没有像追求VPS服务器一样, 但是怎么算来两年内换了四个手机, 先是三星 S4 用了一年多, 然后 Nokia Lumia 635 Windows Phone, 后来又是 BLU, 半年多前换了...
  5. 测测你的幸运 – Linux Fortune-Teller LINUX 下有很好很好玩的命令,之前已经介绍过: figlet, rig, curl. 现在推荐另一个 命令 fortune 是用来随机显示一段(句)话的.fortune 在英文里就是幸运的意思. 这个命令可以不需要 参数 如果没有 可以通过 apt-get...
  6. 虚拟货币USDT兑换法币英镑的汇率比较: Crypto.com, Ledger硬件钱包卡 和 WirexApps USDT虚拟货币 – 也被常称为U或者泰达币. USDT(Tether)是一种与美元挂钩的稳定币. 它旨在与美元保持 1:1 比价, 这意味着 1 USDT 始终等于 1 美元. 它主要用作不同数字资产交易所之间转移价值的手段, 允许交易者和投资者轻松地在平台之间转移资金,...
  7. 2019剑桥龙舟节: 很荣幸代表福建船队参赛 时间: 2019年6月2日星期日 前不久, 剑桥每年一度的龙舟节在剑桥Jesus Green大草地还有边上的剑河举行了. 每次都是星期天, 所以基本上附近的华人都来了, 很热闹. 旁边的剑河里有条不紊的两两进行着淘汰对抗赛, 草地上大人小孩子席地而坐, 野餐, 聊天. 孩子们有蹦蹦床玩, 有美食(摊位)广场, 天空做美,...
  8. Telegram机器人能通过AI算法进行视频和图片换脸 2023年开始AI火起来了, 各种AIGC算法, 生成美女图, 生成视频, 生成文章, 生成音乐等等. 今天发现一个Telegram机器人号称可以把图片和视频给换脸, 只有一次免费使用的机会, 要继续使用就得充值. 支付方式可以使用波场U-USDT虚拟货币来支付买积分. 10个积分能操作一张图片换脸. 视频换脸: 30积分/10s 图片换脸: 10积分/图片...

软件工程师面试: TCP/IP协议是什么?


最近,在面试第一轮抖音(字节跳动)的伦敦职位(Site Reliability Engineer),被问到了这个问题:TCP/IP协议是什么?这个是考基本功,是每个软件工程师都要会的。

TCP/IP(传输控制协议/互联网协议)是一组网络协议,管理数据如何通过互联网和其他网络传输。它是互联网的基本通信模型,由两个主要层组成:

互联网协议 (IP)

IP 负责将数据包从源地址路由到目标地址。它工作在 OSI 模型的网络层。

  • IP 地址:互联网中的每个设备都被分配了一个唯一的 IP 地址,用于标识数据包的发送者和接收者。
  • 数据包路由:IP 将数据分成多个包,并通过不同的网络将其路由到目标地址。
  • 版本:IP 主要有两个版本:IPv4(32位地址)和 IPv6(128位地址)。

传输控制协议 (TCP)

TCP 负责确保设备之间数据传输的可靠性。它工作在 OSI 模型的传输层。

  • 面向连接:TCP 在传输数据之前会在发送方和接收方之间建立连接。
  • 数据完整性:TCP 通过确认、序列号和错误检查等机制,确保数据包按顺序无误地到达。
  • 流量控制:TCP 通过滑动窗口管理数据流,防止接收方超载。

TCP/IP 协同工作原理

  • 应用数据:应用层将数据(例如网页、电子邮件)发送到传输层(TCP)。
  • TCP 层:TCP 将数据分段,添加序列号和错误检查信息,并将其发送到 IP 层。
  • IP 层:IP 层将 TCP 段封装成 IP 包,附上源和目标 IP 地址,并通过各种网络路由数据包。
  • 接收端:在目标设备上,IP 层将数据包交给 TCP,TCP 重新排列并验证数据的完整性,然后将其传递给应用层。

TCP/IP 套件中的其他协议

  • UDP(用户数据报协议):一种无连接、速度更快的 TCP 替代方案,常用于视频流、在线游戏等实时通信。
  • HTTP/HTTPS(超文本传输协议):用于网络通信的应用层协议。
  • DNS(域名系统):将域名解析为 IP 地址。

TCP/IP 确保数据在网络间高效传输,保持可靠性、地址分配和路由,同时遵循互联网的基本通信原则。

TCP/IP 通常被描述为一个四层模型,但有时它可以与 OSI 模型(七层)进行比较。

tcp-ip-and-osi-model 软件工程师面试: TCP/IP协议是什么? 学习笔记 程序员 计算机 计算机 软件工程 面试

TCP/IP 4层协议和OSI的7层协议的比较

TCP/IP 四层模型

TCP/IP 模型简化为四层,旨在反映协议在现实网络中的工作方式。

应用层

这一层对应于 OSI 模型的前三层(应用层、表示层和会话层)。它包括 HTTP、HTTPS、FTP、DNS 和 SMTP 等协议。

传输层

负责设备之间的可靠通信。运行于这一层的协议包括 TCP(传输控制协议)和 UDP(用户数据报协议)。

互联网层

处理跨网络的数据包路由,类似于 OSI 的网络层。该层包含 IP(互联网协议),用于地址分配和数据包路由。

网络接口层(或链路层)

这一层负责物理网络(如以太网、Wi-Fi)和互联网层之间的数据传输。它对应于 OSI 的数据链路层和物理层。

OSI 七层模型

OSI(开放系统互联)模型更加细致,将网络功能分为七个层次。

  • 物理层(如电缆、交换机)
  • 数据链路层(如 MAC 地址、以太网)
  • 网络层(如 IP 路由)
  • 传输层(如 TCP、UDP)
  • 会话层(如管理应用之间的会话)
  • 表示层(如加密、数据格式转换)
  • 应用层(如 HTTP、FTP)

主要区别:TCP/IP vs OSI

TCP/IP 将一些功能合并为更少的层次(四层),反映了它在互联网通信中的实际应用。

OSI 是一个更加详细的概念模型(七层),主要用于教学和理论理解。

总结来说,TCP/IP 通常被认为是四层模型,而 OSI 模型则是七层模型。

英文:What is TCP/IP (4 Layer vs OSI 7 Layer)?

面试经历

面试题

面试技巧

面试其它

本文一共 1009 个汉字, 你数一下对不对.
软件工程师面试: TCP/IP协议是什么?. (AMP 移动加速版本)

扫描二维码,分享本文到微信朋友圈
75a5a60b9cac61e5c8c71a96e17f2d9c 软件工程师面试: TCP/IP协议是什么? 学习笔记 程序员 计算机 计算机 软件工程 面试
The post 软件工程师面试: TCP/IP协议是什么? first appeared on 小赖子的英国生活和资讯.

相关文章:

  1. 按揭贷款(房贷,车贷) 每月还贷计算器 去年给银行借了17万英镑 买了20万7500英镑的房子, 25年还清. 前2年是定率 Fix Rate 的合同 (年利率2.49%). 每个月大概是还 700多英镑. 有很多种还贷的计算方式, 定率/每月固定 是比较常用的. 简单来说就是 每个月交的钱是...
  2. 孩子喜欢的 cozmo 机器人 小儿子今年刚过5岁生日, 问他要啥生日礼物, 他说想要 cozmo 机器人. 我们都不知道这是啥, AMAZON一搜还不便宜, 均价200多到300多英镑都有. 估计是孩子在学校的时候知道的这机器人. 在AMAZON下了单, 很快就到了. 图像识别算法很厉害. 这机器人很厉害, 不需要告诉它, 它可以自己玩,...
  3. 智能手机 HTC One M9 使用测评 虽然我对手机要求不高, 远远没有像追求VPS服务器一样, 但是怎么算来两年内换了四个手机, 先是三星 S4 用了一年多, 然后 Nokia Lumia 635 Windows Phone, 后来又是 BLU, 半年多前换了...
  4. 这些年在英国开过的车 这个车是真的汽车,从2010/2011年开始学驾照,到2012年考过驾照(两次才过),到现在也有十几年的驾龄了,真的算老司机了。 现在开的是两辆车(第四和第五),分别是奥迪Q5和保时捷卡宴。目前每周加保时捷的油费大概是50英镑。 第一辆 Seat Ibiza 第一辆:在英国的第一辆小黄车 Seat Ibiza (西亚特·伊比飒) 离合很重,男人开的车,当时用来练手,最后面到谢菲而得/Sheffield因为住在市中心不太需要车,就给卖了。 第二辆 奥迪AUDI A6 这辆开了有近十年,当时从谢菲搬家到剑桥Cambourne大剑宝就是开得这车。开了近10年的奥迪A6卖给了车厂(内含开车成本) 我当时买的时候是7000左右,然后买来修了修又多花了1000多英镑,...
  5. 同一台服务器上多个WORDPRESS站点的一些设置可以移出去 我自从把所有网站都挪到一处VPS服务器上 就发现很多事情省事很多 可以同时管理多个网站 包括 WORDPRESS博客. 比如我有四个WORDPRESS博客 然后我就把通用的一些资料给移出去 移到 HTTP或者HTTPS都不能直接访问的文件夹里这样就更安全许多. 文件 wp-conn.php 存储了 相同的数据库资料. 1 2...
  6. Win10右键添加管理员权限.reg 保存以下为 *.reg 文件 双击 Windows Registry Editor Version 5.00 @="获取管理员权限" "NoWorkingDirectory"="" @="cmd.exe /c takeown /f...
  7. 老婆的配偶签证被拒 郁闷死了, 601镑签证费打水漂,一去不回!费钱费力. 去年12月份我请了律师拿到了永居.老婆是T1G签证的陪工签 (DEPENDENT VISA) 2016年4月份到期. 然后我就想说得趁早把她的签证转成配偶签(SPOUSE)这样她就可以尽快走五年永居的路线. 今天收到拒签信,原因是我没有提供 有工资进帐的那份银行帐单,我提供了我和我老婆的联名帐户, 但是工资并不是直接打到这个帐单上的.所以就这一点被拒了.完全不给解释,不给补材料的机会.601镑就这样再见了. 英国的签证寄出之后是先由另一个部门先收费, 收完费才正式审理,而且不管结果如何是不退钱的.后悔没让律师弄,也不至于到现在浪费这么多时间和金钱,签证还没过.由于原签证还没到期,所以还不能上述.估计只能等搬完家后年底请律师搞定这事. 真是郁闷, 600镑, 我可以再买一个IPHONE6,或者给我的新买的车换四个轮胎....
  8. 公司给配了台高配DELL笔记本 早上例会结束的时候我顺便说了一句 我的笔记本有点慢, 当时我并不知道我的经理远程用电话也参加会议了(他全程在听), senior staff SE 对着电话说, “peter, you hear that? btw, my disks are...

C/C++ 中的内存管理器(堆与栈)


最近面试的时候遇到这个问题。这个问题考你计算机的基本功。

在 C/C++ 中,内存管理是控制程序如何分配和管理其资源的关键方面。C/C++ 程序中的内存通常分为不同的区域:堆栈和堆是最主要的动态和自动内存分配区域。

ACM题解系列之 – 最小堆栈 (Min Stack)

stack C/C++ 中的内存管理器(堆与栈) 学习笔记 技术 程序员 程序设计 编程 计算机 软件工程 面试

Stack 栈

堆栈内存

  • 定义:堆栈内存用于静态(自动)内存分配。它是存储函数参数、本地变量和返回地址的地方。当调用一个函数时,一个新的内存块(称为堆栈帧)会被添加到堆栈的顶部。当函数返回时,该内存会被自动释放。
  • 分配:内存由系统自动管理——在变量超出作用域时自动分配和释放。无需人工干预。
  • 生命周期:受限于函数或代码块的作用域。一旦函数退出,内存将被释放。
  • 大小限制:堆栈的大小通常较小并由系统预定义,意味着大的分配可能导致堆栈溢出。
  • 访问速度:由于其后进先出(LIFO)的结构,堆栈内存访问速度更快。由于内存是连续的且可预测的,它允许快速访问。
  • 使用场景:局部变量、函数调用信息和固定大小的对象(数组、结构体)。

堆内存

  • 定义:堆内存用于动态内存分配,程序员使用 C 中的 malloc()、calloc()、free() 和 C++ 中的 new、delete 手动分配和释放内存。
  • 分配:内存在运行时分配,并且分配的生命周期由程序员手动控制。它可以持续存在,直到显式释放。
  • 生命周期:堆分配的对象的生命周期不受作用域的限制。内存将一直被使用,直到被释放为止。
  • 大小限制:堆通常比堆栈大,但取决于系统资源。不当处理可能导致内存泄漏(忘记释放分配的内存)或碎片化(内存使用效率低)。
  • 访问速度:堆内存的访问速度比堆栈慢,因为分配是分散的,动态分配涉及更多的开销。
  • 使用场景:如链表、等大数据结构,或在运行时确定大小的对象。

堆与栈的主要区别

特征 堆栈
内存大小 通常较小,预定义 通常较大,受系统资源限制
分配 自动,由编译器管理 手动,由程序员管理(使用 new、malloc 等)
释放 自动(函数退出时) 手动(使用 delete、free 等)
生命周期 限于函数/代码块作用域 可以持续,直到显式释放
速度 较快(连续内存) 较慢(分散内存,开销更大)
风险 堆栈溢出(如果超出大小限制) 内存泄漏和碎片化

堆栈分配示例

void function() {
    int x = 10; // 分配在堆栈上
} // x 会自动释放

堆分配示例

void function() {
    int* p = new int; // 分配在堆上
    *p = 10;
    delete p; // 必须手动释放
}

正确管理堆内存在 C/C++ 中非常重要,因为它可能导致与内存相关的错误,如内存泄漏或重复释放。理解堆和堆栈内存之间的差异有助于优化程序的性能和可靠性。

英文:The Memory Manager in C/C++ (Heap vs Stack)

面试经历

面试题

面试技巧

面试其它

本文一共 874 个汉字, 你数一下对不对.
C/C++ 中的内存管理器(堆与栈). (AMP 移动加速版本)

扫描二维码,分享本文到微信朋友圈
75a5a60b9cac61e5c8c71a96e17f2d9c C/C++ 中的内存管理器(堆与栈) 学习笔记 技术 程序员 程序设计 编程 计算机 软件工程 面试
The post C/C++ 中的内存管理器(堆与栈) first appeared on 小赖子的英国生活和资讯.

相关文章:

  1. Javascript 中 sleep 函数实现 Javascript 中并没有 built-in 的 sleep 函数支持, 在 async/await/Promise 的支持之前, 我们可以用 busy-waiting 的方式来模拟: 1 2 3...
  2. 按揭贷款(房贷,车贷) 每月还贷计算器 去年给银行借了17万英镑 买了20万7500英镑的房子, 25年还清. 前2年是定率 Fix Rate 的合同 (年利率2.49%). 每个月大概是还 700多英镑. 有很多种还贷的计算方式, 定率/每月固定 是比较常用的. 简单来说就是 每个月交的钱是...
  3. 《Steem 指南》之 justyy 在线工具与 API 系列 – 同时给多个帐号发送SBD或者STEEM 同时给多个帐号发送SBD或者STEEM STEEMIT 和 BUSY 的前端都有一个内置的钱包工具, 您可以一次给一个帐号发送 SBD 或者 STEEM. 当我们要给很多很多人发送钱的时候, 就显得有些不方便了. 这时候可以用这个在线工具: https://steemyy.com/wallet-tool/ 填写表单 只需要填上你的ID,...
  4. 智能手机 HTC One M9 使用测评 虽然我对手机要求不高, 远远没有像追求VPS服务器一样, 但是怎么算来两年内换了四个手机, 先是三星 S4 用了一年多, 然后 Nokia Lumia 635 Windows Phone, 后来又是 BLU, 半年多前换了...
  5. 拔牙后的注意事项(图, 慎入) Care of Mouth after Extraction 昨天又拔了两颗牙, 初步定在5月4号装牙套. 这是牙医诊所给的术后注意事项: 拔完后需要等3-4小时麻醉失效后才能吃喝. 稍微流点血是很正常的. 但是请不要漱口吐出, 因为这会加速流血. 你只要轻轻的含着口水并咽下即可. 如果一直流血, 请拿着纱布(并不是纸巾)放在拔牙处20分钟. 24小时内请不要运动, 术后几小时内回家静静坐着. 12小时内不要吸烟, 喝酒或者喝热饮, 因为这会让伤口流血....
  6. 同一台服务器上多个WORDPRESS站点的一些设置可以移出去 我自从把所有网站都挪到一处VPS服务器上 就发现很多事情省事很多 可以同时管理多个网站 包括 WORDPRESS博客. 比如我有四个WORDPRESS博客 然后我就把通用的一些资料给移出去 移到 HTTP或者HTTPS都不能直接访问的文件夹里这样就更安全许多. 文件 wp-conn.php 存储了 相同的数据库资料. 1 2...
  7. 最简单有效的过滤WordPress垃圾评论的方法 当你的Wordpress博客流量大的时候, 不免会收到很多垃圾评论. 本文介绍一种特别简单而且免费的过滤Wordpress垃圾评论的方法. 这种方法不需要你安装任何插件, 也不需要拥有修改Wordpress主题模板函数的能力, 只需要1分钟就可以搞定. 把这个列表拷贝下来 打开 WordPress 的控制面版, 到设置-讨论 拷贝上面的列表到 “评论审核” 或者 “评论黑名单”...
  8. 更改全站的评论名称 坛子给我建议说: 我觉得很有道理,但是别人网站上的留言我改不了, 自己的还是可以先改改的. 于是,我登陆 phpmyadmin (一个网页式的php mysql 管理平台) 然后输入以下命令: update `wp_comments` set `wp_comment_author` = 'JustYY.com...

软件工程师经典面试题: 当你在浏览器的地址栏敲入google.com并按回车后发生了什么?


我认为这无疑是最受欢迎的软件工程师的(Software Engineer) 面试问题 之一。最近有人说这个问题曾出现在 抖音Tiktok 的面试中。

要回答面试中的“当你在浏览器中输入 https://www.google.com 时会发生什么?”这个问题,可以按步骤详细说明整个过程,涉及 DNS 查找、TCP/SSL 握手、请求处理和页面渲染。以下是全面的解释:

URL 解析

当你输入 URL https://www.google.com 并按下回车时:

  • 协议:浏览器识别出协议是 https,意味着它将使用 HTTP 加密传输(TLS)。
  • 主机:浏览器识别出 www.google.com 是域名。
  • 路径:默认路径是 /,因为没有提供具体路径,表示请求主页。

DNS 查找

浏览器需要将域名 www.google.com 转换为一个 IP 地址。这个过程分为几个步骤:

  • 浏览器缓存:浏览器 首先检查自己的缓存,看看是否已有 www.google.com 的 IP 地址。
  • 操作系统缓存:如果未找到,浏览器会向操作系统请求缓存。
  • 路由器缓存:如果操作系统没有该 IP,路由器会检查它的缓存。
  • ISP DNS 服务器:如果依然未找到,路由器会查询 ISP 的 DNS 服务器。
  • 递归 DNS 查找:如果 ISP 没有缓存 IP,DNS 服务器会递归查询 DNS 层次结构(根 DNS 服务器、顶级域名服务器、权威 DNS 服务器)。最终,www.google.com 的 IP 地址被解析出来(例如,142.250.72.196)。

建立 TCP 连接

知道 IP 地址后,浏览器需要与 Google 服务器建立连接,使用以下步骤:

TCP 三次握手:

  • SYN:客户端(浏览器)向服务器发送 SYN(同步)包,启动连接。
  • SYN-ACK:服务器响应 SYN-ACK(同步确认)包。
  • ACK:客户端发送 ACK 包,连接建立。

SSL/TLS 握手(针对 HTTPS)

由于使用的是 HTTPS,浏览器与服务器通过 SSL/TLS 建立加密连接:

  • 浏览器与服务器协商加密协议(TLS 版本)并交换加密密钥。
  • 服务器发送其 SSL 证书,浏览器验证该证书以确保服务器身份。
  • 生成会话密钥,用于加密接下来的通信。

HTTP 请求

建立安全连接后,浏览器向服务器发送 HTTP GET 请求:

  • 方法:GET
  • 请求头:包括浏览器类型、cookies 和缓存信息。
  • 主机:www.google.com
  • 路径:/

服务器处理

Google 的服务器位于 负载均衡器 后面,接收请求:

请求可能会通过多个反向代理和负载均衡器处理,通常分布在多个数据中心,以确保可用性和性能

Google 的 Web 服务器处理请求,检查所请求的资源(Google 的主页),并准备响应。

HTTP 响应

服务器返回一个 HTTP 200 OK 响应,并将必要的 HTML、CSS、JavaScript 和其他资源发送到浏览器。

响应包括响应头(如 Content-Type、Cache-Control)以及响应体(Google 主页的 HTML 内容)。

浏览器渲染

浏览器现在获取了 HTML 并开始渲染页面:

  • HTML 解析:浏览器解析 HTML 以构建 DOM(文档对象模型)。
  • CSS 解析:下载并应用任何链接或嵌入的 CSS 样式表以设置 DOM 元素的样式。
  • JavaScript 执行:下载并执行 JavaScript。JavaScript 可能进一步修改 DOM 或发送额外的网络请求(如 AJAX)以动态更新页面。
  • 渲染:浏览器的渲染引擎将解析和样式化的内容绘制到屏幕上,形成可见的网页。

附加资源请求

当浏览器解析 HTML 时,它会识别出额外的资源(图片、样式表、JavaScript 文件)需要加载:

这些资源通过额外的 HTTP/HTTPS 请求获取。这个过程会通过多个并行连接重复进行,以 快速下载和渲染资源。

浏览器缓存与优化

浏览器会根据缓存头(如 Cache-Control、ETag)缓存某些资源(图片、脚本、样式表)。

现代浏览器使用诸如 HTTP/2 多路复用等优化技术,通过单个 TCP 连接下载多个资源,从而减少延迟。

最终页面显示

一旦所有资源下载、解析和渲染完成,用户可以与完全加载的页面进行交互。进一步的用户操作(点击、输入等)可能会触发更多的网络请求(如提交表单、AJAX 更新)。

加分点

  • CDN(内容分发网络):Google 使用 CDN 从地理位置较近的服务器提供内容,减少延迟并提高加载速度。
  • 安全功能:HSTS(HTTP 严格传输安全)确保所有请求都通过 HTTPS 进行。Google 的证书绑定技术确保服务器的 SSL 证书未被篡改。
  • Service Workers:如果启用,Service Worker 可能会拦截请求,提供缓存响应或启用离线功能。

这份详细的说明涵盖了从用户输入 URL 到浏览器最终渲染页面的所有关键步骤,涉及 DNS、TCP/IP、TLS、HTTP 和浏览器渲染等内容,适合系统设计或软件工程面试。

英文:Software Engineering Interview Question: What Happens When You Type Google.com in the Browser Address Bar?

面试经历

面试题

面试技巧

面试其它

本文一共 1423 个汉字, 你数一下对不对.
软件工程师经典面试题: 当你在浏览器的地址栏敲入google.com并按回车后发生了什么?. (AMP 移动加速版本)

扫描二维码,分享本文到微信朋友圈
75a5a60b9cac61e5c8c71a96e17f2d9c 软件工程师经典面试题: 当你在浏览器的地址栏敲入google.com并按回车后发生了什么? 学习笔记 程序员 计算机 资讯 软件工程 面试
The post 软件工程师经典面试题: 当你在浏览器的地址栏敲入google.com并按回车后发生了什么? first appeared on 小赖子的英国生活和资讯.

相关文章:

  1. 软件工程师面试: TCP/IP协议是什么? 最近,在面试第一轮抖音(字节跳动)的伦敦职位(Site Reliability Engineer),被问到了这个问题:TCP/IP协议是什么?这个是考基本功,是每个软件工程师都要会的。 TCP/IP(传输控制协议/互联网协议)是一组网络协议,管理数据如何通过互联网和其他网络传输。它是互联网的基本通信模型,由两个主要层组成: 互联网协议 (IP) IP 负责将数据包从源地址路由到目标地址。它工作在 OSI 模型的网络层。 IP 地址:互联网中的每个设备都被分配了一个唯一的 IP 地址,用于标识数据包的发送者和接收者。 数据包路由:IP...
  2. Meta的Enterprise Engineer企业工程师是什么? 和软件工程师的区别 我最近收到了一封来自 Meta 招聘人员的邀请邮件,关于 Meta 伦敦的员工企业工程师职位(Staff Enterprise Engineer): Meta 的企业工程师是什么? Meta 的企业工程师专注于设计、开发和维护内部工具和系统,以帮助公司员工提高生产力和效率。与传统的软件工程师角色相比,这一角色更偏向于内部,主要专注于为企业级需求构建基础设施、应用程序和自动化解决方案。以下是该职位的职责概述: 主要职责 内部工具和基础设施开发:企业工程师构建支持 Meta 内部业务运营的工具,例如...
  3. 测测你的幸运 – Linux Fortune-Teller LINUX 下有很好很好玩的命令,之前已经介绍过: figlet, rig, curl. 现在推荐另一个 命令 fortune 是用来随机显示一段(句)话的.fortune 在英文里就是幸运的意思. 这个命令可以不需要 参数 如果没有 可以通过 apt-get...
  4. 新的旅途 – 离别总是伤感的, 离开了一起创业的公司 2周前, 正式离开了一起创业的公司, 这公司是我博士毕业后的第一份正式工作, 待了8年多了, 离别总是伤感的. 我是9月初提的离职, 三个月 Notice Period, 最后的几周交接完工作确实没有什么压力了. 11月30号, 在公司最后一天, 公司有个习惯, 对于 Good...
  5. Minuet in C – 小步舞曲C Posted Youtube – 油管地址 孩子弹琴的时候最帅了. 我现在成了我儿子的粉丝了. Eric (Aged 6) is playing “Minuet in C” when...
  6. 上了年纪痛风脚崴了的惨痛经历(尿酸过高) 痛风是一种疼痛性关节炎, 当血液中的尿酸水平高, 导致晶体形成并积聚在关节内或关节周围, 就会发生痛风. 当人体分解一种叫做嘌呤的化学物质时, 就会产生尿酸. 嘌呤自然存在于您的身体中, 也存在于某些食物中. 尿酸通过尿液从体内排出. 上两周, 和媳妇吵架, 然后就自己一人睡, 有一天起床后脚踝就开始疼了, 然后明显比左脚肿了. 我刚开始就以为是睡觉的时候不小心姿势不对,...
  7. 优衣库 感觉像炒作 这几天 这个在北京三里屯 ‘优衣库’ 试衣间自拍的视频真的很火, 男女主角均被人肉. 不可否认 这个效果还真的不错 因为我之前根本不知道 “优衣库” 是干嘛的 很刺激 在试衣间XXOO是多么爽的事情 女主角 95后妹子 长相甜美....
  8. RMB人民币数字转大写汉字 – Javascript工具 Javascript工具RMB人民币数字转大写汉字 源码: https://justyy.com/js/atoc.js 最多只能计算15位, 小数点支持2位(毛和分). 最后一位分为0时, 需要加上’整’. 而且还需要在万亿,亿,万,元位等关键位0的位置写上’零’. 例如: 325.04 写成人民币 ‘叁佰贰拾伍元零肆分’ 人民币金额用到的中文大写汉字如下: 零~壹~贰~叁~肆~伍~陆~柒~捌~玖~拾~佰~仟~万~亿 壹佰贰拾壹万叁仟肆佰壹拾贰元整...

C++的 map 当键(Key)不存在的时候会发生什么?


面试流程(例如筛选)的早期阶段,一位 Google 招聘人员曾向我问过这个问题。

在C++中,当你使用std::map访问一个不存在的键时,行为取决于你是如何访问它的。

使用下标操作符 [] 访问时

如果键不存在,std::map 会默认插入一个该键的元素,并为其赋值为类型的默认值。比如,如果 map 的值类型是 int,那么它会插入该键并赋值为 0。

例子:

std::map<int, int> myMap;
int value = myMap[10]; // 如果键10不存在,会插入myMap[10] = 0

使用 at() 方法访问时

如果键不存在,at() 会抛出 std::out_of_range 异常。

例子:

std::map<int, int> myMap;
try {
    int value = myMap.at(10); // 如果键10不存在,会抛出异常
} catch (const std::out_of_range& e) {
    std::cout << "Key not found!" << std::endl;
}

使用 find() 方法

find() 方法不会修改 map,它返回一个迭代器。如果键不存在,它会返回 map.end()。

例子:

std::map<int, int> myMap;
auto it = myMap.find(10);
if (it == myMap.end()) {
    std::cout << "Key not found!" << std::endl;
} else {
    std::cout << "Value: " << it->second << std::endl;
}

C++ std::map 和 std::unordered_map的比较

std::unordered_map 处理不存在的键与 std::map 类似,但有一些差异,主要是因为它们内部的数据结构不同。

map 和 unordered_map 的区别:

  • 顺序:std::map 是有序的(内部实现为平衡树),所以元素会按键的顺序排列。而 std::unordered_map 是无序的,使用哈希表存储元素,因此没有特定的顺序。
  • 性能:std::unordered_map 通常有更快的平均访问时间(由于哈希结构,平均时间复杂度为 O(1)),而 std::map 的访问时间复杂度为 O(log n),因为其内部实现为树结构。然而,如果发生大量哈希冲突,unordered_map 在最坏情况下的时间复杂度可能是 O(n)。

总的来说,std::unordered_map 和 std::map 在处理不存在的键时,对于 []、at() 和 find() 的行为相似,但它们在顺序和性能方面存在差异。

总结

  • 使用 [] 访问时,如果键不存在,map 会插入一个新元素并赋予默认值。
  • 使用 at() 访问时,如果键不存在,会抛出异常。
  • 使用 find() 可以检查键是否存在,而不会修改 map。

英文:C++: Access a Non-existent Key in std::map or std::unordered_map

面试经历

面试题

面试技巧

面试其它

本文一共 473 个汉字, 你数一下对不对.
C++的 map 当键(Key)不存在的时候会发生什么?. (AMP 移动加速版本)

扫描二维码,分享本文到微信朋友圈
75a5a60b9cac61e5c8c71a96e17f2d9c C++的 map 当键(Key)不存在的时候会发生什么? ACM题解 学习笔记 小技巧 技术 数据结构与算法 程序设计 编程 资讯 软件工程
The post C++的 map 当键(Key)不存在的时候会发生什么? first appeared on 小赖子的英国生活和资讯.

相关文章:

  1. 步步高学生电脑上 Basic 编程语言 peek 用法示例 步步高学生电脑 是8位FC机的经典之作.它上面的BASIC有三个版本 1.0, 2.0 和 2.1 2.1 版本有个在线帮助,实际上是 help.cmd 1.0 是用 Esc 键退回到 DOS 的,...
  2. 你给SteemIt中文微信群拖后腿了么? 这年头不缺算法, 就缺数据. 这两天花了很多时间在整API上, 整完之后自己用了一下还觉得真是挺方便的. 今天就突然想看一看自己是否给大家拖后腿了, 于是调用每日中文区微信群排行榜单的API, 刷刷拿着 NodeJs 练手: 1 2 3 4 5 6...
  3. Javascript 中 sleep 函数实现 Javascript 中并没有 built-in 的 sleep 函数支持, 在 async/await/Promise 的支持之前, 我们可以用 busy-waiting 的方式来模拟: 1 2 3...
  4. 按揭贷款(房贷,车贷) 每月还贷计算器 去年给银行借了17万英镑 买了20万7500英镑的房子, 25年还清. 前2年是定率 Fix Rate 的合同 (年利率2.49%). 每个月大概是还 700多英镑. 有很多种还贷的计算方式, 定率/每月固定 是比较常用的. 简单来说就是 每个月交的钱是...
  5. 《Steem 指南》之 justyy 在线工具与 API 系列 – 同时给多个帐号发送SBD或者STEEM 同时给多个帐号发送SBD或者STEEM STEEMIT 和 BUSY 的前端都有一个内置的钱包工具, 您可以一次给一个帐号发送 SBD 或者 STEEM. 当我们要给很多很多人发送钱的时候, 就显得有些不方便了. 这时候可以用这个在线工具: https://steemyy.com/wallet-tool/ 填写表单 只需要填上你的ID,...
  6. 智能手机 HTC One M9 使用测评 虽然我对手机要求不高, 远远没有像追求VPS服务器一样, 但是怎么算来两年内换了四个手机, 先是三星 S4 用了一年多, 然后 Nokia Lumia 635 Windows Phone, 后来又是 BLU, 半年多前换了...
  7. 试用 Linkedin (领英) 高级帐号 (Premium) Linkedin (领英) 算是比较靠谱的职业社交网站, 在上面有很多猎头, 很多知名公司的HR 无时无刻在招人. 特别领英在被微软收购之后, 名气就变得大了许多. 领英是免费使用的, 但也有付费用户, 有给猎头的, 也有给想找工作的. 价格并不便宜, 对于想找工作的 Job...
  8. 最简单有效的过滤WordPress垃圾评论的方法 当你的Wordpress博客流量大的时候, 不免会收到很多垃圾评论. 本文介绍一种特别简单而且免费的过滤Wordpress垃圾评论的方法. 这种方法不需要你安装任何插件, 也不需要拥有修改Wordpress主题模板函数的能力, 只需要1分钟就可以搞定. 把这个列表拷贝下来 打开 WordPress 的控制面版, 到设置-讨论 拷贝上面的列表到 “评论审核” 或者 “评论黑名单”...

银弹飞过先锋大厦

作者 hutusi
2024年5月28日 21:37
TL;DR 本文13200+字,全文阅读约需20分钟。其中2680字的示例部分为ChatGPT生成,因此可以说本文GPT含量20%,不过该部分详细内容与本文主旨关系不大,且由GPT-4生成,可略过不看。本文简要回顾了从软件及计算机诞生到当前大模型AI时代的软件工程发展历史,并试图从软件工程历史和ChatGPT实践案例中探讨在大模型时代的软件开发模式。

Code Review 的方法

作者 tison
2022年11月6日 08:00

开源社群可以通过开展广泛的开源协同来规模化开发软件的生产力。为了实现提升生产力的目标,一般而言需要解决两个阶段的问题:第一个阶段是如何找到适合的潜在开发者人群,吸引他们参与软件开发和社群建设;第二个阶段是社群的原始生产力上来以后,应对项目复杂度和沟通成本随人员规模平方级别增长的难题。

第一阶段的解决方案在《共同创造价值》当中有过相关讨论,第二阶段的问题可以通过工作的模块化和 Review 质量的提升来解决。本文即聚焦在开源协同当中的 Code Review 应该秉承什么原则,做到什么程度,如何避免常见问题来展开。

Code Review 的目的

《大教堂与集市》中有一个著名的 Linus 定律,“只要眼睛多,bug 容易捉”。这从某种方面体现了 Code Review 的价值,即发现代码补丁和主干代码当中可能的缺陷,在合并之前或合并之后予以修复,以保证软件的质量。

不过,Code Review 的价值远不止于发现代码缺陷,它至少还有两个重要的功能:减缓软件代码的熵增和传播项目社群的知识。前者从评估改动的必要性,改动方式是否与项目风格保持一致,以及保证代码的测试覆盖和文档覆盖等为切入点;后者主要是在 Patch Author 和 Reviewer 的交流过程中,传递社群成员共识的技术判断和做事方式。

Code Review 的内容

可以从开源社群常见的 Code Review 内容看出各个社群对 Code Review 的定位。

合理的动机

Code Review 的第一步并不是扎到代码里面去看写得对不对跟好不好,而是项目要不要做这个改动。

实际上,相当部分的参与者提交补丁之后迟迟未能得到 Reviewer 反馈的重要原因,就是决口不提为什么要做相关的改动,假设这一改动是社群共识。尤其是公司环境中被委派的工作,完成后想要将对应改动合并到上游,问及缘由只说是甲方或老板的需求,而不能从技术上或者广泛社群用户的角度上论证其价值,往往不会被上游社群所接受。

试想当你看到一个等待 review 的补丁,其中包含成百上千行改动,或者虽然只改了几行几十行但是意义不明,你还会花时间去思考其背后的深意吗?对于 Reviewer 来说,从整个项目的工程效率来看,遇到这种情况要么是直接不看了,要么是让补丁作者说明清楚动机和改动内容。只有判断这个补丁可能是有价值的,Reviewer 才可能分配时间仔细看具体的代码改动。

从另一个角度看,对于影响用户界面的改动,重大代码重构和功能提案,开源社群几乎总是要求提议者在提交代码补丁之前先撰写一个技术提案。Rust 是 RFC 机制,Apache Flink 是 FLIP 机制,Python 是 PEP 机制,诸如此类。

只有提案通过 Review 达成了一致,实现提案的代码补丁才有被 Review 的意义。提案本身不是代码,而是对要做的事情的动机的阐述和方案高度概括的设计。可以看到,Code Review 不是从代码本身开始做起的,而是先判断动机是否合理。

各个开源社群的实践中,PostgreSQL: Reviewing a Patch 文档就有一个 Do we want that? 的问题评估必要性,TiDB 开发者指南里也提到了 The pull request should resolve a real problem for TiDB users. 即改动必须有意义。

符合描述的实现

对代码补丁的动机和整体修改方案达成一致后,Code Review 的下一个阶段也是其核心阶段,就是检验代码实现是否与此前达成的共识一致。

Reviewer 进行 Code Review 的真相是这样的:首先,Reviewer 认同补丁的意图是合理的,随后,Reviewer 会在心里有一个预期的实现,对比这个预期的实现和代码补丁的实现,通常会快速略过和预期相同的代码,针对和预期不符的改动给出 Review 意见。

典型的情况是补丁的改动遗漏了某些特殊条件的判断,在配置的某种排列组合不能正确工作,或者引入了新的问题。这些情况下 Reviewer 会指出问题,负责的 Reviewer 还会尽量给出复现方式、技术原理和可能的改动方案。

为此,Reviewer 需要拉取补丁到本地,结合开发工具分析新版本代码,实际运行测试,以及按照自己的设想做出改动后再测试,最终给出需要改动的 Review 意见。

关于代码补丁的修改与描述一致,Flink 的 Review 指南有一点提到:

Does the Implementation Follow the Agreed Upon Overall Approach/Architecture? In this step, we check if a contribution folllows the agreed upon approach from the previous discussion in Jira or the mailing lists.

TiDB 开发者指南也提到:

The pull request should implement what the author intends to do and fit well in the existing code base.

夸奖优质的贡献

在上面提到的这个比对预期实现和补丁实现的过程里,除了发现补丁实现的问题,为补丁查漏补缺,还有一种情况,是补丁作者提出了意料之外的好方案。

老到的 Reviewer 不吝惜称赞亮眼的改动,虽然新人 Reviewer 可能会误以为 Code Review 的主题就是给补丁挑错,但是其实吸纳高水平的补丁,点出补丁作者做得好的地方,对社群发展有重要意义。这不仅是社群共识和软件质量螺旋上升的必经之路,对于补丁作者而言,得到正面反馈也是非常重要的一份激励。

曾经有位 Hadoop 的参与者在提交完第一个补丁之后,由于实现简洁明了而得到 Reviewer 的热情称赞,他受到强烈的正反馈持续参与,最终成为 Hadoop PMC 成员,并在不同场合分享这段经历,也传承了这个理念将更多新人带到开源参与的正向循环里。

关于正向激励的部分,TiDB 开发者指南有这样一段描述:

Offer sincere praise. Good reviewers focus not only on what is wrong with the code but also on good practices in the code. As a reviewer, you are recommended to offer your encouragement and appreciation to the authors for their good practices in the code. In terms of mentoring, telling the authors what they did is right is even more valuable than telling them what they did is wrong.

Python 开发者指南也有简短的一句:

Comment on what is “good” about the pull request, not just the “bad”. Doing so will make it easier for the PR author to find the good in your comments.

统一的代码风格

Code Review 的一大作用是减缓软件代码的熵增。

随着软件版本不断迭代,开发者们不断实现新的功能,引入新的抽象,就地修复代码缺陷。这些改动重重叠加,会把代码的复杂度也就是熵抬高到任何一个开发者都无法单独理解的程度。

控制代码复杂度的重要手段就是保持统一的代码风格。统一的代码风格能减少开发者入门的学习成本,跨越不同模块的理解成本,以及相互之间交流的沟通成本。

统一的代码风格,首要的一点就是功能实现的风格。

例如,几乎所有大型项目都会遇到不稳定测试的考验。这种不稳定性来到分布式系统领域,则主要是并发问题处理不当,尤其是没有统一的并发风格所导致的。

Apache Flink 的 Task Executor 进程在引入 Mailbox 设计重构之前,进程内的线程逻辑是犬牙交错的。开发者很难判断某个函数会在什么线程上下文当中被调用,也就不知道如何正确的在代码补丁中引用其他接口而不导致死锁。Apache Pulsar 的并发风格更是八仙过海各显神通,而开发者也最终要为这份代码熵付出巨大精力事后熵减的代价

反观开发超过 15 年的 Apache ZooKeeper 虽然并发工具的使用涵盖了直接使用 Thread 到 Executor 框架再到 CompletableFuture 组合子,但是核心的服务端处理逻辑和客户端通信逻辑的并发模型一直保持了连贯的风格,其他的并发工具使用范围都是局部的,这才造就了十余年来挑战者众多但是 ZooKeeper 一直保持分布式共识系统重要选型考虑的地位。另一个例子,Apache SkyWalking 的线程模型是核心模块统一设计、控制和调度的,其他模块通过接口提交任务,而核心模块调度保证这些任务不会出现竞争条件。这样,Code Review 的时候只要关注核心模块的线程变动,同时限制其他模块自建并发模型的范围,就可以很好地规避并发问题。

统一的代码风格,还包括语言范式和特性一致的的取舍。

典型的多范式编程语言,例如 C++ 和 Scala 都需要项目的核心开发者确定语言支持的各个范式和覆盖相同功能的不同特性之间的取舍。否则,一个 Scala 项目里部分代码对外暴露命令式调用方法,另一部分采用函数式编程提供一系列功能函数和组合子,在两个模块的交界处的代码就很容易产生不必要的胶水代码和引入难以分析的缺陷。同样,一个 C++ 项目既有 C 风格的函数尤其是对字符串和指针的用例,又有叠床架屋的模板代码设计出来的高度抽象的功能模块,这对跨越这两部分代码调试问题的开发者,就会引入极高的学习成本和理解成本。

哪怕是特性相对正交,几乎只有一条路实现特定功能的语言来说,这个问题也是存在的。例如,业内评价为暴力美学 Golang 即使代码写的差,也都是整整齐齐的“垃圾”。尽管如此,它还是面临错误处理风格没有语言级别约束的问题。前者虽然大部分 Golang 代码都是通过多返回值同时返回可空的错误和可空的结果来实现的,但是在 TiDB 代码里也有把 error 指针当成传出参数放到函数参数列表的 C 风格代码。类似问题放到 Java 代码里,虽然 Java 宣扬面向对象编程的范式,几乎凡事都可以通过抽象接口、不同实现,调用方只要调接口就行来建模,但是面向对象的几十个设计模式之间的取舍,也是风格不一致的诱发因素。

这是因为,无论语言是怎么设计的,不同的范式是客观存在的。对于熟悉 C 风格代码的开发者来说,他会在编写所有语言代码的时候都复用 C 风格代码的知识,在新的环境下找到熟悉的开发体验。这是难以避免的。对于 Code Review 来说,至少要保持模块内风格一致,模块间调用约定清晰,关系密切或说紧密耦合的模块采用相同的风格,而对于模块内部的实现,则不用锱铢必较。

统一的代码风格,最后是相同的代码格式和惯例。

例如,模块代入的是否有序、什么顺序,注释的风格,空格的风格,换行的风格。新生代的语言大多自带代码格式化工具,例如 Rust 的 rustfmt 和 Golang 的 gofmt 等,甚至 Golang 将某些传统代码格式的偏好固定成编译器检察项,例如 if 后左花括号换行就报错。对于早前的编程语言,包括 C 和 Java 等等,也都有业内共识度较高的工具,对应的是 clang-formatcheckstylespotless 等。

对于开源社群的协同开发而言,重要的不是选择什么风格,而是有一个确定的风格。当然,由于代码风格不适应严重的甚至会导致生理不适,一般而言所选的风格至少是核心开发者的共识。有了确定的风格,再将代码格式化作为提交前的必要检察项,这样就能减少由于不同人偏好的代码风格不同,导致提交上来的代码补丁总是包含形成干扰的格式变更带来的 Review 负担,以及格式化过程中难以控制的重构冲动导致引入新的缺陷。

最后这点,在 TiDB 开发者指南中强调为代码补丁需要专注于一件事:

Concentration. One pull request should only do one thing. No matter how small it is, the change does exactly one thing and gets it right. Don’t mix other changes into it.

显然,实现功能同时格式化代码,这就是两件事。

TiDB 开发者指南对代码风格还有另一段独立的说明:

Style. Code in the pull request should follow common programming style. For Go and Rust, there are built-in tools with the compiler toolchain. However, sometimes the existing code is inconsistent with the style guide, you should maintain consistency with the existing code or file a new issue to fix the existing code style first.

Flink 的代码风格指南则包括了上面提到的所有三个方面。

关键路径的性能因素

在知道算法的情况下,人是能像机器一样解决特定问题的,甚至依靠人的直觉和并行思考能力人的解决方案会更具现实意义。程序相较于人的突出优势,就在于处理重复的工作,尤其是不会出错的重复处理底层逻辑,并且这种处理速度远远超出人的极限。因此,程序的性能几乎是每个开发者心中的圣杯,每每会被提出来考量。

不过,Code Review 当中关注性能的部分,主要是关键路径上的性能因素。所谓关键路径,就是从输入到输出经过的延时最长的逻辑路径。

对于业务代码和实用工具来说,只要代码核心流程各个步骤不要出现时间复杂度的回退,尤其是不要出现与输入成指数级别时间复杂度的代码,基本上不会有太大的性能问题。

对于基础软件来说,处理的对象大多是更加底层的概念,例如单条数据记录或单个字节。在这些环节上就算出现常数级别的重复,在输入数据量的放大下,最终的时间和空间开销都有可能有显著的回退。例如许多 Java 网络系统都会做缓冲区零拷贝优化,就是避免语言运行时默认将网络传输过来的字节从网卡拷贝到用户空间再拷贝到 Java 堆上。从复杂度的大 O 记法来看,这只是常数级别的差异,但是在网络数据量级的放大下,这就是整个系统性能显著的回退了。

关于性能的 Code Review 工作,分析时间和空间占用的时候,不仅要看大 O 记法下的量级,还要考虑实际参数的取值范围和常数,两者综合的结果才是生产环境的实际性能表现。而在分析性能之前,要先判断相关代码改动是否是性能敏感的路径,或者补丁作者声称做出改动是为了改善性能。一个衡量性能优化的常用手段是提供基准测试(Benchmark)结果,这可以类比功能型修复对应的防止回退的测试。

各个开源社群的实践中,类似 TiDB 和 PostgreSQL 等以性能取胜的数据处理系统往往都会在 Code Review 指南中着重点出考虑性能方面的问题。而对于其他性能并非主要特性的项目,这类共识则一般隐含在 Reviewer 的共享知识当中,或者对于特定的几个关键路径会有注释或文档说明需要特别关注性能问题。

测试和文档

最后一个 Code Review 常见的内容是测试和文档。

虽然最后才提及测试和文档,但是它们在实现时却很可能在功能代码之前。上面提到的动机描述和设计文档,就可以算作是文档的一部分;而测试驱动开发的模式,测试是先于功能代码编写,随后实现功能或修复缺陷以通过测试。

测试和文档单独讨论都是一个内涵丰富的主题,在 Code Review 的语境下一并提出,是因为测试和文档的角度都是功能代码的用户。文档主要说明了代码实现了什么功能,调用约定和返回值内容都是什么,进一步的文档会提供代码使用的样例。测试则是功能代码的第一个消费者,Reviewer 和其他阅读源码的开发者都应该掌握阅读测试来理解一个功能模块或者整个系统的意图的能力。

TiDB 开发者指南提到 Code Review 中需要关注测试和文档的以下方面:

Tests. A pull request should be test covered, whether the tests are unit tests, integration tests, or end-to-end tests. Tests should be sufficient, correct and don’t slow down the CI pipeline largely.

Documentation. If a pull request changes how users build, test, interact with, or release code, you must check whether it also updates the related documentation such as READMEs and any generated reference docs. Similarly, if a pull request deletes or deprecates code, you must check whether or not the corresponding documentation should also be deleted.

值得一提的是,测试和文档并不是必要的,也不是越多越好。好的代码是明显没有错误的自解释的代码。只是把一眼看到函数名称,返回值和参数的类型和名称就能明白的内容写成文档其实是冗余的;测试显然正确的代码例如 Getter/Setter 也没有什么意义。

测试应该只检验模块的契约,也就是在不同类别的输入参数下,返回值和副作用是否符合预期。一个常见的测试误区是测试不属于当前模块的代码,尤其是测试外部依赖的逻辑。依赖模块的逻辑应该自己保证正确,下游只会在测试自身逻辑是发现上游不可靠,从而替换成新的实现或者向上游提交补丁,拉取新的版本。

Code Review 的暗礁

虽然大部分开源社群只有小部分成员才有向主干提交代码的权限,但是大部分开源社群都是鼓励所有社群成员参与 Code Review 的。从新人 Reviewer 成长为老到的 Reviewer 的过程中,有一些常见的 Review 技能以外的认识误区。本节从 Review 的几个常被忽略的真相出发,讨论如何规避 Code Review 的暗礁

Code Review 是一个交流的过程

Code Review 虽然有流程,但却不是无需人类活动参与的程序。软件工程没有银弹,同样也没有尽善尽美的代码补丁。程序设计几乎就是关于权衡(trade-off)的艺术,而 Code Review 就是 Patch Author 和 Reviewer 之间关于如何权衡的讨论。

不过,这种讨论又不是完全开放式的讨论。技术交流有一些行业或领域内的共识,正确性、性能报告和成规模的用户反馈实相对客观的。因此,Code Review 是一个技术事实和数据胜过主观感受和偏好的讨论过程。尽管 Reviewer 可能认为某个改动非常“脏”,但是在必要的性能权衡下,或者立即解决正确性问题的权衡下,没有更好的解法,也不应该出于个人主观判断否决提案。这是绝大多数社群都会要求的,给出 -1 的同时必须附带理由,否则 -1 无效。

此外,Code Review 的讨论是务实准确的。TiDB 开发者指南特别强调了这一点:

Asking questions instead of making statements. The wording of the review comments is very important. To provide review comments that are constructive rather than critical, you can try asking questions rather than making statements.

Provide additional details and context of your review process. Instead of simply “approving” the pull request. If your test the pull request, report the result and your test environment details. If you request changes, try to suggest how.

Python 开发者指南也提到,如果你在 Code Review 中检查了补丁确实具备什么功能,那么在 Approve 的时候也请带上相关信息,如果发现了问题,也尽量说明复现方式和环境。

其实这些原则贯穿开源社群的所有交流场景。把发现问题报告问题的原则放到已经合并的代码上,就成了 Issue Report 的原则;而把 Approve 的时候说明检查了什么内容,就变成了 Release Verification 的一个重要步骤。

最后,Code Review 通过交流传递知识。无论是补丁作者还是 Reviewer 提供了好的代码实例,还是交流过程中学习到了其他人分享的知识,都不要吝惜称赞。这种正反馈循环是开源协同长期运转的重要支柱。

开源社群的 Reviewer 都是志愿者

当然,Reviewer 有可能是因为受雇于某家公司才参与社群帮助 Review 的。但是这不妨碍从社群视角来看,开源社群的 Reviewer 都是志愿者。毕竟,如果你跟某个特定的 Reviewer 不在同一家公司,他对你而言是不是一个十足的志愿者呢?

Python 开发者指南中关于 Reviewing 的第一段话就是:

To begin with, please be patient! There are many more people submitting pull requests than there are people capable of reviewing your pull request. Getting your pull request reviewed requires a reviewer to have the spare time and motivation to look at your pull request (we cannot force anyone to review pull requests and no one is employed to look at pull requests).

所以,开源协同当中的 Code Review 以天或周为单位沟通合并是常有的事。为了提高自己在开源社群当中的效率,你不能死等在一个 Code Review 的反馈上,而应该尝试同时进行多个工作,哪一个给出反馈就调度上来再给一个回复。也就是说,开发者在开源协同当中像是一个并发的处理器。

从 Reviewer 的角度来看,你不是社群的雇员,更不是社群的奴隶。为了保持长久的参与热情和个人精神健康,认识到你是社群当中的一个志愿者至关重要:你不欠社群什么,社群也不欠你什么。当然,为了社群茁壮成长,掌握上面所有 Code Review 的方法,高效的完成 Code Review 也是社群生产力规模化的核心源动力。

Approve 意味着同意合并代码补丁

对于一个增长的社群来说,Code Review 是严格把关代码质量的一个重要环节。同时,通过 Code Review 向社群新成员传递的正确理念,将会极大提升他们后续参与的积极性和质量。

然而,如果 Code Review 标准太低,甚至出现为了某些 KPI 而选择先合并低质量代码再修复的策略,不仅损害了当下的代码质量,也会传递出一种类似破窗效应的信号,让其他社群成员误以为这个社群对待软件生产的标准就到这了。

Rust 标准库的开发者文档一开始就强调了 Approve 的意义和严肃性:

You are always welcome to review any PR, regardless of who it is assigned to. However, do not approve PRs unless:

  • You are confident that nobody else wants to review it first. If you think someone else on the team would be a better person to review it, feel free to reassign it to them.
  • You are confident in that part of the code.
  • You are confident it will not cause any breakage or regress performance.
  • It does not change the public API, including any stable promises we make in documentation, unless there’s a finished FCP for the change.

这其中,由于 Maintainer 有提交代码到主干的权限,他们的 Approve 会更加关键。实际上,这是一个选择 Maintainer 的标准。以 Apache 的权限模型为例:

For the committer bar, I always think of whether the candidate is easy to work with - make decisions with caution while bravely, knowing when to ask for help.

For too many new committers, it hurts when their contributions always need revision, especially trivial mistakes. If we elect a new committer while his/her contribution needs more attention to avoid merging wrongly quickly, we lose the reason to invite the very person.

Apache doesn’t set up fine-grained permissions so it’s extremely important not to approve something you’re unsure with.

当然,随着项目固有复杂性的增长,很可能任何单独一个 Reviewer 都不敢确定是否应该合并一个相对复杂的补丁。

面对这种情况,如果补丁是由多个连续的步骤,或者相互独立的几个部分组成的,可以让补丁作者拆分成多个提交。

如果确实不好拆分,则可以由多名 Reviewer 各自 Review 一部分,然后由经验丰富的一位整合 Review 意见。Flink 的 Review 指南的第三点提到:

Does the Contribution Need Attention from some Specific Committers and Is There Time Commitment from These Committers? Some changes require attention and approval from specific committers. For example, changes in parts that are either very performance sensitive, or have a critical impact on distributed coordination and fault tolerance need input by a committer that is deeply familiar with the component.

侧面来看,这也强调了 Approve 的时候带上自己检验过的内容,明确自己 Approve 的是哪一部分的意义。

❌
❌