Skip to main content
Hack, despite being designed to improve upon PHP with static typing and other modern features, still has several anti-patterns that can lead to code quality issues, performance problems, and maintenance challenges. Here are the most important anti-patterns to avoid when writing Hack code.
One of Hack’s main advantages over PHP is its static typing system. Avoid using mixed types excessively or falling back to dynamic type checking with functions like is_array(). Instead, leverage Hack’s type system to catch errors at compile time rather than runtime.
Prefer Hack’s collection classes (Vector, Map, Set, etc.) over PHP arrays. Collections provide type safety, better performance in many cases, and useful higher-order functions for transformations.
While nullable types (?T) are useful, excessive use can lead to null-checking chains and defensive programming. Consider using default values, the Option type pattern, or restructuring your code to minimize nullable types.
Use Hack’s shape types to define the structure of your data instead of using untyped arrays. Shapes provide compile-time checking of field names and types, making your code more robust.
Take advantage of Hack’s async/await features for I/O-bound operations. This allows your code to handle multiple operations concurrently without blocking, improving performance and scalability.
Use XHP (XML in Hack) for generating HTML instead of string concatenation. XHP provides compile-time checking of HTML structure, automatic escaping of values, and a more readable syntax.
Use type aliases and newtype to create more specific types for your domain concepts. This improves type safety, documentation, and prevents accidental misuse of values.
Use enums to represent a fixed set of related values instead of string or integer constants. Enums provide type safety, better documentation, and prevent invalid values.
Use generics to create reusable components that work with different types while maintaining type safety. This reduces the need for type casting and makes your code more robust.
Prefer immutable data structures (ImmVector, ImmMap, ImmSet) over mutable ones when appropriate. Immutable data structures prevent unexpected modifications and make your code easier to reason about, especially in concurrent contexts.
Use traits to share behavior across classes without using inheritance. Traits provide a way to reuse code in a more flexible way than class inheritance.
Implement proper error handling in your code. Use exceptions for exceptional conditions and handle them appropriately. Avoid silently ignoring errors or returning null/false without proper documentation.
Organize your code into namespaces based on functionality or domain concepts. This prevents naming conflicts and makes your codebase more maintainable as it grows.
Use dependency injection to provide a class with its dependencies rather than having the class create them. This makes your code more testable, flexible, and loosely coupled.
Define interfaces for your components and depend on those interfaces rather than concrete implementations. This allows for easier testing and more flexible architecture.
Take advantage of Hack’s type refinement feature, which narrows the type of a variable within conditional blocks based on type checks. This reduces the need for type assertions and makes your code safer.
Use attributes (annotations) to add metadata to your classes and methods. Attributes can be used for routing, validation, authorization, and other cross-cutting concerns.
Write tests for your Hack code. Even with Hack’s strong type system, tests are still important for verifying business logic, edge cases, and integration between components.