دسترسی نامحدود
برای کاربرانی که ثبت نام کرده اند
برای ارتباط با ما می توانید از طریق شماره موبایل زیر از طریق تماس و پیامک با ما در ارتباط باشید
در صورت عدم پاسخ گویی از طریق پیامک با پشتیبان در ارتباط باشید
برای کاربرانی که ثبت نام کرده اند
درصورت عدم همخوانی توضیحات با کتاب
از ساعت 7 صبح تا 10 شب
ویرایش:
نویسندگان: Tom Long
سری: Manning Early Access Program
ناشر: Manning Publications
سال نشر: 2021
تعداد صفحات: [338]
زبان: English
فرمت فایل : PDF (درصورت درخواست کاربر به PDF، EPUB یا AZW3 تبدیل می شود)
حجم فایل: 17 Mb
در صورت تبدیل فایل کتاب Good Code, Bad Code: Think Like a Software Engineer, Version 3 به فرمت های PDF، EPUB، AZW3، MOBI و یا DJVU می توانید به پشتیبان اطلاع دهید تا فایل مورد نظر را تبدیل نمایند.
توجه داشته باشید کتاب کد خوب، کد بد: مانند یک مهندس نرم افزار فکر کنید، نسخه 3 نسخه زبان اصلی می باشد و کتاب ترجمه شده به فارسی نمی باشد. وبسایت اینترنشنال لایبرری ارائه دهنده کتاب های زبان اصلی می باشد و هیچ گونه کتاب ترجمه شده یا نوشته شده به فارسی را ارائه نمی دهد.
Good Code, Bad Code MEAP V03 Copyright Welcome Brief Contents Chapter 1: Code quality 1.1 How code becomes software 1.2 The goals of code quality 1.2.1 Code should work 1.2.2 Code should keep working 1.2.3 Code should be adaptable to changing requirements 1.2.4 Code should not reinvent the wheel 1.3 The pillars of code quality 1.3.1 Make code readable 1.3.2 Avoid surprises 1.3.3 Make code hard to misuse 1.3.4 Make code modular 1.3.5 Make code reusable and generalizable 1.3.6 Make code testable and test it properly 1.4 Does writing high-quality code slow us down? 1.5 Summary Chapter 2: Layers of abstraction 2.1 Nulls and the pseudocode convention in this book 2.2 Why use layers of abstraction? 2.2.1 Layers of abstraction and the pillars of code quality 2.3 Layers of code 2.3.1 APIs and implementation details 2.3.2 Functions 2.3.3 Classes 2.3.4 Interfaces 2.3.5 When layers get too thin 2.4 What about microservices? 2.5 Summary Chapter 3: Thinking about other engineers 3.1 Your code and other engineers’ code 3.1.1 Things that are obvious to you are not obvious to others 3.1.2 Other engineers will inadvertently try to break your code 3.1.3 In time, you will forget about your own code 3.2 How will others figure out how to use your code? 3.2.1 Looking at the names of things 3.2.2 Looking at the data types of things 3.2.3 Reading documentation 3.2.4 Asking you in person 3.2.5 Looking at your code 3.3 Code contracts 3.3.1 Small print in contracts 3.3.2 Don’t rely too much on small print 3.4 Checks and assertions 3.4.1 Checks 3.4.2 Assertions 3.5 Summary Chapter 4: Errors 4.1 Recoverability 4.1.1 Errors that can be recovered from 4.1.2 Errors that cannot be recovered from 4.1.3 Often only the caller knows if an error can be recovered from 4.1.4 Make callers aware of errors they might want to recover from 4.2 Robustness vs failure 4.2.1 Fail fast 4.2.2 Fail loudly 4.2.3 Scope of recoverability 4.2.4 Don’t hide errors 4.3 Ways of signalling errors 4.3.1 Recap: Exceptions 4.3.2 Explicit: checked exceptions 4.3.3 Implicit: unchecked exceptions 4.3.4 Explicit: nullable return type 4.3.5 Explicit: result return type 4.3.6 Explicit: outcome return type 4.3.7 Implicit: promise or future 4.3.8 Implicit: returning a magic value 4.4 Signalling errors that can’t be recovered from 4.5 Signalling errors that a caller might want to recovered from 4.5.1 Arguments for using unchecked exceptions 4.5.2 Arguments for using explicit techniques 4.5.3 My personal opinion: use an explicit technique 4.6 Don’t ignore compiler warnings 4.7 Summary Chapter 5: Make code readable 5.1 Use descriptive names 5.1.1 Non-descriptive names make code hard to read 5.1.2 Comments are a poor substitute for descriptive names 5.1.3 Solution: make names descriptive 5.2 Use comments appropriately 5.2.1 Redundant comments can be harmful 5.2.2 Comments are a poor substitute for readable code 5.2.3 Comments can be great for explaining why code exists 5.2.4 Comments can provide useful high-level summaries 5.3 Don’t fixate on number of lines of code 5.3.1 Avoid succinct but unreadable code 5.3.2 Solution: make code readable, even if it requires more lines 5.4 Stick to a consistent coding style 5.4.1 An inconsistent coding style can cause confusion 5.4.2 Solution: adopt and follow a style guide 5.5 Avoid deeply nesting code 5.5.1 Deeply nested code can be hard to read 5.5.2 Solution: restructure to minimize nesting 5.5.3 Nesting is often a result of doing too much 5.5.4 Solution: break code into smaller functions 5.6 Make function calls readable 5.6.1 Arguments can be hard to decipher 5.6.2 Solution: use named arguments 5.6.3 Solution: use descriptive types 5.6.4 Sometimes there’s no great solution 5.6.5 What about the IDE? 5.7 Avoid using unexplained values 5.7.1 Unexplained values can be confusing 5.7.2 Solution: use a well-named constant 5.7.3 Solution: use a well-named function 5.8 Use anonymous functions appropriately 5.8.1 Anonymous functions can be great for small things 5.8.2 Anonymous functions can be hard to read 5.8.3 Solution: use named-functions instead 5.8.4 Large anonymous functions can be problematic 5.8.5 Solution: break large anonymous functions into named-functions 5.9 Use shiny, new language features appropriately 5.9.1 New features can improve code 5.9.2 Obscure features can be confusing 5.9.3 Use the best tool for the job 5.10 Summary Chapter 6: Avoid surprises 6.1 Avoid returning magic values 6.1.1 Magic values can lead to bugs 6.1.2 Solution: return null or an optional 6.1.3 Sometimes magic values can happen accidentally 6.2 Use the null-object pattern appropriately 6.2.1 Returning an empty collection can improve code 6.2.2 Returning an empty string can sometimes be problematic 6.2.3 More complicated null-objects can cause surprises 6.2.4 A null-object implementation can cause surprises 6.3 Avoid causing unexpected side-effects 6.3.1 Side-effects that are obvious and intentional are fine 6.3.2 Unexpected side-effects can be problematic 6.3.3 Solution: avoid a side-effect or make it obvious 6.4 Beware of mutating input parameters 6.4.1 Mutating an input parameter can lead to bugs 6.4.2 Solution: copy things before mutating them 6.5 Avoid writing misleading functions 6.5.1 Doing nothing when a critical input is missing can cause surprises 6.5.2 Solution: make critical inputs required 6.6 Future-proof enum handling 6.6.1 Implicitly handling future enum values can be problematic 6.6.2 Solution: use an exhaustive switch-statement 6.6.3 Beware of the default case 6.6.4 Caveat: Relying on another project’s enum 6.7 Can’t we just solve all this with testing? 6.8 Summary Chapter 7: Make code hard to misuse 7.1 Consider making things immutable 7.1.1 Mutable classes can be easy to misuse 7.1.2 Solution: set values only at construction time 7.1.3 Solution: Use a design pattern for immutability 7.2 Consider making things deeply immutable 7.2.1 Deep mutability can lead to misuse 7.2.2 Solution: defensively copy things 7.2.3 Solution: use immutable data structures 7.3 Avoid overly general data types 7.3.1 Overly general types can be misused 7.3.2 Pair types are easy to misuse 7.3.3 Solution: use a dedicated type 7.4 Dealing with time 7.4.1 Representing time with integers can be problematic 7.4.2 Solution: use appropriate data structures for time 7.5 Have single sources of truth for data 7.5.1 Second sources of truth can lead to invalid states 7.5.2 Solution: use primary data as the single source of truth 7.6 Have single sources of truth for logic 7.6.1 Multiple sources of truth for logic can lead to bugs 7.6.2 Solution: have a single source of truth 7.7 Summary Chapter 8: Make code modular 8.1 Consider using dependency injection 8.1.1 Hard-coded dependencies can be problematic 8.1.2 Solution: use dependency injection 8.1.3 Design code with dependency injection in mind 8.2 Prefer depending on interfaces 8.2.1 Depending on concrete implementations limits adaptability 8.2.2 Solution: depend on interfaces where possible 8.3 Beware of class inheritance 8.3.1 Class inheritance can be problematic 8.3.2 Solution: use composition 8.3.3 What about genuine is-a relationships? 8.4 Classes should care about themselves 8.4.1 Caring too much about other classes can be problematic 8.4.2 Solution: make classes care about themselves 8.5 Encapsulate related data together 8.5.1 Unencapsulated data can be difficult to handle 8.5.2 Solution: group related data into objects or classes 8.6 Beware of leaking implementation details in return types 8.6.1 Leaking implementation details in a return type can be problematic 8.6.2 Solution: return a type appropriate to the layer of abstraction 8.7 Beware of leaking implementation details in exceptions 8.7.1 Leaking implementation details in exceptions can be problematic 8.7.2 Solution: make exceptions appropriate to the layer of abstraction 8.8 Summary Chapter 9: Make code reusable and generalizable 9.1 Beware of assumptions 9.1.1 Assumptions can lead to bugs when code is reused 9.1.2 Solution: avoid unnecessary assumptions 9.1.3 Solution: if an assumption is necessary, enforce it 9.2 Beware of global state 9.2.1 Global state can make reuse unsafe 9.2.2 Solution: dependency inject shared state 9.3 Use default return values appropriately 9.3.1 Default return values in low-level code can harm reusability 9.3.2 Solution: provide defaults in higher-level code 9.4 Keep function parameters focused 9.4.1 A function that takes more than it needs can be hard to reuse 9.4.2 Solution: make functions take only what they need 9.5 Consider using generics 9.5.1 Depending on a specific type limits generalizability 9.5.2 Solution: use generics 9.6 Summary Chapter 10: Unit testing principles 10.1 Unit testing primer 10.2 What makes a good unit test? 10.2.1 Accurately detects breakages 10.2.2 Agnostic to implementation details 10.2.3 Well-explained failures 10.2.4 Understandable test code 10.2.5 Easy and quick to run 10.3 Focus on the public API, but don’t ignore important behaviors 10.3.1 Important behaviors might be outside the public API 10.4 Test doubles 10.4.1 Reasons for using a test double 10.4.2 Mocks 10.4.3 Stubs 10.4.4 Mocks and stubs can be problematic 10.4.5 Fakes 10.4.6 Schools of thought on mocking 10.5 Pick and choose from testing philosophies 10.6 Summary Chapter 11: Unit testing practices 11.1 Test behaviors not just functions 11.1.1 One test case per function is often inadequate 11.1.2 Solution: concentrate on testing each behavior 11.2 Avoid making things visible just for testing 11.2.1 Testing private functions is often a bad idea 11.2.2 Solution: prefer testing via the public API 11.2.3 Solution: split the code into smaller units 11.3 Test one behavior at a time 11.3.1 Testing multiple behaviors at once can lead to poor tests 11.3.2 Solution: test each behavior in its own test case 11.3.3 Parameterized tests 11.4 Use shared test setup appropriately 11.4.1 Shared state can be problematic 11.4.2 Solution: avoid sharing state or reset it 11.4.3 Shared configuration can be problematic 11.4.4 Solution: define important configuration within test cases 11.4.5 When shared configuration is appropriate 11.5 Use appropriate assertion matchers 11.5.1 Inappropriate matchers can lead to poorly explained failures 11.5.2 Solution: use an appropriate matcher 11.6 Use dependency injection to aid testability 11.6.1 Hard-coded dependencies can make code impossible to test 11.6.2 Solution: use dependency injection 11.7 Some final words on testing 11.8 Summary Appendix A: Chocolate brownie recipe Appendix B: Null safety and optionals B.1 Using null-safety B.1.1 Checking for nulls B.2 Using optional Appendix C: Extra code examples C.1 The builder pattern