代码是一种思想。 出现任务,开发人员考虑如何解决该问题,如何在功能和类中表达需求,如何使其成为朋友,如何实现严谨和正确性以及如何正确开展业务。 实践,技术,原则,模式和方法-一切都需要考虑,一切都需要记住。
随之而来的是,我们看到了经理,助手,服务,控制器,选择器,适配器,吸气剂,设置器和其他恶魔的普遍流行:所有这些都是无效的代码。 他束手无策。
我建议以这种方式与之抗争:您需要以自然语言将程序呈现为文本,并对其进行相应的评估。 这是怎么回事以及发生了什么-在文章中。
循环目录
- 对象
- 动作和属性
- 文字编码
序言
我的经验不高(大约四年),但是我工作的越多,我的理解就越多:如果该程序不可读,则毫无意义。 早已众所周知并提醒人们注意-该代码不仅现在解决了一些问题,而且以后又解决了:支持,扩展,更正了它。 而且,他总是:读。
毕竟,这是文本。
代码作为文本的美观是周期中的关键主题。 这里的美学是杯,我们透过它看事物,然后说,是的,很好,是的,很漂亮。
在美观和可理解性方面,言语至关重要。 要说: “目前,由于血液中乙醇含量高,我的感知处于沉闷状态”与“我喝醉 了”根本不一样。
我们很幸运,程序几乎完全由文字组成。
假设您需要创建“一个具有健康和法术力的角色,他可以行走,攻击,使用咒语”,并且您可以立即看到:有对象 (字符,健康,法术力,咒语), 动作 (行走,攻击,使用)和属性 (角色具有健康,法力和施法速度)-所有这些都将被命名为:类,函数,方法,变量,属性和字段,总之,是编程语言所分割的所有内容。
但是我不会区分类与结构,字段与属性,方法与函数:作为叙述的一部分的字符不依赖于技术细节(可以将其表示为引用或重要类型)。 本质上不同的东西:这是一个角色,他们称他为Hero
(或Character
),而不是HeroData
或HeroUtils
。
现在,我将带大家欣赏一下美学,并展示当今如何编写一些代码以及为什么它远非完美。
对象
在C#中(不仅是),对象-放置在堆上的类的实例在其中生活了一段时间,然后垃圾收集器将其删除。 也可以在堆栈或关联数组等上创建结构。 对我们来说,它们是:类名,名词。
代码中的名称(如一般名称)可能会造成混淆。 是的,您很少看到一个丑陋的名字,而是一个漂亮的物体。 特别是如果是Manager
。
经理而不是对象
UserService
, AccountManager
, DamageUtils
, MathHelper
, GraphicsManager
, GameManager
, VectorUtil
。
在这里不是主要的准确性和有形性,而是模糊不清的地方,在雾中留下了阴影。 对于这样的名称,可以允许很多。
例如,在任何GameManager
您都可以添加与游戏和游戏逻辑相关的任何内容。 六个月后,将会出现技术上的奇异之处。
或者,碰巧,您需要使用facebook。 为什么不将所有代码放在一个地方: FacebookManager
或FacebookService
? 听起来很诱人,但这种含糊的意图会造成同样含糊的决定 。 同时,我们知道Facebook上有用户,朋友,消息,群组,音乐,兴趣爱好等。 够了!
不仅有足够的单词:我们仍在使用它们。 仅在普通语音中,不在程序之间。
不是GitUtils
,而是IRepository
, ICommit
, IBranch
; 不是ExcelHelper
,而是ExcelDocument
, ExcelSheet
; 不是GoogleDocsService
,而是GoogleDocs
。
每个主题区域都充满了对象。 “这些物体被巨大的空隙标记” , “心脏在疯狂跳动” , “房子在站立” –这些物体的动作,感觉,易于想象; 他们在这里某处,有形而密集。
同时,您有时会看到以下内容:在Microsoft/calculator
存储库SetPrimaryDisplay
,使用以下方法: SetPrimaryDisplay
, MaxDigitsReached
, SetParentDisplayText
, OnHistoryItemAdded
...
(不过,我记得曾经见过 UtilsManager
...)
它是这样发生的:我想用新的行为扩展List<>
类型,并且ListUtils
或ListHelper
诞生了。 在这种情况下,最好仅使用扩展方法ListExtensions
更好,更准确:它们是概念的一部分,而不是过程的转储。
少数例外之一是OfficeManager
作为帖子。
其余的...如果程序包含此类单词,则不应对其进行编译。
行动而不是对象
IProcessor
, ILoader
, ISelector
, IFilter
, IProvider
, ISetter
, ICreator
, IOpener
, IHandler
; IEnableable
, IInitializable
, IUpdatable
, ICloneable
, IDrawable
, ILoadable
, IOpenable
, ISettable
, IConvertible
。
在这里,本质的本质是一个过程,而不是一个概念,并且代码再次失去了图像和可读性,通常的单词被人为的代替。
更活泼的是ISequence
,不是IEnumerable
; IBlueprint
,而不是ICreator
; IButton
而不是IButtonPainter
; IPredicate
,而不是IFilter
; IGate
,不是IOpeneable
; IToggle
,不是IEnableable
。
一个好的故事讲述的是人物及其发展,而不是创作者的创作方式,建造者的建造以及画家的绘画。 一个动作不能完全代表一个对象。 ListSorter
不是SortedList
。
以DirectoryCleaner
为例,该对象用于清理文件系统上的文件夹。 优雅吗? 但是我们永远不会说: “要求文件夹清洁程序来清洁D:/测试” ,总是: “清洁D:/测试” ,因此使用Clean
方法的Directory
看起来更自然,更接近。
一个更生动的案例更有趣:.NET中的FileSystemWatcher
是报告更改的文件系统观察者。 但是,为什么整个观察者(如果变更本身可以报告它们已发生)呢? 此外,它们必须与文件或文件夹密不可分地链接,因此也应将它们放置在Directory
或File
(使用Changes
属性可以调用file.Changes.OnNext(action)
)。
这样的口头名字似乎证明了Strategy
设计模式的合理性,指示“封装算法家族” 。 但是,如果我们找到故事中存在的真实对象而不是“算法家族” ,那么我们将看到该策略只是一个概括。
为了解释这些以及许多其他错误,我们转向哲学。
存在先于本质
MethodInfo
, ItemData
, AttackOutput
, CreationStrategy
, StringBuilder
, SomethingWrapper
, LogBehaviour
。
这样的名字由一件事统一起来:它们的存在是基于细节的。
碰巧某些事物会很快干扰任务:某些事物丢失或存在,但并非某种事物。 然后您会想: “现在可以做X的事情会帮助我” -这就是生存的构想。 然后,为了做X,编写了XImpl
这就是实体的外观。
因此,不是IArrayItem
而是IIndexedItem
或IItemWithIndex
更为常见,或者说,在反射API中,我们只看到有关它的信息 ( MethodInfo
),而不是方法 ( Method
)。
一个更真实的方法:面对生存的需求, 找到一个实现它的实体,并且由于这是它的本质,所以找到其他实体。
例如,他们希望在不创建中间实例的情况下更改string
类型的值-事实证明这是StringBuilder
形式的直接解决方案,而我认为更合适MutableString
。
调用文件系统:不需要DirectoryRenamer
重命名文件夹,因为一旦您同意Directory
对象的存在,该操作已经在其中,您只是在代码中找不到相应的方法。
如果要描述如何进行锁定 ,则无需弄清楚这是ILockBehaviour
还是ILockStrategy
,这要容易得多ILock
(使用返回IDisposable
的Acquire
方法)或ICriticalSection
(使用Enter
)。
这也包括各种Data
, Info
, Output
, Input
, Args
, Params
(很少是State
)-完全没有行为的对象,因为它们被认为是单面的。
在主要存在的地方,商与一般相混合,并且对象的名称令人困惑-您必须通读每一行并找出角色去向何处以及为什么只有他的Data
。
奇异分类法
CalculatorImpl
, AbstractHero
, ConcreteThing
, CharacterBase
。
出于上述相同的原因,有时我们会看到对象,这些对象在层次结构中被精确地指出。 再次,生存急于前进,我们再次看到瞬时需求是如何仓促地涌入代码中,而不考虑后果。
毕竟,真的有一个人( Human
)-基本人的继承人( HumanBase
)吗? 但是,当Item
继承AbstractItem
时如何?
有时,他们想要显示出不是Character
,而是某种“原始”相似性-CharacterRaw。
Impl
, Abstract
, Custom
, Base
, Concrete
, Internal
, Raw
不稳定,建筑模糊的标志,就像第一个场景中的枪一样,它肯定会在以后拍摄。
重复次数
对于嵌套类型,会发生这种情况: RepositoryItem
中的Repository
, Window
WindowState
, Hero
HeroBuilder
。
重复贯穿意义,加剧缺陷,只会增加文本的复杂性。
冗余部分
为了同步线程, ManualResetEvent
通常与以下API结合使用:
public class ManualResetEvent {
每次,个人而言,我都必须记住Set
与Reset
(语法不舒服)有何不同,以及在使用流时上下文中的“手动重置事件”通常是什么。
在这种情况下,比起编程(而不是日常生活)更容易使用隐喻:
public class ThreadGate { void Open(); void Close(); bool WaitForOpen(); }
当然没有什么可混淆的!
有时会变得荒谬:指定项目不仅是Items
,还必须是ItemsList
或ItemsDictionary
!
但是,如果ItemsList
不好笑,那么Spring的 AbstractInterceptorDrivenBeanDefinitionDecorator
ItemsList
。 这个名字中的单词是缝制巨大怪物的破布。 虽然...如果这是一个怪物,那么HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor
是HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor
? 希望遗产 。
除了类和接口名称外,还经常在变量或字段中遇到冗余。
例如,类型为IOrdersRepository
的字段称为_ordersRepository
。 但是,报告存储库已提交订单有多重要? 毕竟,容易得多_orders
。
碰巧在LINQ查询中,他们编写了lambda表达式的完整参数名称,例如Player.Items.Where(item => item.IsWeapon)
,尽管我们已经通过查看Player.Items
理解了此项。 。 在这种情况下,我总是喜欢使用相同的字符x
: Player.Items.Where(x => x.IsWeapon)
(如果这些是函数内部的函数,则继续到y
, z
)。
合计
我承认,从这样的开始,要找到客观事实并不容易。 例如,有人会说:写Service
或不写Service
是有争议的,微不足道的,有品位的,如果有效,它有什么区别?
但是你可以用一次性杯子喝!
我坚信内容的路径是通过表单,如果不看这个思想,它似乎就消失了。 在该程序的文本中,所有操作均以相同的方式进行:样式,气氛和节奏有助于表达自己,而不会感到困惑,而是可以理解且功能丰富。
物体的名称不仅是它的面孔,而且是自我。 它确定是空灵的还是饱和的,抽象的还是真实的,干燥的还是动画的。 名称在变化-内容在变化。
在下一篇文章中,我们将讨论这一内容及其发生的情况。