`

Hackable Projects (可拓展的项目)

阅读更多

试着翻译一些英文Blog,这是小试鸡刀第一篇,是Google Testing Blog发布的关于Hackable Projects的。感觉翻译得有点怪,其中有些错误与不解,希望有同学指正。

 

Hackable Projects(点击访问原文)

可拓展的项目

 

Introduction

 简介

Software development is difficult. Projects often evolve over several years, under changing requirements and shifting market conditions, impacting developer tools and infrastructure. Technical debt, slow build systems, poor debuggability, and increasing numbers of dependencies can weigh down a project The developers get weary, and cobwebs accumulate in dusty corners of the code base.

软件开发不容易。不断变化的需求、市场定位的变更、开发者工具与基础架构变化的冲击,在这些摧残下,一些项目经常会持续好几年。而技术债务、构建缓慢的系统、缺乏调试性、还有不断增长的依赖,也都可以拖垮一个项目。开发者们变得很疲惫,代码库中布满灰尘的各个角落也长满了蜘蛛网。

 

 Fighting these issues can be taxing and feel like a quixotic undertaking, but don’t worry — the Google Testing Blog is riding to the rescue! This is the first article of a series on “hackability” that identifies some of the issues that hinder software projects and outlines what Google SETIs usually do about them.

要解决这些问题,看起来会困难重重,且就如唐吉坷德一般不切实际,但是别担心--Google Testing博客正在拍马赶到,将解救万民于水火!这篇文章是“hackability(可拓展性)”三部曲的第一篇,三部曲主要讲解一些阻碍软件项目的问题,并且概括Google SETIs是如何对付它们的。

 

 According to Wiktionary, hackable is defined as: 根据维基词典,hackable的定义如下:

Adjective 形容词
hackable ‎(comparative more hackable, superlative most hackable) hackable(比较级 more hackable,最高级 most hackable)
  1. (computing) That can be hacked or broken into; insecure, vulnerable.  (计算系统)可以被黑或被侵入的;不安全的,容易受攻击的。
  2. That lends itself to hacking (technical tinkering and modification); moddable. 适合于砍掉的(可拓展的,易于修改、可编程的);可模式化的。
 

Obviously, we’re not going to talk about making your product more vulnerable (by, say, rolling your own crypto or something equally unwise); instead, we will focus on the second definition, which essentially means “something that is easy to work on.” This has become the mainfocus for SETIs at Google as the role has evolved over the years.

很显然,我们不是要讨论怎样让你的产品更加容易受到攻击(比如说滚动显示你的密码,或者一些同样愚蠢的行为);相反,我们是要集中于第二个定义,其意味着那些容易起作用的事情。这句不会翻译这成了SETIs,经历了几年的角色演变后,在Google的主要关注点。 

 

In Practice

实践

In a hackable project, it’s easy to try things and hard to break things. Hackability means fast feedback cycles that offer useful information to the developer.

一个可拓展的项目,是易于尝试而难于破坏的。拓展性意味着快速反馈周期,将有用的信息反馈给开发人员。


This is hackability:  可拓展性:
   Developing is easy 易于开发
   Fast build 快速构建
   Good, fast tests 快速有效的测试
   Clean code 干净整洁的代码
   Easy running + debugging 易于执行+调试
   One-click rollbacks  一键回滚
 
In contrast, what is not hackability? 相反,什么是非拓展性?
   Broken HEAD (tip-of-tree) 坏掉的顶端(树的尖端)(不懂怎么理解、翻译)
   Slow presubmit (i.e. checks running before submit缓慢的预提交(也就是在提交代码之前检查软件运行)
   Builds take hours 花费长时间才能构建完毕
   Incremental build/link > 30s 增量的构建/连接>30秒
   Flakytests 脆弱的测试
   Can’t attach debugger 脱离了调试器(不能进行debug)
   Logs full of uninteresting information  充满了无用的日志信息

 

The Three Pillars of Hackability

支撑可拓展性的三根柱子

There are a number of tools and practices that foster hackability. When everything is in place, it feels great to work on the product. Basically no time is spent on figuring out why things are broken, and all time is spent on what matters, which is understanding and working with the code. I believe there are three main pillars that support hackability. If one of them is absent, hackability will suffer. They are: 

有很多工具和实践,可培育出可拓展性。当一切都各就其位时,产品看起来棒极了。基本上,我们很少会花时间去研究为什么事情会变糟,而只会花时间去考虑事件最终的影响,这可以理解,在写代码上也是这样的。我相信有三根柱子支撑着可拓展性。如果缺少了其中一根,可拓展性将垮塌。他们是:

Pillar 1: Code Health

支柱1:代码的健康

“I found Rome a city of bricks, and left it a city of marble.” 朕接下之罗马,砖城耳,朕留下之罗马,大理石城也。
   -- Augustus 奥古斯都

Keeping the code in good shape is critical for hackability. It’s a lot harder to tinker and modify something if you don’t understand what it does (or if it’s full of hidden traps, for that matter).

保持代码的整洁是可拓展性的关键。让你去修改一个你不了解的事物(或者它是一个充满各种坑的东西)是非常困难的。

  

Tests

测试

Unit and small integration tests are probably the best things you can do for hackability. They’re a support you can lean on while making your changes, and they contain lots of good information on what the code does. It isn’t hackability to boot a slow UI and click buttons on every iteration to verify your change worked - it is hackability to run a sub-second set of unit tests! In contrast, end-to-end (E2E) tests generally help hackability much less (and can evenbe a hindrance if they, or the product, are in sufficiently bad shape).

单元测试和小部分集成测试大概是你能做到的,对可拓展性最有利的事情了。当你要改动你的项目(代码)时,它们是你可以依赖的保证,而且它们包含了大量有效的信息,帮助你了解代码的含义。每次软件迭代中,若都需要启动一个加载缓慢的UI,然后点击各个按钮来验证正确性,这不是可拓展性的做法。可拓展性是这么做的:执行一系列毫秒级的单元测试!相反,端对端测试通常对于可编程性没啥益处(若它们被设计得很搓,甚至还能成为阻碍)。

Figure 1: the Testing Pyramid.
图1:测试金字塔(Unit:单元测试;Integration:集成测试;E2E:端对端测试)

I’ve always been interested in how you actually make unit tests happen in a team. It’s about education. Writing a product such that it has good unit tests is actually a hard problem. It requires knowledge of dependency injection, testing/mocking frameworks, language idioms and refactoring. The difficulty varies by language as well. Writing unit tests in Go or Java is quite easy and natural, whereas in C++ it can be very difficult (and it isn’t exactly ingrained in C++ culture to write unit tests).

我一直对怎么在团队中推广单元测试保持浓烈的兴趣。这在于教育(培养)。编写一个包含良好单元测试的软件产品,实际上是个难题。这需要开发人员了解依赖注入、测试/测试替代框架、编程语言惯用法和代码重构的相关知识。不同的语言,问题各不相同,带来的困难也不同。在Go或Java语言中编单元测试挺自然、简单,但是在C++会变得很困难(而且在C++文化中也没有编写单元测试的习惯)。

 

It’s important to educate your developers about unit tests. Sometimes, it is appropriate to lead by example and help review unit tests as well. You can have a large impact on a project by establishing a pattern of unit testing early. If tons of code gets written without unit tests, it will be much harder to add unit tests later.

对开发人员进行单元测试的培训是很重要的工作。有时候,以身作则、帮助他人复查单元测试代码,都是合适的做法。在项目早期应建立起单元测试模块,这对项目有非常重大的影响。如果已经写好了成千上万的代码却没有写单元测试,而后期再想要补上,将会更加困难。

 

What if you already have tons of poorly tested legacy code? The answer is refactoring and adding tests as you go. It’s hard work, but each line you add a test for is one more line that is easier to hack on.

如果你已经拥有一堆无单元测试的历史遗留代码,该怎么办? 答案是,重构并补上单元测试。这是项困难的工作,但每多一行被单元测试覆盖的代码,都意味你的代码离可拓展性更近了一步。

 

Readable Code and Code Review

易读的代码和代码审查

At Google, “readability” is a special committer status that is granted per language (C++, Go, Java and so on). It means that a person not only knows the language and its culture and idioms well, but also can write clean, well tested and well structured code. Readability literally means that you’re a guardian of Google’s code base and should push back on hacky and ugly code. The use of a style guide enforces consistency, andcode review (where at least one person with readability must approve) ensures the code upholds high quality. Engineers must take care to not depend too much on “review buddies” here but really make sure to pull in the person that can give the best feedback.

在Google, “readability(易读性)”是一个特殊的头衔,它是由各个语言(C++、Go、Java等)授予给(代码)提交者的。它代表了一个人不仅了解某个语言及其文化和惯用法,而且还能写出干净整洁、优于测试和结构优良的代码。照字面上看,拥有易读性头衔意味着你是一位Google代码库的守护者,你应该阻挡那些无拓展性、丑陋的代码进入代码库。 强制地统一代码风格,并且进行代码审查(必须至少有一位易读者审核通过),可以保证代码的高质量。工程师们不应该去过多地“关心 (拉拢)”代码审核者,而应该多跟那些可以给出最好最有意义的反馈的人混。



Requiring code reviews naturally results in small changes, as reviewers often get grumpy if you dump huge changelists in their lap (at least if reviewers are somewhat fast to respond, which they should be). This is a good thing, since small changes are less risky and are easy to roll back. Furthermore, code review is good for knowledge sharing. You can also do pair programming if your team prefers that (a pair-programmed change is considered reviewed and can be submitted when both engineers are happy). There are multiple open-source review tools out there, such asGerrit.

自然,代码审查机制会引发一些微小的变化,如果你把大量的列表丢给审查者去审查,通常会让他们变得脾气暴躁。(至少当审查者需且必须尽快给出结果时,就会这样)这是好事,微小的变化说明风险小,易于回滚。此外,代码审查也有利于分享知识。你还可以结伴编程,只要你们团队喜欢这么做。(一个通过结伴编程的代码变更是可以被认为通过审查的,若两个工程师都happy了,则代码可以提交的)这世上有很多开源的代码审工具,比如Gerrit。



Nice, clean code is great for hackability, since you don’t need to spend time to unwind that nasty pointer hack in your head before making your changes. How do you make all this happen in practice? Put together workshops on, say, the SOLID principles, unit testing, or concurrency to encourage developers to learn. Spread knowledge through code review, pair programming and mentoring (such as with the Readability concept). You can’t just mandate higher code quality; it takes a lot of work, effort and consistency.

漂亮、干净的代码有利于可拓展性,因为在你要更改代码前,不需要花费太多的时间来解耦那些在你脑中的可恶的指针。在实践中你要怎么实现这些呢?把大家召集起来,开个学习班,培训SOLID法则、单元测试,同时鼓励开发人员去学习。还要开展关于代码审查、结伴编程的学习,并进行答疑(比如可读性这样的概念)你不能直接下命令立马给出高质量的代码,这需要大量的工作、努力和统一性。

 

Presubmit Testing and Lint

预提交的测试和Lint(Lint是通用术语,可用于描述在任何一种计算机程序语言中,用来标记源代码中有疑义段落的工具。在这里Lint是Android提供的代码扫描工具)

Consistently formatted source code aids hackability. You can scan code faster if its formatting is consistent. Automated tooling also aids hackability. It really doesn’t make sense to waste any time on formatting source code by hand. You should be using tools like gofmtclang-format, etc. If the patch isn’t formatted properly, you should see something like this (example from Chrome):

格式一致的代码有助于可拓展性。当格式一致时,你可以快速地浏览代码。自动化的工具也有助于可拓展性。手工费时费力地进行代码格式化是毫无意义的二逼行为。你应该使用工具,比如gofmt、clang-format等。如果补丁没有被正确地格式化,你应该来瞧瞧这货(来自Chrome的例子):

 

$ git cl upload
Error: the media/audio directory requires formatting. Please run 
    git cl format media/audio.


Source formatting isn’t the only thing to check. In fact, you should check pretty much anything you have as a rule in your project. Should other modules not depend on the internals of your modules? Enforce it with a check. Are there already inappropriate dependencies in your project? Whitelist the existing ones for now, but at least block new bad dependencies from forming. Should our app work on Android 16 phones and newer? Add linting, so we don’t use level 17+ APIs without gating at runtime. Should your project’s VHDL code always place-and-route cleanly on a particular brand of FPGA? Invoke the layout tool in your presubmit and and stop submit if the layout process fails.

代码格式化并不是唯一需要核对的东西。实际上,通常在你的项目中你应该要核对很多各种各样的事物。其他模块是否不应该依赖于你的内部模块?强制去核对它。你的项目是否已经包含了不相关不适当的依赖?把到目前为止已有的依赖列出来,且至少要同时排除那些新的不好的依赖。我们的App是否应该运行在Android 16版本或以上的手机?加入到Lint中,这样我们就不会在运行时不经意用到17+的API了。你项目中的VHDL(硬件描述语言)是否应该总能干净利落地适配某个特殊品牌的FPGA(现场可编程门阵列)?请在你的预提交阶段使用布局工具进行检查,而当检查不通过时停止提交代码。



Presubmit is the most valuable real estate for aiding hackability. You have limited space in your presubmit, but you can get tremendous value out of it if you put the right things there. You should stop all obvious errors here.

预提交是最有利于可拓展性的财富。虽然预提交阶段只给你留下一点点的空间,但当你放入正确的东西,使用得当,它将给你带来极大的好处你应该从现在开始停止所有那些显而易见的错误。



It aids hackability to have all this tooling so you don’t have to waste time going back and breaking things for other developers. Remember you need to maintain the presubmit well; it’s not hackability to have a slow, overbearing or buggy presubmit. Having a good presubmit can make it tremendously more pleasant to work on a project. We’re going to talk more in later articles on how to build infrastructure for submit queues and presubmit.

使用工具作业对实现可拓展性是有帮助的,这样你就不需要把时间浪费在为其他开发人员分解事情上。别忘了预提交也是不能半途而废的,不能放弃;然而缓慢、压倒一切或者饱含bug的预提交,不是可拓展性的。拥有良好的预提交,可以让人非常愉快地为该项目工作。我们将在下一篇文章讨论更多关于如何为提交队列和预提交建造基础架构。

 

Single Branch And Reducing Risk

单一的分支和降低风险

Having a single branch for everything, and putting risky new changes behind feature flags, aids hackability since branches and forks often amass tremendous risk when it’s time to merge them. Single branches smooth out the risk. Furthermore, running all your tests on many branches is expensive. However, a single branch can have negative effects on hackability if Team A depends on a library from Team B and gets broken by Team B a lot. Having some kind of stabilization on Team B’s software might be a good idea there. This article covers such situations, and how to integrate often with your dependencies to reduce the risk that one of them will break you.

只创建一个分支,且使用feature flags功能发布来控制有风险的新需求,对可拓展性是有帮助的,因为多分支会在开发过程中积累大量的风险:当要合并它们时会有很多冲突,解决不好冲突就悲剧了。单一的分支就没有这样的风险。此外,在很多个分支上都运行单元测试,花销也是很大的。然而,单一的分支也有可能给可拓展性带来负面的作用,例如团队A依赖团队B的类库,而类库被团队B搞了很多破坏(类库经常被团队B修改)。让团队B提供一个稳定版本的软件是解决该问题的好方法。这篇文章(原文是个超链接,可以点进去)涵盖了那些状况,和如何有效整合你的依赖来降低被依赖拖累的风险。

 

Loose Coupling and Testability

松耦合与可测试性

Tightly coupled code is terrible for hackability. To take the most ridiculous example I know: I once heard of a computer game where a developer changed a ballistics algorithm and broke the game’s chat. That’s hilarious, but hardly intuitive for the poor developer that made the change. A hallmark of loosely coupled code is that it’s upfront about its dependencies and behavior and is easy to modify and move around.

紧密耦合的代码对可拓展性来说非常糟糕的。举一个我所知道的最可笑的栗子:我曾经听说某个电脑游戏,当开发人员修改了发射子弹的算法时,却把游戏的聊天功能搞坏了。真是可笑之极,但对那位可怜的开发来说却几乎是不可察觉的。松耦合代码的特点是,代码的依赖和代码的行为都是非常直观的,且代码轻轻松松就能修改和回退。



Loose coupling, coherence and so on is really about design and architecture and is notoriously hard to measure. It really takes experience. One of the best ways to convey such experience is through code review, which we’ve already mentioned. Education on the SOLID principles, rules of thumb such as tell-don’t-ask, discussions about anti-patterns and code smells are all good here. Again, it’s hard to build tooling for this. You could write a presubmit check that forbids methods longer than 20 lines or cyclomatic complexity over 30, but that’s probably shooting yourself in the foot. Developers would consider that overbearing rather than a helpful assist.

松耦合、一致性等,都是有关软件设计和程序架构的,众所周知,这些都难于量化。这真的很需要经验来实现。其中最可以传达出这样经验的,就是我们之前讨论过的代码审查。对SOLID原则、各种经验法则(比如tell-don't-ask法则)的培训,对反面模式、代码异味的讨论等,都是有益处的。再次说明,真的没有自动化工具来实现这些。你可以自己写个预提交检查,来发现那些代码超过20行的应该禁止的方法、循环度大于30的代码等,但这些规则只适用于你自己。开发人员会把这当做个负担,而不是有用的帮助。



SETIs at Google are expected to give input on a product’s testability. A few well-placed test hooks in your product can enable tremendously powerful testing, such as serving mock content for apps (this enables you to meaningfully test app UI without contacting your real servers, for instance). Testability can also have an influence on architecture. For instance, it’s a testability problem if your servers are built like a huge monolith that is slow to build and start, or if it can’t boot on localhost without calling external services. We’ll cover this in the next article.

我们期望SETIs在Google可以给出关于产品测试性的方案(不懂怎么翻译)。在你的产品中,在正确的位置上放一些测试钩子,会极大地增强软件测试性,比如在apps中使用服务内容模拟(测试替代,这将可以让你直接有效地测试app的UI,而不需要访问你真实的网络服务器)。可测试性也可以影响到代码架构。比如,当你的服务器如庞然大物一般,构建和启动都非常缓慢时,将给你的测试带来很大的麻烦;或者若程序不调用外部服务就不能在本地启动,也会很大地影响你的测试。我们将在下一篇文章讨论这些。

 

Aggressively Reduce Technical Debt

坚决贯彻落实减少技术债务

It’s quite easy to add a lot of code and dependencies and call it a day when the software works. New projects can do this without many problems, but as the project becomes older it becomes a “legacy” project, weighed down by dependencies and excess code. Don’t end up there. It’s bad for hackability to have a slew of bug fixes stacked on top of unwise and obsolete decisions, and understanding and untangling the software becomes more difficult.

我们可以轻而易举地向我们的软件添加一堆代码和依赖,然后只要它还能运行,我们就可以收工回家睡大觉了。在新项目中这么干没多大问题,但随着时间的推移,新项目也发展成了老项目,被越来越多的依赖和过量的代码喂出了臃肿的身材,不堪负重。别放弃。在愚蠢的、该废弃的决策上进行大量的BUG修复,对可拓展性是有害的,而且对理解、解绑软件也带来了困难。



What constitutes technical debt varies by project and is something you need to learn from experience. It simply means the software isn’t in optimal form. Some types of technical debt are easy to classify, such as dead code and barely-used dependencies. Some types are harder to identify, such as when the architecture of the project has grown unfit to the task from changing requirements. We can’t use tooling to help with the latter, but we can with the former.

技术债务的形成因不同的项目而不同,而具体是由什么组成的,这需要你根据日常的学习和日积月累的经验来判断。这可以简单理解为软件并不是处于最佳的形式。有些技术债务很容易区分,比如无用的代码和几乎用不到的依赖。有些却很难识别,比如项目的架构逐渐发展到再也不适用于那些千变万化的需求。自动化工具并不能帮助我们解决后者的问题,但对于前者却可以。



I already mentioned that dependency enforcement can go a long way toward keeping people honest. It helps make sure people are making the appropriate trade-offs instead of just slapping on a new dependency, and it requires them to explain to a fellow engineer when they want to override a dependency rule. This can prevent unhealthy dependencies like circular dependencies, abstract modules depending on concrete modules, or modules depending on the internals of other modules.

我已经提到过,在让人们可靠诚实的道路上,依赖强制可以让我们走得很远。它可以帮助确认我们做的是正确的交易而不仅仅是随便加上一个新的依赖,且它还要求当我们要重写依赖的规则时,我们必须向其他开发小伙伴解释。这样就可以避免不健康的依赖了,如循环依赖、抽象模块依赖实体模块、或依赖其他模块的内部实现等。



There are various tools available for visualizing dependency graphs as well. You can use these to get a grip on your current situation and start cleaning up dependencies. If you have a huge dependency you only use a small part of, maybe you can replace it with something simpler. If an old part of your app has inappropriate dependencies and other problems, maybe it’s time to rewrite that part.

有很多可将依赖关系图形化的工具。你可以使用它们来掌握当前状况的关键点,然后开始清除掉无用的依赖。如果你引入大量的依赖而只用到了其中一小部分,或许你可以用其他更简单的做法来代替。如果你的app中某个老旧的功能出现了不适当的依赖和其他问题,或许是该到了重新实现该功能的时候了。



The next article will be on Pillar 2: Debuggability.

下一篇文章将讲述第二根柱子:可调试性。

  

0
0
分享到:
评论

相关推荐

    Eaglejs一个用Vuejs构建的可hackable幻灯片框架

    Eagle.js - 一个用Vue.js构建的可hackable幻灯片框架

    Hackable7:可破解的来源#7

    《 Hackable》杂志#7的来源和文件该存储库包含第七期存在的Arduino草图的来源: 使用的库是: DS1307RTC:通过Arduino IDE中的库管理器LiquidCrystal:默认安装时间和时间警报:通过Arduino IDE中的库管理器在...

    FeelUOwn, trying to be a hackable music player.zip

    FeelUOwn, trying to be a hackable music player

    XLE, XLE"hackable" 3D 游戏渲染引擎.zip

    XLE, XLE"hackable" 3D 游戏渲染引擎 XLE Prototype 3D 游戏引擎XLE灵活模块化且功能强大。 它旨在与其他解决方案结合,并扩展为具有特殊案例需求的项目。起始点:开发博客:https://xlgames-inc.github.io技术文档...

    Hackable8:可入侵的来源#8

    《 Hackable》杂志#8的来源和文件该存储库包含Arduino草图以及第八期存在的其他文件(配置,PHP脚本等): AVR_C_arduino/ :Arduino IDE中“真实” C上的文章的C代码, chaudiere_Pi_Axelle_Ludovic/ :用于燃油...

    Hackable6:来源可破解 #6

    Hackable 杂志 #6 的来源和文件 该存储库包含第六期出现的 Arduino 草图的来源: 使用的库是:

    Hackable9:资料来源可入侵#9

    《 Hackable》杂志#9的来源和文件 该存储库包含第九期的草图: WSmatrix44ok/ :电视模拟器的完整Arduino草图,其中.h包含使用FFMPEG从视频中提取的图像, script_images/go.sh :用于从包含用FFMPEG提取的图像...

    Simple-Yet-Hackable-WhatsApp-api:没有官方的WhatsApp API。 这是一个满足需求的简单python类

    简单但可破解的WhatsApp-api安装要在您的项目中使用此api,您可以从此存储库下载whatsapp.py和emoji.json ,并将其保存在项目的同一文件夹/子文件夹中。 为您的项目创建一个新的.py文件,并使用from whatsapp import...

    HackableJSON发现工具

    Hackable JSON发现工具

    可破解的JSON发现工具-JavaScript开发

    文章Discovery.js教程:快速入门JsonDiscovery:更改在浏览器中查看JSON的方式示例CSS语法参考(源)CSSWG规范草稿索引(源)相关项目Discovery CLI –用于基于Discovery.js服务和构建项目的CLI工具JsonDiscovery –...

    Atom-1.37.0-windows_x64.exe

    Atom: A hackable text editor for the 21st Century;

    atomsetup 64bit 1.33.0

    A hackable text editor that easy to use,and may be widely used in the future

    7-pillar-auto-cybersecurity-white-paper

    The problem is complex and the point-solutions that exist today are fragmented leaving a very porous and “hackable” system. BlackBerry provides a 7-Pillar recommendation to harden automobile ...

    loader:来自Userland的ESM的高度实验性加载

    hackable-loader 这是一个实验。 没有人应该在生产中运行此程序。 设计约束,按重要性顺序排列: 独立于节点核心的实现。 符合规范。 最大浏览器兼容性。 易于在现有应用程序中使用。 与已经使用ESM编写的...

    Android代码-huginn

    Think of it as a hackable version of IFTTT or Zapier on your own server. You always know who has your data. You do. Here are some of the things that you can do with Huginn: Track the weather and ...

    扁平简单和非侵入的颜色选择器

    Flat, simple and hackable Color-Picker。没有依赖关系,没有jQuery,与所有CSS框架兼容比如Bootstrap、Materialize。

    AtomSetup-x64

    Atom is a text editor that's modern, approachable, yet hackable to the core—a tool you can customize to do anything but also use productively without ever touching a config file.

    Emastic - CSS Framework 0.8(Beta3)源码

    This is a code copy for Emastic, which as so fas as saying, is a hackable CSS framework,which home page is [ https://code.google.com/p/emastic/ ]. This copy comes from the politics reason between ...

    网络安全原理与应用:任意文件上传攻击演示.pptx

    函数来构建具有执行外部命令恶意代码的PHP文件,例:cmd.php2、将恶意代码上传到目标服务器,并显示出上传之后的路径和文件名例:../../hackable/uploads/cmd.php3、通过浏览器URL执行恶意代码的页面,例:05/master...

Global site tag (gtag.js) - Google Analytics