ARTS第一周

Algorithm

使用链表判断字符串是不是回文字符串

//1 快慢指针定位中间节点
//2 从中间节点对后半部分逆序
//3 前后半部分比较,判断是否为回文
//4 后半部分逆序复原
//时间复杂度O(n), 空间复杂度O(1)
class Solution {
  public isPalindrome(head) {
    if (head == null || head.next == null) {
      return true;
    }

    prev = null;
    slow = head;
    fast = head;

    while (fast != null && fast.next != null) {
      fast = fast.next.next;
      ListNode next = slow.next;
      slow.next = prev;
      prev = slow;
      slow = next;
    }

    if (fast != null) {
      slow = slow.next;
    }

    while (slow != null) {
      if (slow.val != prev.val) {
        return false;
      }
      slow = slow.next;
      prev = prev.next;
    }

    return true;
  }
}

review

(感觉这个文章选错了)
原文:https://medium.com/javascript-scene/tdd-changed-my-life-5af0ce099f80

review翻译

为什么是TDD(测试驱动开发,)

为了解决什么问题哦,已经有一段时间了,不是为了让开发人员不在犯错,是因为那么多年来,不管是我领导 的团队还是担任开发的团队,都使用TDD,当然,bug还是会有,但是在线上阶段,bug的产生率已经接近为0了,不过,因此,软件系统的升级和维护工作从使用TDD过后,就变得非常难。

无论什么时候有人问我为什么要使用TDD的时候,我都会想起这个故事,使用TDD最主要的原因就是提高了测试覆盖率,让线上错误减少了40%-80%,这也是它最大的好处之一。就像举重的时候,直接从肩膀上举一样。

在我们的项目中,自动化测试和单元测试,可以阻止几乎每天都在正在发生的重大事故变化,比如,我现在正在看的过去一周的10次自动库版本升级,我原来对每次合并都非常担心,万一它改动了什么东西呢?

现在这些升级都是自动化的了,并且已经投入生产,我不回查看他们当中任何一个,我也不会担心他们,打开github,查看最近的合并,他们都在那,曾静需要手动维护的,现在都是自动化流程,你也可以不要良好的自动化测试覆盖率,但是不推荐你这样。

什么是TDD

TDD就是测试驱动开发(UTDD单元测试驱动开发,ATDD验收驱动开发),(这里可以延伸出很多有趣的东西,领域驱动模型,测试驱动模型,业务驱动模型,)

img

1.在我们实现代码之前,先要编写单元测试来证明这个实现代码是有效的还是失败的,在进入下一步之前,观察测试是否失败,(这样我可以知道通过测试是真的还是假的,还有我们如何测试我们的测试 。)

2.编写实现代码,看测试通过不

3.如果需要重构代码的时候,也不用担心了,有一个完整的测试用例会告诉你,你重构的代码有没有破环原来的东西,你应该有信息重构代码。

在我们开发的时候,如何使用TDD?

虽然说,表面上,编写这些测试用例,我们写很多额外的代码,这些额外的代码都额外的时间,但其实这是非常有用的,因为这个过程我们需要努力的思考如何编写测试代码,并且努力思考如何将这些测试代码编写到我们已经写好的逻辑中。

TDD是有一个多出的学习曲线的,当你开始挑战这个曲线的时候,要比你平常多出15%-35%的时间,但是你坚持2年后,你会发现,可以利用单元测试更快的编写实现代码了,而不是不要它们。

几年前,我在视图中创建了一个视频剪辑范围功能,这个功能大概是,你可以设置一个视频的起点和终点,当用户链接到这个视频后,会匹配到剪辑的视频,而不是整个视频。

但是没起作用,用户在播放到剪辑末尾的时候 ,会继续播放,不知道为什么?

我一直以为是与事件监听器有关,我的代码是这样的:

video.addEventListener('timeupdate', () => {
  if (video.currentTime >= clip.stopTime) {
    video.pause();
  }
});

更改,编译,刷新,点击,等待,重复

每次更改都要花费差不多一分钟的时间来进行测试,我尝试了很多的方法,

我拼错了timeupdate嘛?还是我api用的不对?video.pause()是否有效,我做了一个更改,添加了一个console.log,回到浏览器,开始测试,等待剪辑视频到结束点,然后在根本就没有进入if,这也是一个线索,我复制了api确保没有拼错,然后重复步骤,还是不行。

然后我把console.log放到if外面,我想这也不能生效,毕竟这个if那么简单,我不会弄错,结果打印了,WTF?

然后我加了一个断点,来看到底发生了什么,我检查了clip.stoptime的值,undefined?我又重新检查我的代码,当用户点击暂停的时候,会停止视频,但是不会设置stopTIme,哦买噶,我真是一个白痴?

多年以后,我还是忘不了这种白痴的感觉,你应该能理解我,毕竟我们都这样过,所以,如果是今天,我要写那段逻辑,我会这样写

describe('clipReducer/setClipStopTime', async assert => {
  const stopTime = 5;
  const clipState = {
    startTime: 2,
    stopTime: Infinity
  };
  assert({
    given: 'clip stop time',
    should: 'set clip stop time in state',
    actual: clipReducer(clipState, setClipStopTime(stopTime)),
    expected: { ...clipState, stopTime }
  });
});

从表面上看,这看起来比clip.stopTime = video.currentTime的代码量要多很多,但这就是重点,这个代码的作用类似于规范,文档,以及代码按记录的方式工作的证据。主要因为它的存在,当我在进行光标定位改变停止时间的时候,我不必担心我是否在这个过程中是否会破坏剪辑停止时间的代码,所以关键不在于写这个代码需要多长的时间,关键在于出现了问题之后,需要多长的时间在调试它,如果这部分代码出现问题,这个测试会给我一个很棒的报告,我马上就知道是什么问题了,我知道它在clipReducer,setClipStopTime中做了什么,实际输出,和期望输出,更重要的事,未来6个月,我的同事也会在实现代码中添加功能,我也不必担心。

我在每个项目做的第一件事就是设置一个监听脚本,在每次文件更改的时候,自动运行我的单元测试,我经常有两个显示器,,一个显示器显示在开发控制台监听脚本的结果,另一个用来编码,当我改变代码的时候,我会立刻知道这次改变是否正确。

对于我来说,TDD不仅仅是一个安全网,它也是持续,快速,实时的反馈,当我做对了,就反馈正确,错了,就马上报告错误。

TDD告诉我们如何编写更好的代码

我要承认一个尴尬的事情,在我通过单元测试学习TDD之前,我并不知道如何构建一个应用,我是怎么被聘用的,我都不知道,但是在我接触了大量的程序员之后,我可以非常自信的告诉你,大多数程序员都是这样的。TDD教会了我几乎所有关于解耦,软件的组件开发,组合,模块,函数,对象,UI的知识。

原因是因为单元测试迫使我单独测试组件的IO,给定一些输入,产生一些输出,如果没有,则测试失败,否则,通过,关键是它应该独立于应用程序的其他部分。如果正在测试状态逻辑,那么你应该能够在不向屏幕传达任何内容的情况下测试,如果你正在测试UI,则应该能够不在浏览器加载页面或者访问的情况进行测试。

TDD告诉我,当你尽可能的减少UI组件时,生活会很美好,从UI隔离业务逻辑,实际上,这意味着,如果你使用基于组件的UI框架,vue,react,那么创建显示组件和容器组件并将它们分开,是非常重要的。(这就是我们说的木偶组件,和智能组件,或者受控组件,非受控组件,状态组件和无状态组件。都一个意思),

对于显示组件,给定一些props,始终显示相同的状态,这些组件可以很容易的进行测试,以确保props是正确的,并且UI布局中的任何条件逻辑都能正常工作,例如,如果列表为空,可能根本不应该呈现列表组件,并且应该在一些表示空的东西显示在列表组件。

在我学习TDD之前很久就知道了关注点的分离,但我不知道如何区分的问题

单元测试告诉我如何使用模拟测试事物,然后它告诉我模拟是一种代码嗅觉,很让我吃惊,完全改变了我处理软件组合的方式。

所有的软件开发都是组合,将大问题分解成许多的小问题,易于解决,然后组合这些问题的解决方案以形成应用程序的过程。为了进行单元测试而进行模拟表明你的原子单位组成并不是真正的原子,并且在不牺牲测试覆盖率的情况下学习如何根除模拟教会了我如何发现无数紧密耦合的来源。

这让我成为了一个更好的开发人员,并教会我如何编写更好的代码,这些代码在复杂性和云基础架构等大型分布式系统中更容易扩展,维护。

TIP

JavaScript提案中一些新特性

1.?运算符

//由于JavaScript的弱类型,比如我们有个对象obj,接受服务端返回的数据,、
// 然后在使用过程中,obj.a.b,如果服务端这个时候,返回是空,或者出错了,,就会导致前端出错,而我们前端出错,可能直接就白屏了,通常我们会这样
// obj && obj.a && obj.a.b
// 不是很美观,新特性可以这样
// obj.a?obj.a.b

2.空值合并运算符,??

console.log(undefined ?? 'abc');abc
console.log(null ?? 'abc');abc
console.log(void 0 ?? 'abc');abc
// 如果是空值,可返回后面的,这里最主要的用处就是,??不会为0,false,''这些工作,

3管道运算符,函数式编程中,compose的时候,我们需要连续调用多个函数,并且把上一个函数的返回值作为下一个函数的参数,

// a(b(c(d('abcd'))))
// 新特性
// abcd |> d |> c |> b |> a

SHARE

chrome调试和修改远程代码

大多数人都知道如何小瓷瓶啊之类代理软件将远程请求代理到本地,当然nginx也能做,其实chrome也能。

在这里插入图片描述

在source下面,选择overrides然后启用,就会让你选择本地文件,

接下来就可以随意修改sources中的文件,然后保存,就会在我们所选中的文件夹中,保存我们修改的版本,并且会使用本地版本。

在这里插入图片描述

比如这里,加了个输出,看看react.createElement的情况,

在这里插入图片描述

结果执行了30000次,创建了30000多个dom节点,平时写代码,还是主要结构简洁啊,结构越复杂,从解析道创建,渲染,都是性能消耗

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值